Merge remote-tracking branch 'origin/main' into claude/concord-quartz-amethyst-plan-0oy779

# Conflicts:
#	amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
#	amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/AuthCoordinator.kt
This commit is contained in:
Claude
2026-07-13 01:44:54 +00:00
55 changed files with 3022 additions and 333 deletions
+20
View File
@@ -282,6 +282,26 @@ Do this before considering the task complete.
- The only acceptable inline fully-qualified names are: a genuine name
collision (prefer `import ... as Alias` instead), or where the language
requires it. Comments, KDoc, and string literals are exempt.
- **Prefer the `androidx.core` KTX extension over the raw platform Java call**
when one exists — this is what Android Lint's `UseKtx` flags. Common swaps:
`Bitmap.createBitmap(w, h, cfg)``createBitmap(w, h)`,
`Bitmap.createScaledBitmap(src, w, h, f)``src.scale(w, h, f)`,
`Uri.parse(s)``s.toUri()`, and `prefs.edit()…apply()``prefs.edit { }`.
Only adopt the KTX form when it's behaviour-preserving: keep any explicit
argument that differs from the extension's default (a non-`ARGB_8888`
`Bitmap.Config`, `scale(filter = false)`), and leave calls the KTX has no
equivalent for (e.g. the `createBitmap` pixels/matrix overloads, or a
conditional-`apply()` editor loop) untouched.
- **This "prefer the KTX sugar" rule does NOT extend to collection operators.**
The KTX preference is about platform wrappers (`Bitmap`/`Uri`/`SharedPreferences`),
which compile to the identical call. Collections are the opposite: in hot
event/parse paths Quartz deliberately uses raw JVM arrays (`TagArray =
Array<Array<String>>`) and the inline `fast*` operators (`fastForEach`,
`fastAny`, `fastFirstOrNull`, `fastFirstNotNullOfOrNull`, … in
`nip01Core/core/TagArray.kt`) instead of Kotlin `List` + stdlib
`forEach`/`map`/`filter`/`any` — the `fast*` variants allocate no iterator,
no intermediate list, and no lambda object. Don't "modernize" those into
stdlib collection calls; match the surrounding hot-path style.
### Navigation Shell
- **Desktop**: Sidebar + main content area
-19
View File
@@ -278,25 +278,6 @@ call does not guarantee lint finishes first):
The reports persist under each module's `build/reports/`, so re-run lint only
when you want fresh lint data in the next scan.
### 5. Optional: include test coverage
Coverage comes from [Kover](https://github.com/Kotlin/kotlinx-kover). The root
`koverXmlReportCoverage` task runs the unit-test suites of the covered modules
(`quartz`, `commons`, `quic`, `nestsClient`, `geode`, `cli`, `relayBench`,
`desktopApp`, and `amethyst`'s `fdroidDebug` variant) and merges the result
into `build/reports/kover/reportCoverage.xml`, which the scanner imports
automatically when it exists. Same recipe as lint — generate first, scan
second:
```bash
./gradlew koverXmlReportCoverage
./gradlew sonar
```
For a human-readable version of the same data, run
`./gradlew koverHtmlReportCoverage` and open
`build/reports/kover/htmlCoverage/index.html`.
Every `sonar.*` entry in `local.properties` is forwarded to the scanner, so any
[analysis parameter](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/analysis-parameters/)
can be set there. `sonar.projectKey` / `sonar.projectName` default to the root
-1
View File
@@ -6,7 +6,6 @@ plugins {
alias(libs.plugins.jetbrainsComposeCompiler)
alias(libs.plugins.serialization)
alias(libs.plugins.googleKsp)
alias(libs.plugins.kotlinxKover)
}
fun getCurrentBranch(workingDir: java.io.File): String =
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst
import android.graphics.Bitmap
import android.graphics.Color
import androidx.core.graphics.createBitmap
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.vitorpamplona.amethyst.model.AccountSettings
@@ -81,7 +82,7 @@ class ImageUploadTesting {
.build()
private fun getBitmap(): ByteArray {
val bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.ARGB_8888)
val bitmap = createBitmap(200, 300)
for (x in 0 until bitmap.width) {
for (y in 0 until bitmap.height) {
bitmap.setPixel(x, y, Color.rgb(Random.nextInt(), Random.nextInt(), Random.nextInt()))
@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.service.images
import android.graphics.Bitmap
import androidx.core.graphics.createBitmap
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.After
@@ -44,7 +45,7 @@ class ThumbnailDiskCacheInstrumentedTest {
cacheDir = File(appContext.cacheDir, "thumbnail-test-${UUID.randomUUID()}")
cache = ThumbnailDiskCache(cacheDir)
sourceFile = File(appContext.cacheDir, "source-${UUID.randomUUID()}.jpg")
val bitmap = Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888)
val bitmap = createBitmap(64, 64)
sourceFile.outputStream().use { bitmap.compress(Bitmap.CompressFormat.JPEG, 90, it) }
bitmap.recycle()
}
@@ -79,7 +79,6 @@ import com.vitorpamplona.amethyst.service.relayClient.CacheClientConnector
import com.vitorpamplona.amethyst.service.relayClient.RelayProxyClientConnector
import com.vitorpamplona.amethyst.service.relayClient.TorCircuitHealthTracker
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.AuthCoordinator
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.DataStoreRelayAuthPermissionStore
import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model.NotifyCoordinator
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.RelaySubscriptionsCoordinator
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.EventFinderQueryState
@@ -571,13 +570,13 @@ class AppModules(
// Verifies and inserts in the cache from all relays, all subscriptions
val cacheClientConnector = CacheClientConnector(client, cache)
// Show messages from the Relay and controls their dismissal
val notifyCoordinator = NotifyCoordinator(client)
// Show messages from the Relay and controls their dismissal. Attributes each NOTIFY to the
// account whose AUTH the relay rejected (accountsCache is declared below; the lambda reads it
// lazily at NOTIFY time, long after init).
val notifyCoordinator = NotifyCoordinator(client) { pubkey -> accountsCache.accounts.value[pubkey] }
// Persists per-relay NIP-42 ALLOW/DENY overrides across app restarts.
val relayAuthPermissionStore by lazy {
DataStoreRelayAuthPermissionStore(appContext)
}
// Per-relay NIP-42 ALLOW/DENY overrides are now per-account (Account.relayAuthPermissions,
// backed by a file under accounts/<pubkey>/), so there is no app-wide store here anymore.
// Singleton stores for napplet permissions — DataStore v1 enforces one instance per file.
val nappletPermissionStore by lazy { DataStoreNappletPermissionStore(appContext) }
@@ -56,6 +56,8 @@ import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSendResult
import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSendStage
import com.vitorpamplona.amethyst.commons.onchain.OnchainZapSender
import com.vitorpamplona.amethyst.commons.onchain.OnchainZapShare
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthCustomToggles
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore
import com.vitorpamplona.amethyst.commons.richtext.RichTextParser
import com.vitorpamplona.amethyst.commons.service.pow.PersistedPoWJob
import com.vitorpamplona.amethyst.commons.service.pow.PoWCategory
@@ -133,6 +135,10 @@ import com.vitorpamplona.amethyst.model.topNavFeeds.IFeedTopNavFilter
import com.vitorpamplona.amethyst.model.topNavFeeds.OutboxLoaderState
import com.vitorpamplona.amethyst.model.trustedAssertions.TrustProviderListState
import com.vitorpamplona.amethyst.service.location.LocationState
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.InMemoryRelayAuthPermissionStore
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.RelayAuthPermissionCache
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.RelayAuthPermissionLedger
import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model.NotifyRequestsCache
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCPaymentFilterAssembler
import com.vitorpamplona.amethyst.service.uploads.FileHeader
import com.vitorpamplona.amethyst.ui.screen.loggedIn.EventProcessor
@@ -188,6 +194,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.fetchFirst
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrlOrNull
import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
@@ -362,6 +369,7 @@ class Account(
val marmotMessageStore: com.vitorpamplona.quartz.marmot.mls.group.MarmotMessageStore? = null,
val marmotKeyPackageStore: com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageBundleStore? = null,
val powQueue: () -> PoWPublishQueue? = { null },
relayAuthPermissionStore: RelayAuthPermissionStore = InMemoryRelayAuthPermissionStore(),
) : IAccount {
private var userProfileCache: User? = null
@@ -376,6 +384,41 @@ class Account(
val userMetadata = UserMetadataState(signer, cache, scope, settings)
// Per-account NIP-42 ALLOW/DENY overrides, warm-cached in memory so a relay AUTH challenge is
// answered without a disk read. Backed by a per-account file (see AccountCacheState).
val relayAuthPermissions = RelayAuthPermissionCache(relayAuthPermissionStore, scope)
// Per-account NIP-42 policy evaluator (blocked → per-relay override → global policy → prompt),
// reading THIS account's own toggles, relay lists and follow graph. Cached here so every AUTH
// path (foreground screen + background notification consumer) shares one instance, and so an
// AUTH challenge is decided per account instead of folding every logged-in account together.
val relayAuthLedger =
RelayAuthPermissionLedger(
store = relayAuthPermissions,
globalPolicy = { settings.defaultRelayAuthPolicy.value },
customToggles = {
RelayAuthCustomToggles(
myRelaysAndVenues = settings.relayAuthTrustMyRelaysAndVenues.value,
readFollows = settings.relayAuthTrustReadFollows.value,
messageFollows = settings.relayAuthTrustMessageFollows.value,
messageStrangers = settings.relayAuthTrustMessageStrangers.value,
)
},
isInMyRelayList = { relayUrl -> relayUrl.normalizeRelayUrlOrNull()?.let { it in trustedRelays.flow.value } ?: false },
isBlocked = { relayUrl -> relayUrl.normalizeRelayUrlOrNull()?.let { it in blockedRelayList.flow.value } ?: false },
isFollowed = { pubkey -> pubkey in allFollows.flow.value.authors },
isTrustedVenue = { venueId ->
venueId in publicChatList.flowSet.value ||
venueId in communityList.flowSet.value ||
Address.parse(venueId)?.pubKeyHex?.let { it in allFollows.flow.value.authors } == true
},
)
// Per-account relay NOTIFY (payment-prompt) cache. NotifyCoordinator attributes each incoming
// NOTIFY to the account whose AUTH the relay rejected and drops it here, so a prompt for one
// account never surfaces under another (the old cache was a process-wide singleton).
val relayNotifications = NotifyRequestsCache()
override val nip47SignerState = NwcSignerState(signer, nwcFilterAssembler, cache, scope, settings)
val nip65RelayList = Nip65RelayListState(signer, cache, scope, settings)
@@ -31,6 +31,7 @@ import com.vitorpamplona.amethyst.model.marmot.AndroidMarmotMessageStore
import com.vitorpamplona.amethyst.model.marmot.AndroidMlsGroupStateStore
import com.vitorpamplona.amethyst.model.marmot.InMemoryMlsGroupStateStore
import com.vitorpamplona.amethyst.service.location.LocationState
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.DataStoreRelayAuthPermissionStore
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.nwc.NWCPaymentFilterAssembler
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
@@ -224,6 +225,10 @@ class AccountCacheState(
null
}
// Per-account NIP-42 ALLOW/DENY overrides live in this account's own dir, so a DENY for one
// account never leaks into another (the store used to be a single app-wide file).
val relayAuthPermissionStore = DataStoreRelayAuthPermissionStore(accountDir)
return Account(
settings = accountSettings,
signer = signerWithClientTag,
@@ -247,6 +252,7 @@ class AccountCacheState(
marmotMessageStore = marmotMessageStore,
marmotKeyPackageStore = marmotKeyPackageStore,
powQueue = powQueue,
relayAuthPermissionStore = relayAuthPermissionStore,
).also { newAccount ->
accounts.update { existingAccounts ->
existingAccounts.plus(Pair(signer.pubKey, newAccount))
@@ -32,6 +32,7 @@ import android.os.Messenger
import android.os.RemoteException
import android.os.SystemClock
import android.util.Log
import androidx.core.net.toUri
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.favorites.FavoriteApp
import com.vitorpamplona.amethyst.commons.napplet.NappletBroker
@@ -359,7 +360,7 @@ class NappletBrokerService : Service() {
val intent =
Intent(applicationContext, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
data = Uri.parse("nostr:connectedapp?coordinate=" + Uri.encode(coordinate))
data = ("nostr:connectedapp?coordinate=" + Uri.encode(coordinate)).toUri()
}
runCatching { applicationContext.startActivity(intent) }
.onFailure { Log.w("NappletBrokerService", "Could not open Connected Apps detail", it) }
@@ -21,7 +21,7 @@
package com.vitorpamplona.amethyst.napplet
import android.content.Context
import android.net.Uri
import androidx.core.net.toUri
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
@@ -86,7 +86,7 @@ object WebAppNetworkRegistry {
}
/** The host key for [url] (e.g. `vitorpamplona.com`), or the raw string if it has no host. */
fun hostKeyOf(url: String): String = runCatching { Uri.parse(url).host }.getOrNull()?.takeIf { it.isNotBlank() } ?: url
fun hostKeyOf(url: String): String = runCatching { url.toUri().host }.getOrNull()?.takeIf { it.isNotBlank() } ?: url
/** Whether the site behind [url] routes through Tor. Defaults to true (Tor) for any site never set. */
fun useTor(url: String): Boolean = modes[hostKeyOf(url)] ?: true
@@ -27,6 +27,7 @@ import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.MainActivity
import com.vitorpamplona.amethyst.ui.stringRes
@@ -64,7 +65,7 @@ object CalendarReminderNotifier {
val tapIntent =
Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_VIEW
data = android.net.Uri.parse(deepLink)
data = deepLink.toUri()
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
val tapPendingIntent =
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.service.calendar
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
/**
* Device-wide preferences for the calendar reminder worker.
@@ -40,13 +41,13 @@ class CalendarReminderPrefs(
fun isEnabled(): Boolean = prefs.getBoolean(KEY_ENABLED, DEFAULT_ENABLED)
fun setEnabled(enabled: Boolean) {
prefs.edit().putBoolean(KEY_ENABLED, enabled).apply()
prefs.edit { putBoolean(KEY_ENABLED, enabled) }
}
fun leadMinutes(): Int = prefs.getInt(KEY_LEAD_MINUTES, DEFAULT_LEAD_MINUTES)
fun setLeadMinutes(minutes: Int) {
prefs.edit().putInt(KEY_LEAD_MINUTES, minutes).apply()
prefs.edit { putInt(KEY_LEAD_MINUTES, minutes) }
}
companion object {
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.service.calendar
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
/**
* Persistent "I've already notified for this event" set. Backed by [SharedPreferences] because
@@ -54,7 +55,7 @@ class CalendarReminderStore(
eventId: String,
eventStartSeconds: Long,
) {
prefs.edit().putLong(keyFor(eventId), eventStartSeconds).apply()
prefs.edit { putLong(keyFor(eventId), eventStartSeconds) }
}
/**
@@ -24,16 +24,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthCustomToggles
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.AuthCoordinator
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.RelayAuthPermissionLedger
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.ScreenAuthAccount
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.quartz.nip01Core.core.Address
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.normalizeRelayUrlOrNull
/** The owner pubkey of an addressable venue (`kind:pubkey:dTag`), or null for a bare channel id. */
private fun venueOwnerPubkey(venueId: String): String? = Address.parse(venueId)?.pubKeyHex
@Composable
fun RelayAuthSubscription(accountViewModel: AccountViewModel) = RelayAuthSubscription(accountViewModel, Amethyst.instance.authCoordinator)
@@ -45,51 +38,17 @@ fun RelayAuthSubscription(
) {
val account = accountViewModel.account
// The per-account NIP-42 policy ledger now lives on Account (account.relayAuthLedger), so this
// only has to register the account itself. The coordinator decides + signs per account.
val state =
remember(accountViewModel) {
ScreenAuthAccount(account)
}
val ledger =
remember(accountViewModel) {
RelayAuthPermissionLedger(
store = Amethyst.instance.relayAuthPermissionStore,
globalPolicy = { account.settings.defaultRelayAuthPolicy.value },
customToggles = {
RelayAuthCustomToggles(
myRelaysAndVenues = account.settings.relayAuthTrustMyRelaysAndVenues.value,
readFollows = account.settings.relayAuthTrustReadFollows.value,
messageFollows = account.settings.relayAuthTrustMessageFollows.value,
messageStrangers = account.settings.relayAuthTrustMessageStrangers.value,
)
},
isInMyRelayList = { relayUrl ->
val normalized = relayUrl.normalizeRelayUrlOrNull() ?: return@RelayAuthPermissionLedger false
normalized in account.trustedRelays.flow.value
},
isBlocked = { relayUrl ->
val normalized = relayUrl.normalizeRelayUrlOrNull() ?: return@RelayAuthPermissionLedger false
normalized in account.blockedRelayList.flow.value
},
// Any follow list (kind 3, follow sets, etc.) counts as trusting the counterparty
// enough to reveal our identity to a relay that serves them.
isFollowed = { pubkey -> pubkey in account.allFollows.flow.value.authors },
// A venue (public chat / community / live stream) is trusted if we've joined it, or
// its owner — the pubkey in a `kind:pubkey:dTag` address — is someone we follow.
isTrustedVenue = { venueId ->
venueId in account.publicChatList.flowSet.value ||
venueId in account.communityList.flowSet.value ||
venueOwnerPubkey(venueId)?.let { it in account.allFollows.flow.value.authors } == true
},
)
}
DisposableEffect(state, ledger) {
DisposableEffect(state) {
dataSource.subscribe(state)
dataSource.subscribeLedger(ledger)
onDispose {
dataSource.unsubscribe(state)
dataSource.unsubscribeLedger(ledger)
}
}
}
@@ -22,6 +22,8 @@ package com.vitorpamplona.amethyst.service.relayClient.authCommand.model
import androidx.compose.runtime.Stable
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthContext
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthVerdict
import com.vitorpamplona.amethyst.isDebug
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@@ -43,24 +45,11 @@ class ScreenAuthAccount(
@Stable
class AuthCoordinator(
client: INostrClient,
val client: INostrClient,
scope: CoroutineScope,
val promptBus: RelayAuthPromptBus = RelayAuthPromptBus(),
) {
private val authWithAccounts = ListWithUniqueSetCache<ScreenAuthAccount, Account> { it.account }
private val tempAccount by lazy {
NostrSignerSync()
}
@Volatile private var relayLedgers: List<RelayAuthPermissionLedger> = emptyList()
fun subscribeLedger(ledger: RelayAuthPermissionLedger) {
synchronized(this) { relayLedgers = relayLedgers + ledger }
}
fun unsubscribeLedger(ledger: RelayAuthPermissionLedger) {
synchronized(this) { relayLedgers = relayLedgers - ledger }
}
val receiver =
RelayAuthenticator(
@@ -70,13 +59,12 @@ class AuthCoordinator(
// Concord plane traffic is gated behind NIP-42 as the derived *stream key*, not the
// user: a relay serves a plane's kind-1059 wraps only to a connection authenticated
// as that stream key. These AUTHs expose no user identity (ephemeral derived keys)
// and are signed locally, so we always attach them — independent of the user-auth
// and are signed locally, so we always attach them — independent of the per-account
// policy below — or Concord channels/messages never load. No-op for non-Concord relays.
val streamAuths = signConcordStreamAuths(relayUrl, authTemplate)
// Reconstruct *why* this relay wants auth from what we're doing with it, so each
// account's ledger can apply follow-based trust and (later) explain the prompt.
// Built lazily so the no-ledgers auto-allow path below doesn't pay for it.
// Reconstruct *why* this relay wants auth from what the shared client is doing with
// it. Built lazily so accounts that fail the first-party gate below don't pay for it.
val context by
lazy(LazyThreadSafetyMode.NONE) {
RelayAuthContext(
@@ -88,54 +76,67 @@ class AuthCoordinator(
),
)
}
val currentLedgers = relayLedgers
// Ask the user (only in the ASK case) and fold every account's verdict into one
// decision plus an optional per-relay override to remember. When this relay hosts our
// Concord planes, never block the derived stream-key AUTH behind a user prompt: skip
// the user-auth ASK (DISMISS) so we return the stream AUTHs immediately instead of
// waiting on — or being dropped by — a dialog the user may never answer.
val outcome =
AuthDecisionResolver.resolve(currentLedgers.map { it.decide(context) }) {
if (streamAuths.isNotEmpty()) UserAuthChoice.DISMISS else promptBus.requestDecision(relayUrl, context.purposes)
}
outcome.remember?.let { decision ->
currentLedgers.firstOrNull()?.setDecision(relayUrl.url, decision)
}
val shouldAuth = outcome.shouldAuth
// One socket is shared by every logged-in account, so an AUTH challenge is not tied
// to any single one of them. We answer PER ACCOUNT: an account only reveals its
// identity to a relay it has a first-party reason to be on (its own inbox/outbox
// traffic, or a relay it configured) AND its own ledger verdict allows it. This is
// what stops account B — or a throwaway key — being billed / de-anonymized on a
// relay only account A uses (the inbox.nostr.wine over-AUTH bug): unlike the old
// "any account ALLOWs → sign with everyone (else a random key)" path, a bystander
// account never signs, and there is no random-key fallback.
val signed = mutableListOf<RelayAuthEvent>()
var askChoice: UserAuthChoice? = null
val userAuths =
if (shouldAuth) {
// Remember why we granted this relay so the settings screen can explain it.
currentLedgers.firstOrNull()?.recordGrant(context)
authWithAccounts.distinctValues().forEach forEachAccount@{ screen ->
val account = screen.account
if (!account.signer.isWriteable()) return@forEachAccount
if (!isFirstParty(account, relayUrl)) return@forEachAccount
// distinct() returns Set<Account> (the key type U of ListWithUniqueSetCache)
val results =
authWithAccounts.distinct().mapNotNull {
if (it.signer.isWriteable()) {
try {
it.signer.sign(authTemplate)
} catch (e: Exception) {
Log.e("AuthCoordinator", "Failed trying to authenticate a writeable account", e)
null
val approve =
when (account.relayAuthLedger.decide(context)) {
RelayAuthVerdict.ALLOW -> true
RelayAuthVerdict.DENY -> false
RelayAuthVerdict.ASK -> {
// Prompt at most once per challenge; reuse the answer for any other
// account that also reaches ASK on this same relay. But never block the
// derived stream-key AUTH behind that dialog: on a relay that hosts our
// Concord planes we DISMISS the user-auth ASK (skip account auth) so the
// stream AUTHs return immediately instead of waiting on a prompt.
val choice =
askChoice ?: (
if (streamAuths.isNotEmpty()) {
UserAuthChoice.DISMISS
} else {
promptBus.requestDecision(relayUrl, context.purposes)
}
).also { askChoice = it }
when (choice) {
UserAuthChoice.ALLOW_ONCE -> true
UserAuthChoice.ALWAYS_ALLOW -> {
account.relayAuthLedger.setDecision(relayUrl.url, RelayAuthDecision.ALLOW)
true
}
} else {
null
UserAuthChoice.BLOCK -> {
account.relayAuthLedger.setDecision(relayUrl.url, RelayAuthDecision.DENY)
false
}
UserAuthChoice.DISMISS -> false
}
}
// Always auth, even with random keys (unless we're only here for stream auth).
if (results.isNotEmpty()) {
results
} else if (streamAuths.isEmpty()) {
listOf(tempAccount.sign(authTemplate))
} else {
emptyList()
}
} else {
emptyList()
}
streamAuths + userAuths
if (approve) {
// Remember why we granted this relay so the settings screen can explain it.
account.relayAuthLedger.recordGrant(context)
try {
signed.add(account.signer.sign(authTemplate))
} catch (e: Exception) {
Log.e("AuthCoordinator", "Failed trying to authenticate a writeable account", e)
}
}
}
signed + streamAuths
},
)
@@ -165,6 +166,28 @@ class AuthCoordinator(
// stream secret (hex) -> its local signer. Bounded by joined communities × channels.
private val streamSigners = ConcurrentHashMap<HexKey, NostrSignerSync>()
/**
* True when [account] has a first-party reason to authenticate with [relayUrl] on the shared
* client: it is publishing its own event there, a subscription there is reading its own
* inbox/outbox (`#p` or `authors` names its pubkey), or the relay is in its own relay list.
*
* Merely *following* the counterparty of someone else's traffic is deliberately NOT first-party:
* that is exactly how a bystander account got dragged into a paid inbox relay's AUTH (the shared
* auth context carries the OTHER account's counterparties, evaluated against this account's
* follow graph). Reads of a followed author's outbox on an auth-gated relay this account doesn't
* use are therefore no longer auto-authed a deliberate privacy-positive trade-off.
*/
private fun isFirstParty(
account: Account,
relayUrl: NormalizedRelayUrl,
): Boolean =
RelayAuthFirstParty.hasReason(
me = account.pubKey,
relayUrl = relayUrl,
pendingEvents = client.activeOutboxEvents(relayUrl),
myRelays = account.trustedRelays.flow.value,
)
fun destroy() {
receiver.destroy()
}
@@ -34,6 +34,7 @@ import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.coroutines.flow.first
import java.io.File
import java.security.MessageDigest
import java.util.concurrent.ConcurrentHashMap
/**
* Single-file DataStore-backed [RelayAuthPermissionStore]. All per-relay ALLOW/DENY overrides
@@ -45,11 +46,10 @@ class DataStoreRelayAuthPermissionStore(
) : RelayAuthPermissionStore {
constructor(context: Context) : this(context.applicationContext.filesDir)
private val store: DataStore<Preferences> by lazy {
PreferenceDataStoreFactory.create(
produceFile = { File(filesDir, "datastore/relay_auth.preferences_pb") },
)
}
// DataStore v1 throws if two instances are ever active on the same file. loadAccount can build
// this store more than once for the same account (re-login, cache races), so the underlying
// DataStore is shared per absolute file path across the process instead of created per instance.
private val store: DataStore<Preferences> get() = dataStoreFor(File(filesDir, "datastore/relay_auth.preferences_pb"))
override suspend fun loadDecision(relayUrl: String): RelayAuthDecision? {
val raw = store.data.first()[decisionKey(relayUrl)] ?: return null
@@ -198,6 +198,15 @@ class DataStoreRelayAuthPermissionStore(
private fun lastUsedKey(relayUrl: String) = stringPreferencesKey("$LAST_USED_PREFIX${hash(relayUrl)}")
companion object {
// One DataStore per file path, process-wide. computeIfAbsent runs the factory at most once
// per path, so concurrent constructions for the same account share a single active DataStore.
private val stores = ConcurrentHashMap<String, DataStore<Preferences>>()
private fun dataStoreFor(file: File): DataStore<Preferences> =
stores.computeIfAbsent(file.absolutePath) {
PreferenceDataStoreFactory.create(produceFile = { file })
}
private const val DECISION_PREFIX = "allow:"
private const val URL_PREFIX = "url:"
private const val RATIONALE_PREFIX = "rat:"
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.service.relayClient.authCommand.model
import com.vitorpamplona.amethyst.commons.relayauth.AuthPurposeKind
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore
/**
* Volatile, non-persistent [RelayAuthPermissionStore]. Used as the default for [com.vitorpamplona.amethyst.model.Account]
* instances built without a disk-backed store (Compose previews, unit tests, the mock account view
* models) so nothing on the auth path has to null-check the store.
*/
class InMemoryRelayAuthPermissionStore : RelayAuthPermissionStore {
private val decisions = mutableMapOf<String, RelayAuthDecision>()
private val rationale = mutableMapOf<String, MutableMap<AuthPurposeKind, MutableSet<String>>>()
override suspend fun loadDecision(relayUrl: String): RelayAuthDecision? = decisions[relayUrl]
override suspend fun storeDecision(
relayUrl: String,
decision: RelayAuthDecision,
) {
decisions[relayUrl] = decision
}
override suspend fun clearDecision(relayUrl: String) {
decisions.remove(relayUrl)
}
override suspend fun allDecisions(): Map<String, RelayAuthDecision> = decisions.toMap()
override suspend fun recordUse(
relayUrl: String,
additions: Map<AuthPurposeKind, Set<String>>,
) {
val forRelay = rationale.getOrPut(relayUrl) { mutableMapOf() }
for ((kind, pubkeys) in additions) {
forRelay.getOrPut(kind) { mutableSetOf() }.addAll(pubkeys)
}
}
override suspend fun loadRationale(relayUrl: String): Map<AuthPurposeKind, Set<String>> = rationale[relayUrl]?.mapValues { it.value.toSet() } ?: emptyMap()
override suspend fun allRationales(): Map<String, Map<AuthPurposeKind, Set<String>>> = rationale.mapValues { entry -> entry.value.mapValues { it.value.toSet() } }
override suspend fun clearRationale(relayUrl: String) {
rationale.remove(relayUrl)
}
}
@@ -54,6 +54,12 @@ class ListWithUniqueSetCache<T, U>(
return newSet
}
/** One representative [T] per unique key — the first occurrence wins. */
fun distinctValues(): List<T> {
val seen = HashSet<U>()
return list.get().filter { seen.add(key(it)) }
}
fun forEachSubscriber(action: (T) -> Unit) {
list.get().forEach(action)
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.service.relayClient.authCommand.model
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
/**
* Whether a given account has a *first-party* reason to authenticate (NIP-42) with a relay on the
* shared [com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient]. Pure so the per-account
* signing gate can be tested without a live client, signer, or Compose.
*
* The socket is shared by every logged-in account, so "this relay wants auth" says nothing about
* *which* account should answer. An account should reveal its identity to a relay only when:
* - it is publishing its own event there ([pendingEvents] authored by it e.g. delivering a DM to
* the recipient's inbox relay), or
* - the relay is one it configured itself ([myRelays] its NIP-65 / DM / search / lists, which
* is where its own inbox/outbox reads are routed anyway).
*
* Crucially, an active subscription merely *naming* the account (a `#p` tag or `authors` entry) is
* NOT a first-party reason: the app packs several accounts' pubkeys into one merged filter and fans
* it out to the union of everyone's relays, so account B's pubkey routinely rides a subscription to
* account A's paid relay. Trusting that dragged bystander accounts (e.g. into inbox.nostr.wine's
* AUTH, and its bill). Genuine own-inbox reads still qualify via [myRelays] the relay serving them
* is by definition in the account's own list.
*/
object RelayAuthFirstParty {
fun hasReason(
me: HexKey,
relayUrl: NormalizedRelayUrl,
pendingEvents: List<Event>,
myRelays: Set<NormalizedRelayUrl>,
): Boolean {
if (pendingEvents.any { it.pubKey == me }) return true
return relayUrl in myRelays
}
}
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.service.relayClient.authCommand.model
import com.vitorpamplona.amethyst.commons.relayauth.AuthPurposeKind
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
/**
* In-memory, warm-cached view over one account's [RelayAuthPermissionStore] (a per-account file
* see [DataStoreRelayAuthPermissionStore] built from `accounts/<pubkey>/`). Held on the
* [com.vitorpamplona.amethyst.model.Account] like the other state caches.
*
* The ALLOW/DENY overrides are the only thing read on the hot NIP-42 decision path
* ([RelayAuthPermissionLedger.decide]). They are snapshotted into memory once, right after the
* account loads, and served from there so an incoming AUTH challenge is answered without a disk
* read (a slow disk hit here would stall login-time relay auth). Writes update memory *and* disk.
*
* Rationale + last-used are read only by the settings screen, off the hot path, so they pass
* straight through to disk. Implements [RelayAuthPermissionStore] so it drops into every existing
* call site (the ledger and the settings screen) unchanged.
*/
class RelayAuthPermissionCache(
private val disk: RelayAuthPermissionStore,
scope: CoroutineScope,
) : RelayAuthPermissionStore {
private val loaded = CompletableDeferred<Unit>()
private val _overrides = MutableStateFlow<Map<String, RelayAuthDecision>>(emptyMap())
/** Per-relay overrides for this account, observable so the settings screen refreshes on change. */
val overrides: StateFlow<Map<String, RelayAuthDecision>> = _overrides.asStateFlow()
init {
scope.launch {
_overrides.value = disk.allDecisions()
loaded.complete(Unit)
}
}
/** Non-suspending override lookup — returns null until the initial warm load finishes. */
fun decisionOrNull(relayUrl: String): RelayAuthDecision? = _overrides.value[relayUrl]
override suspend fun loadDecision(relayUrl: String): RelayAuthDecision? {
loaded.await()
return _overrides.value[relayUrl]
}
override suspend fun storeDecision(
relayUrl: String,
decision: RelayAuthDecision,
) {
disk.storeDecision(relayUrl, decision)
_overrides.update { it + (relayUrl to decision) }
}
override suspend fun clearDecision(relayUrl: String) {
disk.clearDecision(relayUrl)
_overrides.update { it - relayUrl }
}
override suspend fun allDecisions(): Map<String, RelayAuthDecision> {
loaded.await()
return _overrides.value
}
// --- rationale + last-used: settings-screen only, never on the auth decision path ---
override suspend fun recordUse(
relayUrl: String,
additions: Map<AuthPurposeKind, Set<String>>,
) = disk.recordUse(relayUrl, additions)
override suspend fun loadRationale(relayUrl: String): Map<AuthPurposeKind, Set<String>> = disk.loadRationale(relayUrl)
override suspend fun allRationales(): Map<String, Map<AuthPurposeKind, Set<String>>> = disk.allRationales()
override suspend fun clearRationale(relayUrl: String) = disk.clearRationale(relayUrl)
override suspend fun allLastUsed(): Map<String, Long> = disk.allLastUsed()
}
@@ -21,22 +21,19 @@
package com.vitorpamplona.amethyst.service.relayClient.notifyCommand.compose
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model.NotifyRequestsCache
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
import kotlinx.coroutines.flow.map
@Composable
fun DisplayNotifyMessages(
accountViewModel: AccountViewModel,
nav: INav,
) = DisplayNotifyMessages(Amethyst.instance.notifyCoordinator.requests, accountViewModel, nav)
) = DisplayNotifyMessages(accountViewModel.account.relayNotifications, accountViewModel, nav)
@Composable
fun DisplayNotifyMessages(
@@ -44,17 +41,10 @@ fun DisplayNotifyMessages(
accountViewModel: AccountViewModel,
nav: INav,
) {
val flow =
remember(accountViewModel) {
requests.transientPaymentRequests.map {
it.filter { notifyMsg ->
notifyMsg.relayUrl in accountViewModel.account.dmRelayList.flow.value ||
notifyMsg.relayUrl in accountViewModel.account.nip65RelayList.allFlowNoDefaults.value
}
}
}
val openDialogMsg = flow.collectAsStateWithLifecycle(emptySet())
// [requests] is THIS account's own cache. NotifyCoordinator only files a NOTIFY under the account
// whose AUTH the relay rejected, so there is no cross-account leak to filter out here — a prompt
// in this cache genuinely belongs to this account.
val openDialogMsg = requests.transientPaymentRequests.collectAsStateWithLifecycle()
openDialogMsg.value.firstOrNull()?.let { request ->
NotifyRequestDialog(
@@ -20,20 +20,98 @@
*/
package com.vitorpamplona.amethyst.service.relayClient.notifyCommand.model
import android.util.LruCache
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.RelayNotifier
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.RelayConnectionListener
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.Message
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.NotifyMessage
import com.vitorpamplona.quartz.nip01Core.relay.commands.toClient.OkMessage
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.AuthCmd
import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.Command
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.utils.Log
import java.util.concurrent.ConcurrentHashMap
/**
* Routes relay `NOTIFY` payment prompts to the account they actually concern.
*
* A relay's NOTIFY does not reliably name a pubkey, so we can't parse the account out of the
* message. Instead we correlate it with the AUTH that triggered it: a paid relay answers an
* unauthorized AUTH with `OK <authEventId> false ` immediately followed by the NOTIFY. We *signed*
* that auth event, so [AuthCmd.event] tells us which account's key it was. We remember that per auth
* event, resolve the failing `OK` back to the signer, and drop the NOTIFY into THAT account's own
* [NotifyRequestsCache] ([Account.relayNotifications]).
*
* The cache is per account (not a process-wide singleton), so a prompt for account A can never
* surface under account B and an unattributable NOTIFY is dropped rather than shown to the wrong
* account. This is the fix for the stale-global-cache leak where switching accounts re-surfaced
* another account's inbox.nostr.wine prompt.
*/
class NotifyCoordinator(
client: INostrClient,
private val client: INostrClient,
private val accountForPubkey: (HexKey) -> Account?,
) {
val requests = NotifyRequestsCache()
companion object {
const val TAG = "NotifyCoordinator"
private const val AUTH_EVENT_CACHE = 256
}
val receiver =
RelayNotifier(client) { message, relay ->
requests.addPaymentRequestIfNew(message, relay.url)
// authEventId -> the pubkey we signed it with. Bounded: only a handful of relays re-auth.
private val signerOfAuthEvent = LruCache<HexKey, HexKey>(AUTH_EVENT_CACHE)
// relay -> pubkey of the auth the relay most recently rejected there (the one it will bill).
private val billedPubkeyAt = ConcurrentHashMap<NormalizedRelayUrl, HexKey>()
private val listener =
object : RelayConnectionListener {
override fun onSent(
relay: IRelayClient,
cmdStr: String,
cmd: Command,
success: Boolean,
) {
if (cmd is AuthCmd) {
signerOfAuthEvent.put(cmd.event.id, cmd.event.pubKey)
}
}
override fun onIncomingMessage(
relay: IRelayClient,
msgStr: String,
msg: Message,
) {
when (msg) {
is OkMessage ->
if (!msg.success) {
signerOfAuthEvent.get(msg.eventId)?.let { billedPubkeyAt[relay.url] = it }
}
is NotifyMessage -> route(relay.url, msg.message)
else -> {}
}
}
}
private fun route(
relay: NormalizedRelayUrl,
message: String,
) {
// Consume the correlation so a later, unrelated NOTIFY can't reuse a stale attribution.
// An unattributable NOTIFY (none of our auths were rejected here) is dropped rather than
// risk surfacing it under the wrong account.
val account = billedPubkeyAt.remove(relay)?.let(accountForPubkey)
account?.relayNotifications?.addPaymentRequestIfNew(message, relay)
}
init {
Log.d(TAG, "Init, Subscribe")
client.addConnectionListener(listener)
}
fun destroy() {
receiver.destroy()
Log.d(TAG, "Destroy, Unsubscribe")
client.removeConnectionListener(listener)
}
}
@@ -25,6 +25,7 @@ import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import androidx.core.graphics.createBitmap
import kotlin.math.roundToInt
/**
@@ -57,7 +58,7 @@ fun roadEventPinBitmap(
val cx = width / 2f
val cy = pad + radius
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val bitmap = createBitmap(width, height)
val canvas = Canvas(bitmap)
// Head circle + pointer drawn as a single path so they share one shadow
@@ -21,12 +21,10 @@
package com.vitorpamplona.amethyst.ui.note.types
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@@ -85,7 +83,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.gitRepo.repoHasFetchableClo
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Font12SP
import com.vitorpamplona.amethyst.ui.theme.HalfDoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.Size16dp
import com.vitorpamplona.amethyst.ui.theme.Size5dp
@@ -93,7 +90,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size8dp
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.amethyst.ui.theme.grayText
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.theme.subtleBorder
import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hasHashtags
import com.vitorpamplona.quartz.nip34Git.issue.GitIssueEvent
import com.vitorpamplona.quartz.nip34Git.patch.GitPatchEvent
@@ -102,9 +98,7 @@ import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestEvent
import com.vitorpamplona.quartz.nip34Git.pr.GitPullRequestUpdateEvent
import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
private val CardShape = QuoteBorder
private val ChipShape = RoundedCornerShape(8.dp)
private val CardPadding = PaddingValues(start = Size10dp, top = Size10dp, end = Size10dp, bottom = Size5dp)
private val HeaderSpacing = Arrangement.spacedBy(Size8dp)
private val LinkRowSpacing = Arrangement.spacedBy(Size8dp)
@@ -113,15 +107,7 @@ private fun GitCardContainer(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
val border = MaterialTheme.colorScheme.subtleBorder
Column(
modifier =
modifier
.fillMaxWidth()
.clip(CardShape)
.border(1.dp, border, CardShape)
.padding(CardPadding),
) {
Column(modifier = modifier.fillMaxWidth()) {
content()
}
}
@@ -261,12 +247,31 @@ private fun GitMetaRow(
/** Shortens a 40-char git object id to its 7-char prefix for display. */
private fun String.shortCommit(): String = if (length > 7) take(7) else this
/**
* Some NIP-34 clients duplicate the subject tag as a leading markdown heading of the
* content ("# Title\n\n"). The card already renders the subject as its own title, so
* when the first line is a heading matching [subject], drop it from the body.
*/
private fun stripDuplicatedSubject(
content: String,
subject: String?,
): String {
if (subject.isNullOrBlank()) return content
val trimmed = content.trimStart()
if (!trimmed.startsWith("#")) return content
val firstLineEnd = trimmed.indexOf('\n').let { if (it < 0) trimmed.length else it }
val heading = trimmed.substring(0, firstLineEnd).trimStart('#').trim()
if (!heading.equals(subject.trim(), ignoreCase = true)) return content
return trimmed.substring(firstLineEnd).trimStart()
}
/**
* The shared markdown body used by patches, issues and pull requests: honors
* the collapsed [makeItShort] preview for the logged-in user's own posts and
* otherwise renders the full content with sensitivity warnings and uncited
* hashtags. The subject, when present, is rendered separately as a title by the
* caller, so it is not inlined here.
* caller, so it is not inlined here pass it as [renderedSubject] so a copy
* duplicated into the content as a leading heading is stripped.
*/
@Composable
private fun GitMarkdownBody(
@@ -277,8 +282,10 @@ private fun GitMarkdownBody(
backgroundColor: MutableState<Color>,
accountViewModel: AccountViewModel,
nav: INav,
renderedSubject: String? = null,
) {
LoadDecryptedContent(note, accountViewModel) { body ->
LoadDecryptedContent(note, accountViewModel) { rawBody ->
val body = remember(rawBody, renderedSubject) { stripDuplicatedSubject(rawBody, renderedSubject) }
val isAuthorTheLoggedUser =
remember(note.event) { accountViewModel.isLoggedUser(note.author) }
@@ -537,7 +544,7 @@ private fun RenderGitIssueEvent(
Spacer(modifier = HalfDoubleVertSpacer)
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav)
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav, renderedSubject = subject)
if (!makeItShort) {
GitStatusActions(note, accountViewModel)
@@ -669,7 +676,7 @@ private fun RenderGitPullRequestEvent(
Spacer(modifier = HalfDoubleVertSpacer)
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav)
GitMarkdownBody(note, makeItShort, canPreview, quotesLeft, backgroundColor, accountViewModel, nav, renderedSubject = subject)
if (!makeItShort) {
GitPullRequestChanges(cloneUrls, currentCommit, mergeBase, accountViewModel)
@@ -99,9 +99,13 @@ fun GitPullRequestChanges(
when (val s = state) {
ChangesState.Idle ->
FilledTonalButton(onClick = { load() }, modifier = Modifier.padding(top = 8.dp)) {
Icon(MaterialSymbols.Code, contentDescription = null, modifier = Modifier.size(18.dp))
Text(stringRes(R.string.git_pr_view_changes), modifier = Modifier.padding(start = 6.dp))
FilledTonalButton(
onClick = { load() },
modifier = Modifier.padding(top = 8.dp).then(CompactButtonHeight),
contentPadding = CompactButtonPadding,
) {
Icon(MaterialSymbols.Code, contentDescription = null, modifier = Modifier.size(16.dp))
Text(stringRes(R.string.git_pr_view_changes), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
}
ChangesState.Loading ->
@@ -129,9 +133,13 @@ fun GitPullRequestChanges(
}
ChangesState.Failed ->
FilledTonalButton(onClick = { load() }, modifier = Modifier.padding(top = 8.dp)) {
Icon(MaterialSymbols.Refresh, contentDescription = null, modifier = Modifier.size(18.dp))
Text(stringRes(R.string.git_pr_changes_retry), modifier = Modifier.padding(start = 6.dp))
FilledTonalButton(
onClick = { load() },
modifier = Modifier.padding(top = 8.dp).then(CompactButtonHeight),
contentPadding = CompactButtonPadding,
) {
Icon(MaterialSymbols.Refresh, contentDescription = null, modifier = Modifier.size(16.dp))
Text(stringRes(R.string.git_pr_changes_retry), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
}
}
}
@@ -22,6 +22,8 @@ package com.vitorpamplona.amethyst.ui.note.types
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ButtonDefaults
@@ -55,6 +57,10 @@ import com.vitorpamplona.quartz.nip34Git.status.GitStatusOpenEvent
private enum class StatusTarget { OPEN, CLOSED, APPLIED }
/** Compact sizing shared by the small action buttons on git cards. */
internal val CompactButtonHeight = Modifier.height(32.dp)
internal val CompactButtonPadding = PaddingValues(horizontal = 14.dp, vertical = 4.dp)
/**
* NIP-34 status controls for an issue, patch or pull request. Visible only to the
* people allowed to moderate the thread the item's author and the repository
@@ -85,23 +91,33 @@ fun GitStatusActions(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
if (closedOrApplied) {
FilledTonalButton(onClick = { sendStatus(accountViewModel, note, StatusTarget.OPEN) }) {
Icon(MaterialSymbols.RadioButtonChecked, contentDescription = null, modifier = Modifier.size(18.dp))
Text(stringRes(R.string.git_status_reopen), modifier = Modifier.padding(start = 6.dp))
FilledTonalButton(
onClick = { sendStatus(accountViewModel, note, StatusTarget.OPEN) },
modifier = CompactButtonHeight,
contentPadding = CompactButtonPadding,
) {
Icon(MaterialSymbols.RadioButtonChecked, contentDescription = null, modifier = Modifier.size(16.dp))
Text(stringRes(R.string.git_status_reopen), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
}
} else {
if (isPatchOrPr) {
FilledTonalButton(onClick = { sendStatus(accountViewModel, note, StatusTarget.APPLIED) }) {
Icon(MaterialSymbols.Check, contentDescription = null, modifier = Modifier.size(18.dp))
Text(stringRes(R.string.git_status_mark_merged), modifier = Modifier.padding(start = 6.dp))
FilledTonalButton(
onClick = { sendStatus(accountViewModel, note, StatusTarget.APPLIED) },
modifier = CompactButtonHeight,
contentPadding = CompactButtonPadding,
) {
Icon(MaterialSymbols.Check, contentDescription = null, modifier = Modifier.size(16.dp))
Text(stringRes(R.string.git_status_mark_merged), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
}
}
OutlinedButton(
onClick = { sendStatus(accountViewModel, note, StatusTarget.CLOSED) },
colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.error),
modifier = CompactButtonHeight,
contentPadding = CompactButtonPadding,
) {
Icon(MaterialSymbols.Cancel, contentDescription = null, modifier = Modifier.size(18.dp))
Text(stringRes(R.string.git_status_close), modifier = Modifier.padding(start = 6.dp))
Icon(MaterialSymbols.Cancel, contentDescription = null, modifier = Modifier.size(16.dp))
Text(stringRes(R.string.git_status_close), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(start = 6.dp))
}
}
}
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.note.types
import android.graphics.Bitmap
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -46,6 +45,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.graphics.createBitmap
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.stringRes
@@ -160,8 +160,7 @@ private fun Ps1SaveIconImage(icon: Ps1SaveIcon) {
val frames =
remember(icon) {
icon.frames.map { pixels ->
Bitmap
.createBitmap(Ps1SaveIcon.SIZE, Ps1SaveIcon.SIZE, Bitmap.Config.ARGB_8888)
createBitmap(Ps1SaveIcon.SIZE, Ps1SaveIcon.SIZE)
.apply { setPixels(pixels, 0, Ps1SaveIcon.SIZE, 0, 0, Ps1SaveIcon.SIZE, Ps1SaveIcon.SIZE) }
.asImageBitmap()
}
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.browser
import android.net.Uri
import android.os.Build
import androidx.activity.compose.BackHandler
import androidx.annotation.RequiresApi
@@ -44,6 +43,7 @@ import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.net.toUri
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
@@ -193,14 +193,14 @@ private fun EmbeddedWebAppTab(
}
/** The host of [url] for the tab title, falling back to the raw string. */
internal fun hostLabel(url: String): String = runCatching { Uri.parse(url).host }.getOrNull()?.takeIf { it.isNotBlank() } ?: url
internal fun hostLabel(url: String): String = runCatching { url.toUri().host }.getOrNull()?.takeIf { it.isNotBlank() } ?: url
/**
* The `scheme://host[:port]` origin of [url] — the exact form the sandbox reports for NIP-07 consent, so
* it matches the `browser:<origin>` permission-ledger key. Null when [url] has no usable scheme/host.
*/
internal fun browserOrigin(url: String): String? {
val uri = runCatching { Uri.parse(url) }.getOrNull() ?: return null
val uri = runCatching { url.toUri() }.getOrNull() ?: return null
val scheme = uri.scheme?.takeIf { it.isNotBlank() } ?: return null
val host = uri.host?.takeIf { it.isNotBlank() } ?: return null
return "$scheme://$host" + if (uri.port > 0) ":${uri.port}" else ""
@@ -59,6 +59,7 @@ import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
@@ -582,11 +583,11 @@ private fun LocationRow(location: String) {
val trimmed = location.trim()
val intent =
if (isUrl) {
Intent(Intent.ACTION_VIEW, Uri.parse(trimmed))
Intent(Intent.ACTION_VIEW, trimmed.toUri())
} else {
// `geo:0,0?q=<location>` is the Android geo intent; the user's
// installed maps app handles it.
Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=${Uri.encode(trimmed)}"))
Intent(Intent.ACTION_VIEW, "geo:0,0?q=${Uri.encode(trimmed)}".toUri())
}
// runCatching swallows ActivityNotFoundException when no handler is
// installed — we don't have anywhere useful to fall back to.
@@ -64,17 +64,15 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.Amethyst
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.commons.relayauth.AuthPurposeKind
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthDecision
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPermissionStore
import com.vitorpamplona.amethyst.commons.relayauth.RelayAuthPolicy
import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
import com.vitorpamplona.amethyst.service.relayClient.authCommand.compose.LoadRelayAuthUser
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.DataStoreRelayAuthPermissionStore
import com.vitorpamplona.amethyst.service.relayClient.authCommand.model.RelayAuthPermissionLedger
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
@@ -105,8 +103,8 @@ fun RelayAuthSettingsScreen(
nav: INav,
) {
val account = accountViewModel.account
val store: DataStoreRelayAuthPermissionStore = Amethyst.instance.relayAuthPermissionStore
val ledger = remember { RelayAuthPermissionLedger(store, { account.settings.defaultRelayAuthPolicy.value }) }
val store: RelayAuthPermissionStore = account.relayAuthPermissions
val ledger = account.relayAuthLedger
val scope = rememberCoroutineScope()
val globalPolicy by account.settings.defaultRelayAuthPolicy.collectAsState()
+579
View File
@@ -599,6 +599,13 @@
<string name="app_definition_handles">Zpracovává</string>
<string name="app_definition_by">od</string>
<string name="app_definition_available_on">Dostupné na</string>
<string name="app_definition_categories">Kategorie</string>
<string name="app_definition_related">Související</string>
<string name="app_definition_implements">Implementuje</string>
<string name="app_definition_supported_nips">Podporované NIP</string>
<string name="app_definition_via">prostřednictvím %1$s</string>
<string name="app_definition_nip">NIP-%1$s</string>
<string name="app_definition_kind_app">Aplikace</string>
<string name="platform_web">Web</string>
<string name="platform_android">Android</string>
<string name="platform_ios">iOS</string>
@@ -629,6 +636,7 @@
<string name="workout_suggestion_connect_title">Sdílejte své tréninky</string>
<string name="workout_suggestion_connect_message">Nechte Amethyst číst dokončené tréninky z Health Connect (Samsung Health, Google Fit, Fitbit, Garmin…) a navrhnout příspěvek.</string>
<string name="workout_suggestion_connect_button">Připojit</string>
<string name="workout_suggestion_distance_km">%1$s km</string>
<string name="workout_from_health_connect">Z Health Connect</string>
<string name="exercise_running">Běh</string>
<string name="exercise_walking">Chůze</string>
@@ -642,8 +650,12 @@
<string name="exercise_diet">Dieta</string>
<string name="exercise_fasting">Půst</string>
<string name="exercise_circuit">Okruh</string>
<string name="exercise_emom">EMOM</string>
<string name="exercise_amrap">AMRAP</string>
<string name="software_apps">Aplikace</string>
<string name="route_software_apps">Aplikace</string>
<string name="napplets">nApplety</string>
<string name="nsites">nSites</string>
<string name="nsite_none_found">Zatím nenalezeny žádné nSites.</string>
<string name="browser">Prohlížeč</string>
<string name="browser_reload">Obnovit</string>
@@ -654,6 +666,9 @@
<string name="browser_go">Otevřít</string>
<string name="browser_clear">Vymazat</string>
<string name="browser_favorites">Oblíbené</string>
<string name="browser_suggested">Objevujte webové aplikace</string>
<string name="browser_discover_nsites">Weby od lidí, které sledujete</string>
<string name="browser_discover_napplets">Aplikace od lidí, které sledujete</string>
<string name="browser_recent_options">Možnosti</string>
<string name="browser_recent_remove">Odebrat z historie</string>
<string name="favorite_apps">Oblíbené aplikace</string>
@@ -679,11 +694,15 @@
<string name="napplet_permissions_forget">Zapomenout tento nApplet</string>
<string name="napplet_permissions_blocked">Zablokováno</string>
<string name="napplet_permissions_revoke">Odebrat</string>
<string name="napplet_permissions_ask_each_time">Zeptat se pokaždé</string>
<string name="napplet_none_found">Zatím nenalezeny žádné nApplets.</string>
<string name="napplet_fallback_title">nApplet %1$s…</string>
<!-- Napplet sandbox chrome (host top bar + live action notices) -->
<!-- Napplet capability names -->
<string name="napplet_cap_shell">Shell</string>
<string name="napplet_cap_identity">Identita</string>
<string name="napplet_cap_keys">Akce klávesnice</string>
<string name="napplet_cap_relay">Relaye</string>
<string name="napplet_cap_storage">Úložiště</string>
<string name="napplet_cap_value">Platby</string>
<string name="napplet_cap_resource">Síť</string>
@@ -727,14 +746,106 @@
<item quantity="other">Tento nApplet chce zaplatit Lightning fakturu za %1$d sats.</item>
</plurals>
<!-- Signer permissions: first-connect dialog -->
<string name="napplet_connect_title">Připojit k Nostr</string>
<string name="napplet_connect_subtitle">se chce připojit k vašemu účtu Nostr</string>
<string name="napplet_connect_how_handle">Jak se mají zpracovávat požadavky této aplikace?</string>
<string name="napplet_connect_button">Připojit</string>
<string name="napplet_connect_block">Zablokovat a ignorovat %1$s</string>
<!-- Signer trust levels -->
<string name="napplet_policy_full_trust">Plně jí důvěřuji</string>
<string name="napplet_policy_full_trust_desc">Automaticky podepisovat všechny požadavky (kromě plateb)</string>
<string name="napplet_policy_reasonable">Buďme rozumní</string>
<string name="napplet_policy_reasonable_desc">Automaticky schvalovat nejběžnější požadavky</string>
<string name="napplet_policy_paranoid">Jsem trochu paranoidní</string>
<string name="napplet_policy_paranoid_desc">Nepodepisuj nic, aniž by ses mě zeptal!</string>
<!-- Signer per-op consent dialog -->
<string name="napplet_consent_wants_to">chce %1$s</string>
<string name="napplet_consent_show_event">Zobrazit událost</string>
<string name="napplet_consent_hide_event">Skrýt událost</string>
<string name="napplet_consent_more_options">Více možností</string>
<string name="napplet_consent_fewer_options">Méně možností</string>
<string name="napplet_signer_allow_once">Povolit jednou</string>
<string name="napplet_signer_allow_session">Povolit pro tuto relaci</string>
<string name="napplet_signer_allow_24h">Povolit na 24 hodin</string>
<string name="napplet_signer_allow_30d">Povolit na 30 dní</string>
<string name="napplet_signer_allow_op">Znovu se neptat na %1$s</string>
<string name="napplet_signer_allow_all">Znovu se neptat na žádné požadavky Nostr</string>
<string name="napplet_signer_deny_once">Odmítnout</string>
<string name="napplet_signer_deny_op">Vždy odmítnout %1$s</string>
<string name="napplet_signer_last_used">Naposledy použito</string>
<string name="napplet_signer_expires">Vyprší</string>
<!-- Signer op labels -->
<string name="napplet_op_sign_kind">podepsat událost druhu %1$d</string>
<string name="napplet_op_sign_kind_named">podepsat pro %1$s (druh: %2$d)</string>
<string name="napplet_op_encrypt">zašifrovat zprávu</string>
<!-- Decrypt: the message is already decrypted by Amethyst; the permission is to expose it to the app -->
<string name="napplet_op_decrypt">číst vaše soukromé zprávy</string>
<!-- Permissions management screen -->
<string name="napplet_permissions_title">Připojené aplikace</string>
<string name="napplet_permissions_revoke_all">Odvolat všechna oprávnění</string>
<string name="napplet_permissions_overrides">Výjimky operací</string>
<string name="napplet_signer_permissions_empty">Zatím se nepřipojily žádné aplikace.</string>
<string name="napplet_signer_permissions_revoke_all">Odvolat všechna oprávnění</string>
<string name="napplet_decision_allow">Povolit</string>
<string name="napplet_decision_ask">Zeptat se</string>
<string name="napplet_decision_deny">Odmítnout</string>
<string name="napplet_connected_apps_search_keywords">aplikace oprávnění podepisovač napplet nsite webová aplikace důvěra připojené</string>
<string name="napplet_connected_app_trust_level">Úroveň důvěry pro podepisování</string>
<string name="napplet_connected_app_capabilities">Oprávnění</string>
<string name="napplet_connected_app_forget">Zapomenout tuto aplikaci</string>
<string name="napplet_connected_app_op_overrides">Výjimky pro podepisovací operace</string>
<string name="napplet_connected_app_empty">Zatím se nepřipojily žádné aplikace.\n\nAž se webová aplikace připojí k vašemu klíči Nostr, objeví se zde.</string>
<!-- Relay Authentication (NIP-42) settings -->
<string name="relay_auth_settings_title">Autentizace relay</string>
<string name="relay_auth_search_keywords">auth autentizace relay podepsat ověřit nip-42 identita</string>
<string name="relay_auth_global_policy">Kdy se ověřovat</string>
<string name="relay_auth_custom_section">Kam se přihlásit</string>
<string name="relay_auth_policy_always">Vždy se ověřovat</string>
<string name="relay_auth_policy_always_desc">Podepisovat autentizační výzvy pro každý relay, který o to požádá</string>
<string name="relay_auth_policy_never">Nikdy se neověřovat</string>
<string name="relay_auth_policy_never_desc">Ignorovat autentizační výzvy ze všech relayů</string>
<string name="relay_auth_policy_custom">Vlastní</string>
<string name="relay_auth_policy_custom_desc">Vyberte přesně, ke kterým relayům se přihlásit. Na cokoli, co jste níže nepovolili, budete dotázáni.</string>
<string name="relay_auth_toggle_my_relays">Mé relaye a místnosti</string>
<string name="relay_auth_toggle_my_relays_desc">Přihlásit se ke svým vlastním relayům a k veřejným chatům, komunitám a živým vysíláním, ke kterým jste se připojili nebo je oblíbili.</string>
<string name="relay_auth_toggle_read_follows">Číst příspěvky od lidí, které sleduji</string>
<string name="relay_auth_toggle_read_follows_desc">Přihlásit se k relayům sledovaného pro stažení jeho příspěvků.</string>
<string name="relay_auth_toggle_message_follows">Zprávy lidem, které sleduji</string>
<string name="relay_auth_toggle_message_follows_desc">Přihlásit se k relayům sledovaného pro odesílání DM, odpovědí a upozornění.</string>
<string name="relay_auth_toggle_message_strangers">Zprávy komukoli</string>
<string name="relay_auth_toggle_message_strangers_desc">Přihlásit se k relayům cizích lidí pro odesílání DM, odpovědí a upozornění. Ve výchozím nastavení vypnuto; místo toho budete dotázáni pokaždé.</string>
<string name="relay_auth_prompt_title">Potvrdit tomuto relay, že jste to vy?</string>
<string name="relay_auth_prompt_message">Tento relay si nejprve chce ověřit, že jste to opravdu vy. Jeho provozovatel uvidí, který účet jste.</string>
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">Odeslat vaši zprávu pro %1$s?</string>
<string name="relay_auth_title_notify">Upozornit %1$s?</string>
<string name="relay_auth_title_read">Načíst příspěvky z %1$s?</string>
<string name="relay_auth_title_post_venue">Přispět do %1$s?</string>
<string name="relay_auth_title_read_venue">Otevřít %1$s?</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">Pokud tak neučiníte, vaše zpráva pro %1$s nebude doručena.</string>
<string name="relay_auth_consequence_notify">Pokud tak neučiníte, %1$s o tom nebude upozorněn.</string>
<string name="relay_auth_consequence_read">Pokud tak neučiníte, neuvidíte zde příspěvky od %1$s.</string>
<string name="relay_auth_consequence_post_venue">Pokud tak neučiníte, vaše zpráva na %1$s nebude odeslána.</string>
<string name="relay_auth_consequence_read_venue">Pokud tak neučiníte, neuvidíte zde %1$s.</string>
<string name="relay_auth_name_and_others">%1$s a další</string>
<string name="relay_auth_reason_send_dm">Odeslat vaši soukromou zprávu pro:</string>
<string name="relay_auth_reason_notify_inbox">Upozornit:</string>
<string name="relay_auth_reason_read_outbox">Stáhnout příspěvky z:</string>
<string name="relay_auth_reason_post_venue">Přispět do této místnosti</string>
<string name="relay_auth_reason_read_venue">Otevřít tuto místnost</string>
<string name="relay_auth_reason_other">Použít tento relay</string>
<string name="relay_auth_reason_my_own_relay">Připojit se ke svému vlastnímu relay</string>
<string name="relay_auth_allow_once">Povolit jednou</string>
<string name="relay_auth_always_allow">Vždy povolit tento relay</string>
<string name="relay_auth_always_deliver">Vždy doručovat mé zprávy</string>
<string name="relay_auth_block">Zablokovat tento relay</string>
<string name="relay_auth_per_relay_overrides">Výjimky pro jednotlivé relaye</string>
<string name="relay_auth_forget">Zapomenout</string>
<string name="relay_auth_last_used">Naposledy použito před %1$s</string>
<string name="relay_auth_no_overrides">Zatím zde nic není — na každý relay se vztahuje vaše globální zásada.</string>
<string name="relay_auth_decision_allow">Povolit</string>
<string name="relay_auth_decision_deny">Odmítnout</string>
<string name="nip82_repository_label">Zdroj: %1$s</string>
<string name="nip82_version_label">v%1$s</string>
<string name="nip82_download">Stáhnout</string>
@@ -901,6 +1012,122 @@
<string name="route_podcasts">Podcasty</string>
<string name="podcast_view_episodes">Zobrazit epizody</string>
<string name="podcast_no_episodes">Zatím nenalezeny žádné epizody</string>
<string name="podcast_trailer">Upoutávka</string>
<string name="podcast_trailer_season">Série %1$d</string>
<string name="podcast_explicit">Explicitní</string>
<string name="podcast_completed">Dokončeno</string>
<string name="podcast_premium">Prémiový</string>
<string name="podcast_support_show">Podpořte pořad</string>
<string name="podcast_by_author">od %1$s</string>
<string name="podcast_season_episode">S%1$d · E%2$d</string>
<string name="podcast_episode_number">Ep %1$d</string>
<string name="podcast_season">Série %1$d</string>
<string name="podcast_video">Video</string>
<string name="podcast_transcript">Přepis</string>
<string name="podcast_chapters">Kapitoly</string>
<string name="podcast_value_for_value">Value-for-Value</string>
<string name="podcast_value_split_percent">%1$d%%</string>
<string name="podcast_value_zap_split_hint">Zapy na toto se rozdělují mezi:</string>
<string name="podcast_hosts_and_guests">Moderátoři a hosté</string>
<string name="podcast_play_soundbite">Přehrát ukázku</string>
<string name="podcast_top_supporters">Nejlepší podporovatelé</string>
<plurals name="podcast_chapters_count">
<item quantity="one">%1$d kapitola</item>
<item quantity="few">%1$d kapitoly</item>
<item quantity="many">%1$d kapitoly</item>
<item quantity="other">%1$d kapitol</item>
</plurals>
<string name="podcast_role_host">Moderátor</string>
<string name="podcast_role_cohost">Spolumoderátor</string>
<string name="podcast_role_editor">Editor</string>
<string name="podcast_author_verified">Ověřený autor</string>
<string name="podcast_value_error_title">Chyba Value-for-Value</string>
<string name="podcast_value_no_recipients">Tento podcast nemá žádné platitelné příjemce hodnoty.</string>
<string name="podcast_value_keysend_requires_nwc">Připojte peněženku Nostr Wallet Connect pro odesílání příjemcům keysend (uzel).</string>
<string name="podcast_value_stream">Streamovat sats</string>
<string name="podcast_value_stream_rate">%1$d sats/min</string>
<string name="podcast_value_stream_hint">Automaticky posílá hodnotu, když posloucháte.</string>
<string name="podcast_value_streamed_total">V této relaci odesláno %1$d sats</string>
<string name="podcast_value_stream_requires_wallet">Připojte peněženku Nostr Wallet Connect nebo debetní peněženku pro streamování sats během poslechu.</string>
<string name="podcast_new_episode">Nová epizoda</string>
<string name="podcast_edit_episode">Upravit epizodu</string>
<string name="podcast_publishing_banner">Publikování…</string>
<string name="podcast_cover_upload_cta">Přidat obal</string>
<string name="podcast_cover_upload_hint">Čtvercový obrázek zobrazený u epizody</string>
<string name="podcast_episode_title_label">Název</string>
<string name="podcast_episode_title_placeholder">Název epizody</string>
<string name="podcast_episode_summary_label">Shrnutí</string>
<string name="podcast_episode_duration_label">Délka (sekundy)</string>
<string name="podcast_episode_more_details">Více podrobností</string>
<string name="podcast_episode_season_label">Série</string>
<string name="podcast_episode_number_label">Epizoda č.</string>
<string name="podcast_episode_video_label">URL videa</string>
<string name="podcast_episode_transcript_label">URL přepisu</string>
<string name="podcast_episode_chapters_label">URL kapitol</string>
<string name="podcast_episode_topics_label">Témata</string>
<string name="podcast_episode_topics_placeholder">čárkami, oddělené, štítky</string>
<string name="podcast_episode_audio_url_label">URL zvuku</string>
<string name="podcast_episode_audio_url_placeholder">https://…/epizoda.mp3</string>
<string name="podcast_episode_audio_picked">Zvukový soubor připraven k nahrání</string>
<string name="podcast_episode_audio_upload_cta">Přidat zvukový soubor</string>
<string name="podcast_episode_audio_upload_hint">MP3, M4A nebo jiný zvuk</string>
<string name="podcast_episode_delete">Smazat epizodu</string>
<string name="podcast_episode_delete_confirm">Smazat tuto epizodu? Tuto akci nelze vrátit zpět.</string>
<string name="podcast_edit_show">Váš podcast</string>
<string name="podcast_show_cover_cta">Přidat obal</string>
<string name="podcast_show_cover_hint">Čtvercový obal vašeho pořadu</string>
<string name="podcast_show_title_label">Název pořadu</string>
<string name="podcast_show_title_placeholder">Můj podcast</string>
<string name="podcast_show_description_label">Popis</string>
<string name="podcast_show_author_label">Autor</string>
<string name="podcast_show_email_label">Kontaktní e-mail</string>
<string name="podcast_show_website_label">Web</string>
<string name="podcast_show_categories_label">Kategorie</string>
<string name="podcast_show_categories_placeholder">Technologie, Zprávy</string>
<string name="podcast_show_funding_label">Odkazy na financování</string>
<string name="podcast_show_funding_placeholder">https://…</string>
<string name="podcast_show_language_label">Jazyk</string>
<string name="podcast_show_language_placeholder">cs</string>
<string name="podcast_show_copyright_label">Autorská práva</string>
<string name="podcast_show_type_label">Typ pořadu</string>
<string name="podcast_show_type_episodic">Epizodický</string>
<string name="podcast_show_type_serial">Seriálový</string>
<string name="podcast_show_explicit">Explicitní obsah</string>
<string name="podcast_show_complete">Pořad kompletní (žádné další epizody)</string>
<string name="podcast_show_locked">Uzamčeno (prémiové)</string>
<string name="podcast_new_trailer">Nová upoutávka</string>
<string name="podcast_trailer_upload_cta">Přidat klip upoutávky</string>
<string name="podcast_trailer_upload_hint">Krátký zvukový nebo video náhled</string>
<string name="podcast_trailer_title_placeholder">Název upoutávky</string>
<string name="podcast_trailer_url_label">URL média</string>
<string name="podcast_your_podcast">Váš podcast</string>
<string name="podcast_untitled">Bez názvu</string>
<string name="podcast_no_episodes_yet">Zatím žádné epizody. Klepnutím na Nová epizoda publikujte svou první.</string>
<string name="podcast_create_your_show">Vytvořte svůj podcast</string>
<string name="podcast_tap_to_edit_show">Klepnutím upravíte podrobnosti pořadu</string>
<string name="podcast_create_show_hint">Nastavte název, obal a podrobnosti svého pořadu</string>
<plurals name="podcast_trailer_count">
<item quantity="one">%1$d upoutávka</item>
<item quantity="few">%1$d upoutávky</item>
<item quantity="many">%1$d upoutávky</item>
<item quantity="other">%1$d upoutávek</item>
</plurals>
<string name="podcast_value_editor_hint">Přidejte příjemce pro rozdělení příchozích sats podle váhy. Posluchači posílají boost nebo streamují hodnotu do těchto cílů.</string>
<string name="podcast_value_add_recipient">Přidat příjemce</string>
<string name="podcast_value_add_address">Přidat adresu ručně</string>
<string name="podcast_value_search_user">Přidat uživatele Nostr</string>
<string name="podcast_value_search_user_hint">Hledat podle jména nebo @handle</string>
<string name="podcast_value_user_no_lnaddress">Tento uživatel nemá Lightning adresu</string>
<string name="podcast_value_remove_recipient">Odebrat příjemce</string>
<string name="podcast_value_recipient_name">Jméno (volitelné)</string>
<string name="podcast_value_type_lnaddress">Lightning adresa</string>
<string name="podcast_value_type_node">Uzel (keysend)</string>
<string name="podcast_value_lnaddress">Lightning adresa</string>
<string name="podcast_value_lnaddress_hint">jmeno@example.com</string>
<string name="podcast_value_node_pubkey">Veřejný klíč uzlu</string>
<string name="podcast_value_node_pubkey_hint">02abc… (33bajtový hex)</string>
<string name="podcast_value_weight">Váha</string>
<string name="podcast_value_fee">Poplatek</string>
<plurals name="podcast_episode_count">
<item quantity="one">%1$d epizoda</item>
<item quantity="few">%1$d epizody</item>
@@ -933,6 +1160,10 @@
</plurals>
<string name="private_bookmarks">Soukromé záložky</string>
<string name="public_bookmarks">Veřejné záložky</string>
<string name="repository_bookmarks">Repozitáře</string>
<string name="repository_bookmarks_explainer">Vaše git repozitáře v záložkách</string>
<string name="podcast_bookmarks">Podcasty</string>
<string name="podcast_bookmarks_explainer">Vaše podcasty a epizody v záložkách</string>
<string name="add_to_private_bookmarks">Přidat do soukromých záložek</string>
<string name="add_to_public_bookmarks">Přidat do veřejných záložek</string>
<string name="remove_from_private_bookmarks">Odebrat ze soukromých záložek</string>
@@ -1482,6 +1713,26 @@
<string name="wallet_connect">Připojení peněženky</string>
<string name="language">Jazyk</string>
<string name="theme">Motiv</string>
<string name="accent_color">Barva zvýraznění</string>
<string name="accent_color_description">Hlavní barva používaná napříč tlačítky a odkazy</string>
<string name="accent_color_purple">Fialová</string>
<string name="accent_color_blue">Modrá</string>
<string name="accent_color_green">Zelená</string>
<string name="accent_color_orange">Oranžová</string>
<string name="accent_color_red">Červená</string>
<string name="accent_color_pink">Růžová</string>
<string name="font_family">Písmo</string>
<string name="font_family_description">Typ písma používaný v celé aplikaci</string>
<string name="font_family_system">Výchozí systémové</string>
<string name="font_family_sans_serif">Bezpatkové</string>
<string name="font_family_serif">Patkové</string>
<string name="font_family_monospace">Neproporcionální</string>
<string name="font_size">Velikost písma</string>
<string name="font_size_description">Změna velikosti textu v celé aplikaci</string>
<string name="font_size_small">Malá</string>
<string name="font_size_normal">Normální</string>
<string name="font_size_large">Velká</string>
<string name="font_size_huge">Obrovská</string>
<string name="automatically_load_images_gifs">Automaticky načítat obrázky/gif</string>
<string name="automatically_play_videos">Automaticky přehrávat videa</string>
<string name="autoplay_videos">Automatické přehrávání videí</string>
@@ -1558,6 +1809,118 @@
<string name="messages_create_public_chat">Veřejné</string>
<string name="messages_create_group">Skupina</string>
<string name="messages_create_public_private_chat_description">Nová veřejná nebo soukromá skupina</string>
<string name="relay_groups_title">Skupiny relay</string>
<string name="relay_group_view_inline">V řadě</string>
<string name="relay_group_view_grouped">Podle relay</string>
<string name="relay_group_view_inline_desc">Zobrazí každou skupinu jako vlastní konverzaci, promíchanou s vašimi chaty.</string>
<string name="relay_group_view_grouped_desc">Sbalí skupiny každého relay do jednoho řádku, umístěného u jeho nejnovější zprávy.</string>
<string name="relay_group_view_mode_title">Zobrazení skupin NIP-29</string>
<string name="relay_group_server_label">Skupiny relay</string>
<string name="relay_groups_button">Skupiny</string>
<string name="messages_settings">Zprávy</string>
<string name="relay_group_create_title">Vytvořit skupinu</string>
<string name="relay_group_relay_no_nip29">Tento relay neuvádí podporu skupin NIP-29. Skupina zde vytvořená nebude fungovat — její název, členové a zprávy nebudou relayem spravovány. Vyberte relay, který podporuje skupiny založené na relay.</string>
<string name="relay_group_create_name">Název skupiny</string>
<string name="relay_group_create_topic">Téma (volitelné)</string>
<string name="relay_group_create_private">Soukromá (čtení jen pro členy)</string>
<string name="relay_group_create_invite_only">Pouze na pozvání</string>
<string name="relay_group_create_confirm">Vytvořit</string>
<string name="relay_group_invite_title">Pozvat lidi</string>
<string name="relay_group_invite_description">Sdílejte tento kód, aby se lidé mohli připojit k této skupině.</string>
<string name="relay_group_invite_generating">Vytváření pozvánky…</string>
<string name="relay_group_invite_copied">Kód pozvánky zkopírován</string>
<string name="relay_group_invite_code_label">Kód pozvánky (pro tuto skupinu na pozvání):</string>
<string name="relay_group_join_title">Připojit se ke skupině</string>
<string name="relay_group_join_code_label">Kód pozvánky</string>
<string name="relay_group_join_code_hint">Tato skupina je pouze na pozvání. Zadejte kód, který jste dostali.</string>
<string name="relay_group_join_confirm">Připojit se</string>
<string name="relay_group_pending">Požádáno</string>
<string name="relay_group_role_admin">Správce</string>
<string name="relay_group_role_moderator">Moderátor</string>
<string name="relay_group_role_member">Člen</string>
<string name="relay_group_members_title">Členové</string>
<string name="relay_group_make_admin">Udělat správcem</string>
<string name="relay_group_make_moderator">Udělat moderátorem</string>
<string name="relay_group_demote_member">Odebrat roli</string>
<string name="relay_group_remove_user">Odebrat ze skupiny</string>
<string name="relay_group_remove_user_confirm">Odebrat %1$s z této skupiny? Ztratí přístup, dokud nebude znovu přidán nebo pozván.</string>
<string name="relay_group_edit_title">Upravit skupinu</string>
<string name="relay_group_edit_name">Název skupiny</string>
<string name="relay_group_edit_topic">Téma (volitelné)</string>
<string name="relay_group_edit_private">Soukromá (čtení jen pro členy)</string>
<string name="relay_group_edit_invite_only">Pouze na pozvání</string>
<string name="relay_group_edit_confirm">Uložit</string>
<string name="relay_group_menu_members">Členové</string>
<string name="relay_group_menu_edit">Upravit skupinu</string>
<string name="relay_group_threads_title">Vlákna</string>
<string name="relay_group_open">Otevřít skupinu</string>
<string name="relay_group_channels_empty">Na tomto relay zatím nejsou žádné skupiny.</string>
<string name="relay_group_invite_preparing">Příprava pozvánky…</string>
<string name="relay_group_badge_private">Soukromá</string>
<string name="relay_group_badge_invite_only">Pouze na pozvání</string>
<string name="relay_group_browse_invalid_url">Zadejte platnou URL relay (wss://…).</string>
<string name="relay_group_field_name">Název</string>
<string name="relay_group_field_about">Popis</string>
<string name="relay_group_field_picture">Obrázek skupiny</string>
<string name="relay_group_add_photo">Přidat fotku</string>
<string name="relay_group_change_photo">Změnit fotku</string>
<string name="relay_group_section_discovery">Objevování</string>
<string name="relay_group_section_discovery_desc">Pomozte lidem najít tuto skupinu. Témata a poloha ji zobrazí pod odpovídajícími filtry objevování (pokud je hostitelský relay podporuje).</string>
<string name="relay_group_field_topics">Témata</string>
<string name="relay_group_field_topics_hint">bitcoin, nostr, umění</string>
<string name="relay_group_field_geohash">Poloha (geohash)</string>
<string name="relay_group_field_geohash_hint">u0nd</string>
<string name="relay_group_section_permissions">Oprávnění</string>
<string name="relay_group_flag_private">Soukromá</string>
<string name="relay_group_flag_private_desc">Zprávy mohou číst pouze členové.</string>
<string name="relay_group_flag_invite_only">Pouze na pozvání</string>
<string name="relay_group_flag_invite_only_desc">Lidé musí být pozváni nebo schváleni, aby se mohli připojit.</string>
<string name="relay_group_flag_restricted">Přispívání jen pro členy</string>
<string name="relay_group_flag_restricted_desc">Zprávy mohou psát pouze členové.</string>
<string name="relay_group_flag_hidden">Neuvedená</string>
<string name="relay_group_flag_hidden_desc">Skrýt tuto skupinu z veřejného adresáře relay.</string>
<string name="relay_group_discovery_empty">Hledání skupin napříč vašimi relayi…</string>
<string name="relay_group_discovery_empty_filtered">Pro tento filtr zatím nebyly nalezeny žádné skupiny.</string>
<string name="relay_group_favorite_relay">Oblíbit tento relay</string>
<string name="relay_group_threads_empty">Zatím žádná vlákna. Založte jedno tlačítkem +.</string>
<string name="relay_group_thread_new">Nové vlákno</string>
<string name="relay_group_thread_untitled">Bez názvu</string>
<string name="relay_group_thread_title_label">Název</string>
<string name="relay_group_thread_body_label">Napište něco…</string>
<string name="relay_group_thread_post">Přispět</string>
<string name="relay_group_browse_title">Najít skupiny</string>
<string name="relay_group_browse_description">Procházejte skupiny hostované na relay. Vložte adresu relay nebo vyberte některou níže.</string>
<string name="relay_group_browse_relay_label">Adresa relay</string>
<string name="relay_group_browse_go">Procházet</string>
<string name="relay_group_browse_your_relays">Relaye, na kterých jste</string>
<string name="relay_group_browse_popular">Oblíbené relaye</string>
<string name="relay_group_no_messages_yet">Zatím žádné zprávy</string>
<string name="relay_group_join_to_post">Připojte se k této skupině pro odesílání zpráv.</string>
<string name="relay_group_invite_only_to_post">Tato skupina je pouze na pozvání — k přispívání potřebujete pozvánku.</string>
<plurals name="relay_group_member_count">
<item quantity="one">%1$d člen</item>
<item quantity="few">%1$d členové</item>
<item quantity="many">%1$d člena</item>
<item quantity="other">%1$d členů</item>
</plurals>
<plurals name="relay_group_message_count">
<item quantity="one">%1$d zpráva</item>
<item quantity="few">%1$d zprávy</item>
<item quantity="many">%1$d zprávy</item>
<item quantity="other">%1$d zpráv</item>
</plurals>
<plurals name="relay_group_message_count_capped">
<item quantity="one">%1$d+ zpráva</item>
<item quantity="few">%1$d+ zprávy</item>
<item quantity="many">%1$d+ zprávy</item>
<item quantity="other">%1$d+ zpráv</item>
</plurals>
<plurals name="relay_group_follows_participating">
<item quantity="one">%1$d osoba, kterou sledujete</item>
<item quantity="few">%1$d osoby, které sledujete</item>
<item quantity="many">%1$d osoby, které sledujete</item>
<item quantity="other">%1$d osob, které sledujete</item>
</plurals>
<string name="messages_new_message">Soukromé</string>
<string name="messages_new_message_to">Pro</string>
<string name="messages_new_message_subject">Předmět</string>
@@ -1797,12 +2160,42 @@
<string name="cashu_no_wallet_description">Vytvořte si peněženku Cashu pro uchovávání tokenů ecash a příjem nutzapů.</string>
<string name="cashu_discovering">Hledám vaši peněženku…</string>
<string name="cashu_discovering_description">Peněženky NIP-60 se synchronizují mezi klienty. Pokud jste si nějakou vytvořili v jiné aplikaci pod tímto klíčem Nostr, měla by se za pár sekund objevit.</string>
<string name="cashu_wizard_title">Nastavte si peněženku</string>
<string name="cashu_wizard_searching">Hledání vaší peněženky…</string>
<string name="cashu_wizard_searching_description">Prohledáváme každý relay a hledáme peněženku Cashu publikovanou pod vaším klíčem Nostr.</string>
<string name="cashu_wizard_searching_progress">Prohledávání relayů… %1$d / %2$d</string>
<string name="cashu_wizard_analyzing">Ověřování peněženek, které jsme našli…</string>
<string name="cashu_wizard_none_title">Žádná peněženka nenalezena</string>
<string name="cashu_wizard_none_description">Na žádném relay jsme nenašli existující peněženku Cashu pod vaším klíčem Nostr. Začněte vytvořením nové.</string>
<string name="cashu_wizard_create">Vytvořit novou peněženku</string>
<string name="cashu_wizard_single_title">Našli jsme vaši peněženku</string>
<string name="cashu_wizard_single_description">Tato peněženka Cashu je publikována v síti Nostr pod vaším klíčem. Používejte ji na tomto zařízení — znovu ji rozešleme na vaše relaye, aby se příště snadno našla.</string>
<string name="cashu_wizard_use_wallet">Použít tuto peněženku</string>
<string name="cashu_wizard_multiple_title">Našli jsme několik peněženek</string>
<string name="cashu_wizard_multiple_description">Máte v síti více než jednu peněženku Cashu — nejspíše vytvořené různými aplikacemi. Nejnovější se stane vaší hlavní peněženkou; převeďte do ní veškeré prostředky ze starších.</string>
<string name="cashu_wizard_main_label">Nejnovější — vaše hlavní peněženka</string>
<string name="cashu_wizard_old_label">Starší peněženka</string>
<string name="cashu_wizard_set_main">Nastavit jako hlavní peněženku</string>
<string name="cashu_wizard_recover_funds">Obnovit prostředky do hlavní peněženky</string>
<string name="cashu_wizard_recoverable">%1$s sats k obnovení</string>
<string name="cashu_wizard_recovered">Obnoveno %1$s sats</string>
<string name="cashu_wizard_no_funds">Žádné obnovitelné prostředky</string>
<string name="cashu_wizard_invalid">Tuto peněženku nelze přečíst</string>
<string name="cashu_wizard_set_main_first">Nejprve nastavte hlavní peněženku, poté obnovte prostředky ze starších.</string>
<string name="cashu_wizard_adopting">Nastavování vaší peněženky…</string>
<string name="cashu_wizard_retry">Hledat znovu</string>
<string name="cashu_wizard_mints_label">Mincovny: %1$s</string>
<string name="cashu_created_title">Peněženka vytvořena</string>
<string name="cashu_created_subtitle">Nyní vyberte několik mincoven, které budou hostit vaše sats.</string>
<string name="cashu_created_pick_mints">Vyberte mincovny</string>
<string name="cashu_balance">Zůstatek</string>
<string name="cashu_mints">Minty</string>
<string name="cashu_mint_url">URL mintu</string>
<string name="cashu_remove_mint">Odebrat mint</string>
<string name="cashu_add_mint">Přidat mint</string>
<string name="cashu_history">Historie</string>
<string name="cashu_wallet_autosaves">Vaše peněženka se ukládá automaticky, jak přidáváte nebo odebíráte mincovny. Klíč nutzap se pro vás vytvoří při prvním přidání mincovny.</string>
<string name="cashu_wallet_saving">Ukládání…</string>
<string name="cashu_p2pk_section">Klíč pro nutzap (pokročilé)</string>
<string name="cashu_p2pk_explainer">Samostatný soukromý klíč používaný pouze k příjmu nutzapů NIP-61. Není to klíč vaší identity Nostr.</string>
<string name="cashu_p2pk_autogen">Vygenerovat nový klíč</string>
@@ -2158,6 +2551,7 @@
<string name="profile_ui_setting_app_recommendations">Doporučení aplikací</string>
<string name="profile_ui_setting_zap_received_feed">Kanál přijatých zapů</string>
<string name="profile_ui_setting_followers_feed">Kanál sledujících</string>
<string name="profile_ui_setting_onchain_wallet">Bitcoin (on-chain) peněženka</string>
<string name="reactions_settings">Nastavení reakcí</string>
<string name="reactions_settings_description">Nastavte, která tlačítka reakcí se zobrazují, jejich pořadí a zda se mají zobrazovat počty.</string>
<string name="reactions_settings_enabled">Povoleno</string>
@@ -2306,6 +2700,10 @@
<string name="forked_from">Rozštěpováno od</string>
<string name="git_web_address">Internet:</string>
<string name="git_clone_address">Klon:</string>
<string name="git_branch">Větev</string>
<string name="git_commit">Commit</string>
<string name="git_merge_base">Základ sloučení</string>
<string name="git_pr_update_description">Pull request byl aktualizován na nový commit.</string>
<string name="git_status_open">Otevřeno</string>
<string name="git_status_merged">Sloučeno</string>
<string name="git_status_closed">Uzavřeno</string>
@@ -2313,12 +2711,86 @@
<string name="git_repo_tab_overview">Přehled</string>
<string name="git_repo_tab_issues">Úkoly</string>
<string name="git_repo_tab_patches">Patche a PR</string>
<string name="git_repo_filter_open">Otevřené</string>
<string name="git_repo_filter_closed">Uzavřené a vyřešené</string>
<string name="git_repo_label_all">Vše</string>
<string name="git_repo_bookmark">Přidat repozitář do záložek</string>
<string name="git_repo_stat_branches">Větve</string>
<string name="git_repo_stat_tags">Značky</string>
<string name="git_repo_stat_files">Soubory</string>
<string name="git_repo_stat_updated">Aktualizováno</string>
<string name="git_repo_recent_activity">Nedávná aktivita</string>
<string name="git_repo_maintained_by">Spravuje</string>
<string name="git_repo_external_host_title">Hostováno externě</string>
<string name="git_repo_external_host_body">Tento repozitář nelze klonovat přes http(s), takže zde není zobrazení kódu k dispozici.</string>
<string name="git_repo_open_in_browser">Otevřít v prohlížeči</string>
<string name="git_untitled">Bez názvu</string>
<string name="git_repo_section_about">O projektu</string>
<string name="git_repo_section_links">Odkazy</string>
<string name="git_repo_section_maintainers">Správci</string>
<string name="git_repo_section_topics">Témata</string>
<string name="git_repo_personal_fork">Osobní fork</string>
<string name="git_repo_tab_readme">Readme</string>
<string name="git_repo_tab_code">Kód</string>
<string name="git_repo_code_loading">Načítání repozitáře…</string>
<string name="git_repo_code_error">Repozitář se nepodařilo načíst z jeho klonovací URL.</string>
<string name="git_repo_no_clone_url">Toto oznámení repozitáře neobsahuje žádnou http(s) klonovací URL k procházení.</string>
<string name="git_repo_readme_missing">Tento repozitář nemá soubor README.</string>
<string name="git_repo_file_load_error">Tento soubor se nepodařilo načíst.</string>
<string name="git_repo_binary_file">Binární soubor (%1$s) — náhled není k dispozici.</string>
<string name="git_repo_empty_folder">Tato složka je prázdná.</string>
<string name="git_repo_root">kořen</string>
<string name="git_repo_retry">Zkusit znovu</string>
<string name="git_repo_default_branch">výchozí</string>
<string name="git_repo_branches">Větve</string>
<string name="git_repo_tags">Značky</string>
<string name="git_repo_search_files">Hledat soubory…</string>
<string name="git_repo_no_search_results">Žádné odpovídající soubory.</string>
<string name="git_repo_commits">Commity</string>
<string name="git_repo_no_commits">Není k dispozici žádná historie commitů.</string>
<string name="git_repo_copy_file">Kopírovat obsah souboru</string>
<string name="git_repo_plain_text">Text</string>
<plurals name="git_repo_item_count">
<item quantity="one">%1$d položka</item>
<item quantity="few">%1$d položky</item>
<item quantity="many">%1$d položky</item>
<item quantity="other">%1$d položek</item>
</plurals>
<plurals name="git_diff_files_changed">
<item quantity="one">%1$d soubor změněn</item>
<item quantity="few">%1$d soubory změněny</item>
<item quantity="many">%1$d souboru změněno</item>
<item quantity="other">%1$d souborů změněno</item>
</plurals>
<string name="git_diff_binary">Binární soubor se nezobrazuje.</string>
<string name="git_new_issue_button">Nový</string>
<string name="git_new_issue_title">Nový problém</string>
<string name="git_new_issue_subject">Název</string>
<string name="git_new_issue_body">Popis</string>
<string name="git_new_issue_create">Vytvořit</string>
<string name="git_new_issue_cancel">Zrušit</string>
<string name="git_new_issue_labels">Štítky</string>
<string name="git_new_issue_labels_hint">bug, vylepšení…</string>
<string name="git_issue_close">Uzavřít problém</string>
<string name="git_issue_reopen">Znovu otevřít</string>
<string name="git_status_close">Uzavřít</string>
<string name="git_status_reopen">Znovu otevřít</string>
<string name="git_status_mark_merged">Označit jako sloučené</string>
<string name="git_pr_view_changes">Zobrazit změny</string>
<string name="git_pr_loading_changes">Načítání změn…</string>
<string name="git_pr_no_changes">Nebyly nalezeny žádné změny souborů.</string>
<string name="git_pr_changes_retry">Zkusit načíst změny znovu</string>
<string name="git_pr_revised">Upraveno</string>
<string name="git_repo_settings_title">Upravit repozitář</string>
<string name="git_repo_settings_name">Název</string>
<string name="git_repo_settings_description">Popis</string>
<string name="git_repo_settings_clone_urls">Klonovací URL (jedna na řádek)</string>
<string name="git_repo_settings_web_urls">Webové URL (jedna na řádek)</string>
<string name="git_repo_settings_topics">Témata (oddělená čárkami)</string>
<string name="git_repo_settings_save">Uložit</string>
<string name="git_repositories">Git repozitáře</string>
<string name="nsite_title">Statický web: %1$s</string>
<string name="napplet_card_title">nApplet: %1$s</string>
<string name="napplet_card_permissions">Oprávnění:</string>
<string name="profile_tab_apps">Aplikace &amp; Weby</string>
<string name="nsite_root_site">Kořenový web</string>
@@ -2607,6 +3079,8 @@
<string name="kind_git_patch">Git záplata</string>
<string name="kind_git_repo">Git repozitář</string>
<string name="kind_git_reply">Git odpověď</string>
<string name="kind_git_pr">Pull request</string>
<string name="kind_git_pr_update">Aktualizace PR</string>
<string name="kind_zap_goals">Cíle zapů</string>
<string name="kind_hashtag_follows">Sledované hashtagy</string>
<string name="kind_highlights">Zvýraznění</string>
@@ -2907,6 +3381,7 @@
<string name="goal_progress">%1$s financováno z %2$s sats cíle</string>
<string name="fundraiser_ends">Končí %1$s</string>
<string name="fundraiser_onchain_donation">On-chain dar</string>
<string name="bird_detection_title">Detekce ptáků</string>
<plurals name="birdex_species_count">
<item quantity="one">Birdex · %1$d druh</item>
<item quantity="few">Birdex · %1$d druhy</item>
@@ -2920,6 +3395,9 @@
<item quantity="other">%1$s +%2$d dalších</item>
</plurals>
<!-- PS1 memory-card saves over nostr (kind 38192). "PS1" is the PlayStation 1, do not translate. -->
<string name="ps1_save_title">Uložení na paměťovou kartu PS1</string>
<string name="ps1_save_block">blok %1$d</string>
<string name="ps1_save_empty_slot">Prázdný slot</string>
<!-- Roadstr road event reports (kinds 1315/1316). "Roadstr" is a proper noun, do not translate. -->
<string name="road_event_police">Policie</string>
<string name="road_event_speed_camera">Rychlostní radar</string>
@@ -3048,6 +3526,105 @@
<string name="compose_settings">Nastavení editoru</string>
<string name="auto_create_drafts_setting_title">Automaticky vytvářet koncepty</string>
<string name="auto_create_drafts_setting_description">Automaticky uloží koncept události, když píšeš nebo opouštíš editor s neodeslaným textem, a odešle ho na tvé soukromé odchozí relaye.</string>
<string name="compose_signature_setting_title">Podpis</string>
<string name="compose_signature_setting_description">Přidá se na konec zprávy při otevírání nového příspěvku, odpovědi, citace nebo článku. Ponechte prázdné pro vypnutí.</string>
<string name="compose_signature_setting_hint">Váš podpis</string>
<string name="pow_settings_title">Proof of Work</string>
<string name="pow_difficulty_title">Obtížnost</string>
<string name="pow_difficulty_explainer">Vytěží do vašich příspěvků NIP-13 proof of work před publikováním, aby je relaye a čtenáři mohli zvážit oproti spamu. Vyšší hodnoty trvají exponenciálně déle. Příspěvky se po vytěžení publikují na pozadí.</string>
<string name="pow_difficulty_off">Vypnuto</string>
<string name="pow_custom_difficulty_title">Vlastní obtížnost</string>
<string name="pow_custom_difficulty_explainer">Jemné doladění cíle v počtu úvodních nulových bitů.</string>
<string name="pow_categories_title">Co těžit</string>
<string name="pow_categories_explainer">Časově kritické události (autentizace relay, žádosti o zap, zprávy peněženky a podepisovače, koncepty, seznamy) se nikdy netěží.</string>
<string name="pow_category_short_notes">Krátké poznámky a odpovědi</string>
<string name="pow_category_short_notes_explainer">Hlavní veřejná plocha pro spam</string>
<string name="pow_category_comments">Komentáře</string>
<string name="pow_category_comments_explainer">Odpovědi na články, soubory a jiný obsah</string>
<string name="pow_category_reports">Nahlášení</string>
<string name="pow_category_reports_explainer">Relaye váží nahlášení podle jejich nákladů</string>
<string name="pow_category_long_form">Dlouhé texty a zvýraznění</string>
<string name="pow_category_long_form_explainer">Články a zvýraznění; zřídkavé, náklady jsou zanedbatelné</string>
<string name="pow_category_voice">Hlasové zprávy</string>
<string name="pow_category_voice_explainer">Veřejné hlasové příspěvky a odpovědi</string>
<string name="pow_category_reposts">Přeposlání</string>
<string name="pow_category_reposts_explainer">Vysoký objem pro aktivní uživatele</string>
<string name="pow_category_reactions">Reakce</string>
<string name="pow_category_reactions_explainer">Nejobjemnější druh; těžení každého lajku stojí baterii</string>
<string name="pow_category_public_chat">Veřejný a živý chat</string>
<string name="pow_category_public_chat_explainer">Prodlevy při těžení narušují plynulost konverzace</string>
<string name="pow_category_gift_wraps">Obálky soukromých zpráv</string>
<string name="pow_category_gift_wraps_explainer">Umožňuje DM relayům filtrovat spam ve schránce; těží se pouze vnější obálka, nikdy vaše zpráva</string>
<string name="pow_category_other_public">Jiný veřejný obsah</string>
<string name="pow_category_other_public_explainer">Ankety, živé statusy, inzeráty a vše ostatní veřejné</string>
<string name="pow_mining_title">Těžení proof of work</string>
<plurals name="pow_mining_progress">
<item quantity="one">Těžení proof of work… (%1$d příspěvek ve frontě)</item>
<item quantity="few">Těžení proof of work… (%1$d příspěvky ve frontě)</item>
<item quantity="many">Těžení proof of work… (%1$d příspěvku ve frontě)</item>
<item quantity="other">Těžení proof of work… (%1$d příspěvků ve frontě)</item>
</plurals>
<plurals name="pow_mining_job">
<item quantity="one">%1$s • těžení na %2$d bitu</item>
<item quantity="few">%1$s • těžení na %2$d bitech</item>
<item quantity="many">%1$s • těžení na %2$d bitu</item>
<item quantity="other">%1$s • těžení na %2$d bitech</item>
</plurals>
<plurals name="pow_queued_job">
<item quantity="one">%1$s • čeká na těžbu na %2$d bitu</item>
<item quantity="few">%1$s • čeká na těžbu na %2$d bitech</item>
<item quantity="many">%1$s • čeká na těžbu na %2$d bitu</item>
<item quantity="other">%1$s • čeká na těžbu na %2$d bitech</item>
</plurals>
<plurals name="pow_option_default_on">
<item quantity="one">Výchozí (%1$d bit)</item>
<item quantity="few">Výchozí (%1$d bity)</item>
<item quantity="many">Výchozí (%1$d bitu)</item>
<item quantity="other">Výchozí (%1$d bitů)</item>
</plurals>
<string name="pow_option_default_off">Výchozí (vypnuto)</string>
<string name="pow_option_off">Vypnuto pro tento příspěvek</string>
<plurals name="pow_option_bits">
<item quantity="one">%1$d bit</item>
<item quantity="few">%1$d bity</item>
<item quantity="many">%1$d bitu</item>
<item quantity="other">%1$d bitů</item>
</plurals>
<string name="pow_notification_channel_name">Těžení proof of work</string>
<string name="pow_notification_channel_description">Zobrazuje příspěvky, které stále těží svůj NIP-13 proof of work, aby mohly dokončit těžbu i po opuštění aplikace.</string>
<string name="pow_notification_cancel_all">Zrušit</string>
<string name="pow_difficulty_estimate">≈ %1$s na příspěvek na tomto zařízení</string>
<string name="pow_estimate_instant">&lt;1 s</string>
<plurals name="pow_estimate_seconds">
<item quantity="one">%1$d sekunda</item>
<item quantity="few">%1$d sekundy</item>
<item quantity="many">%1$d sekundy</item>
<item quantity="other">%1$d sekund</item>
</plurals>
<plurals name="pow_estimate_minutes">
<item quantity="one">%1$d minuta</item>
<item quantity="few">%1$d minuty</item>
<item quantity="many">%1$d minuty</item>
<item quantity="other">%1$d minut</item>
</plurals>
<plurals name="pow_estimate_hours">
<item quantity="one">%1$d hodina</item>
<item quantity="few">%1$d hodiny</item>
<item quantity="many">%1$d hodiny</item>
<item quantity="other">%1$d hodin</item>
</plurals>
<plurals name="pow_estimate_days">
<item quantity="one">%1$d den</item>
<item quantity="few">%1$d dny</item>
<item quantity="many">%1$d dne</item>
<item quantity="other">%1$d dní</item>
</plurals>
<string name="pow_time_left">≈ %1$s zbývá</string>
<string name="pow_time_left_soon">každou chvíli</string>
<string name="pow_publish_failed">Váš %1$s dokončil těžbu, ale nepodařilo se jej publikovat: %2$s</string>
<string name="pow_publish_failed_retry">Váš %1$s dokončil těžbu, ale nepodařilo se jej publikovat. Bude to zkuseno znovu při příštím spuštění aplikace.</string>
<string name="pow_kind_chat_message">Chatová zpráva</string>
<string name="pow_kind_report">Nahlášení</string>
<string name="ai_writing_use_this">Použít toto</string>
<string name="ai_writing_dismiss">Zavřít</string>
<string name="ai_tone_correct">Opravit</string>
@@ -3121,6 +3698,7 @@
<string name="marmot_create_group_footer">Bude vytvořena nová MLS skupina. Členy můžete přidat poté.</string>
<string name="marmot_group_default_name">Skupina Marmot</string>
<string name="marmot_group_fallback_name">Skupina %1$s…</string>
<string name="marmot_user_fallback_name">%1$s…</string>
<string name="marmot_tab_known">Známé</string>
<string name="marmot_tab_known_count">Známé (%1$d)</string>
<string name="marmot_tab_new_requests">Nové žádosti</string>
@@ -3185,6 +3763,7 @@
<string name="marmot_revoke_admin_confirm">Odebrat administrátorská práva \"%1$s\"? Zůstane členem skupiny.</string>
<string name="marmot_admin_revoked">Administrátorská práva odebrána</string>
<string name="marmot_failed_to_revoke_admin">Nepodařilo se odebrat administrátorská práva: %1$s</string>
<string name="marmot_relays_header">Relaye</string>
<string name="marmot_relay_no_events">zatím žádné eventy</string>
<string name="marmot_relay_last_event">poslední event%1$s</string>
<string name="marmot_not_a_member">Nejste členem této skupiny</string>
@@ -586,6 +586,10 @@
<string name="app_definition_by">von</string>
<string name="app_definition_available_on">Verfügbar auf</string>
<string name="app_definition_categories">Kategorien</string>
<string name="app_definition_related">Verwandt</string>
<string name="app_definition_implements">Implementiert</string>
<string name="app_definition_supported_nips">Unterstützte NIPs</string>
<string name="app_definition_via">über %1$s</string>
<string name="platform_web">Web</string>
<string name="platform_android">Android</string>
<string name="platform_ios">iOS</string>
@@ -628,6 +632,7 @@
<string name="exercise_meditation">Meditation</string>
<string name="exercise_diet">Diät</string>
<string name="exercise_fasting">Fasten</string>
<string name="exercise_circuit">Zirkel</string>
<string name="software_apps">Apps</string>
<string name="route_software_apps">Apps</string>
<string name="nsite_none_found">Noch keine nSites gefunden.</string>
@@ -640,6 +645,9 @@
<string name="browser_go">Öffnen</string>
<string name="browser_clear">Löschen</string>
<string name="browser_favorites">Favoriten</string>
<string name="browser_suggested">Web-Apps entdecken</string>
<string name="browser_discover_nsites">Sites von Personen, denen du folgst</string>
<string name="browser_discover_napplets">Apps von Personen, denen du folgst</string>
<string name="browser_recent_options">Optionen</string>
<string name="browser_recent_remove">Aus Verlauf entfernen</string>
<string name="favorite_apps">Lieblings-Apps</string>
@@ -665,6 +673,7 @@
<string name="napplet_permissions_forget">Dieses nApplet vergessen</string>
<string name="napplet_permissions_blocked">Blockiert</string>
<string name="napplet_permissions_revoke">Widerrufen</string>
<string name="napplet_permissions_ask_each_time">Mich jedes Mal fragen</string>
<string name="napplet_none_found">Noch keine nApplets gefunden.</string>
<!-- Napplet sandbox chrome (host top bar + live action notices) -->
<!-- Napplet capability names -->
@@ -711,14 +720,106 @@
<item quantity="other">Dieses nApplet möchte eine Lightning-Rechnung über %1$d sats bezahlen.</item>
</plurals>
<!-- Signer permissions: first-connect dialog -->
<string name="napplet_connect_title">Mit Nostr verbinden</string>
<string name="napplet_connect_subtitle">möchte sich mit deinem Nostr-Konto verbinden</string>
<string name="napplet_connect_how_handle">Wie sollen die Anfragen dieser App behandelt werden?</string>
<string name="napplet_connect_button">Verbinden</string>
<string name="napplet_connect_block">%1$s blockieren und ignorieren</string>
<!-- Signer trust levels -->
<string name="napplet_policy_full_trust">Ich vertraue ihr voll</string>
<string name="napplet_policy_full_trust_desc">Alle Anfragen automatisch signieren (außer Zahlungen)</string>
<string name="napplet_policy_reasonable">Bleiben wir vernünftig</string>
<string name="napplet_policy_reasonable_desc">Die häufigsten Anfragen automatisch genehmigen</string>
<string name="napplet_policy_paranoid">Ich bin etwas paranoid</string>
<string name="napplet_policy_paranoid_desc">Nichts ohne Nachfrage signieren!</string>
<!-- Signer per-op consent dialog -->
<string name="napplet_consent_wants_to">möchte %1$s</string>
<string name="napplet_consent_show_event">Ereignis anzeigen</string>
<string name="napplet_consent_hide_event">Ereignis ausblenden</string>
<string name="napplet_consent_more_options">Mehr Optionen</string>
<string name="napplet_consent_fewer_options">Weniger Optionen</string>
<string name="napplet_signer_allow_once">Einmal erlauben</string>
<string name="napplet_signer_allow_session">Für diese Sitzung erlauben</string>
<string name="napplet_signer_allow_24h">Für 24 Stunden erlauben</string>
<string name="napplet_signer_allow_30d">Für 30 Tage erlauben</string>
<string name="napplet_signer_allow_op">Nicht mehr fragen für %1$s</string>
<string name="napplet_signer_allow_all">Bei keiner Nostr-Anfrage mehr fragen</string>
<string name="napplet_signer_deny_once">Verweigern</string>
<string name="napplet_signer_deny_op">%1$s immer verweigern</string>
<string name="napplet_signer_last_used">Zuletzt verwendet</string>
<string name="napplet_signer_expires">Läuft ab</string>
<!-- Signer op labels -->
<string name="napplet_op_sign_kind">Ereignis vom Typ %1$d signieren</string>
<string name="napplet_op_sign_kind_named">für %1$s signieren (Typ: %2$d)</string>
<string name="napplet_op_encrypt">eine Nachricht verschlüsseln</string>
<!-- Decrypt: the message is already decrypted by Amethyst; the permission is to expose it to the app -->
<string name="napplet_op_decrypt">deine privaten Nachrichten lesen</string>
<!-- Permissions management screen -->
<string name="napplet_permissions_title">Verbundene Apps</string>
<string name="napplet_permissions_revoke_all">Alle Berechtigungen widerrufen</string>
<string name="napplet_permissions_overrides">Vorgangs-Ausnahmen</string>
<string name="napplet_signer_permissions_empty">Bisher haben sich keine Apps verbunden.</string>
<string name="napplet_signer_permissions_revoke_all">Alle Berechtigungen widerrufen</string>
<string name="napplet_decision_allow">Erlauben</string>
<string name="napplet_decision_ask">Fragen</string>
<string name="napplet_decision_deny">Verweigern</string>
<string name="napplet_connected_apps_search_keywords">apps berechtigungen signierer napplet nsite webapp vertrauen verbunden</string>
<string name="napplet_connected_app_trust_level">Signierungs-Vertrauensstufe</string>
<string name="napplet_connected_app_capabilities">Berechtigungen</string>
<string name="napplet_connected_app_forget">Diese App vergessen</string>
<string name="napplet_connected_app_op_overrides">Signierungs-Ausnahmen</string>
<string name="napplet_connected_app_empty">Bisher haben sich keine Apps verbunden.\n\nWenn sich eine Web-App mit deinem Nostr-Schlüssel verbindet, erscheint sie hier.</string>
<!-- Relay Authentication (NIP-42) settings -->
<string name="relay_auth_settings_title">Relay-Authentifizierung</string>
<string name="relay_auth_search_keywords">auth authentifizierung relay signieren verifizieren nip-42 identität</string>
<string name="relay_auth_global_policy">Wann authentifiziert wird</string>
<string name="relay_auth_custom_section">Wo du dich anmelden willst</string>
<string name="relay_auth_policy_always">Immer authentifizieren</string>
<string name="relay_auth_policy_always_desc">Auth-Challenges für jedes Relay signieren, das sie anfordert</string>
<string name="relay_auth_policy_never">Nie authentifizieren</string>
<string name="relay_auth_policy_never_desc">Auth-Challenges von allen Relays ignorieren</string>
<string name="relay_auth_policy_custom">Benutzerdefiniert</string>
<string name="relay_auth_policy_custom_desc">Wähle genau, bei welchen Relays du dich anmeldest. Bei allem, was du unten nicht erlaubt hast, wirst du gefragt.</string>
<string name="relay_auth_toggle_my_relays">Meine Relays und Räume</string>
<string name="relay_auth_toggle_my_relays_desc">Bei deinen eigenen Relays und bei öffentlichen Chats, Communitys und Livestreams anmelden, denen du beigetreten bist oder die du favorisiert hast.</string>
<string name="relay_auth_toggle_read_follows">Beiträge von Personen lesen, denen ich folge</string>
<string name="relay_auth_toggle_read_follows_desc">Bei den Relays einer gefolgten Person anmelden, um deren Beiträge herunterzuladen.</string>
<string name="relay_auth_toggle_message_follows">Personen, denen ich folge, Nachrichten senden</string>
<string name="relay_auth_toggle_message_follows_desc">Bei den Relays einer gefolgten Person anmelden, um DMs, Antworten und Benachrichtigungen zu senden.</string>
<string name="relay_auth_toggle_message_strangers">Jedem Nachrichten senden</string>
<string name="relay_auth_toggle_message_strangers_desc">Bei den Relays von Fremden anmelden, um DMs, Antworten und Benachrichtigungen zu senden. Standardmäßig aus; stattdessen wirst du jedes Mal gefragt.</string>
<string name="relay_auth_prompt_title">Diesem Relay bestätigen, dass du es bist?</string>
<string name="relay_auth_prompt_message">Dieses Relay möchte zuerst bestätigen, dass du es wirklich bist. Sein Betreiber sieht, welches Konto du bist.</string>
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">Deine Nachricht an %1$s senden?</string>
<string name="relay_auth_title_notify">%1$s benachrichtigen?</string>
<string name="relay_auth_title_read">Beiträge von %1$s laden?</string>
<string name="relay_auth_title_post_venue">In %1$s posten?</string>
<string name="relay_auth_title_read_venue">%1$s öffnen?</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">Wenn nicht, wird deine Nachricht an %1$s nicht zugestellt.</string>
<string name="relay_auth_consequence_notify">Wenn nicht, wird %1$s nicht darüber benachrichtigt.</string>
<string name="relay_auth_consequence_read">Wenn nicht, siehst du hier keine Beiträge von %1$s.</string>
<string name="relay_auth_consequence_post_venue">Wenn nicht, wird deine Nachricht an %1$s nicht gepostet.</string>
<string name="relay_auth_consequence_read_venue">Wenn nicht, siehst du %1$s hier nicht.</string>
<string name="relay_auth_name_and_others">%1$s und andere</string>
<string name="relay_auth_reason_send_dm">Deine private Nachricht senden an:</string>
<string name="relay_auth_reason_notify_inbox">Benachrichtigen:</string>
<string name="relay_auth_reason_read_outbox">Beiträge herunterladen von:</string>
<string name="relay_auth_reason_post_venue">In diesem Raum posten</string>
<string name="relay_auth_reason_read_venue">Diesen Raum öffnen</string>
<string name="relay_auth_reason_other">Dieses Relay verwenden</string>
<string name="relay_auth_reason_my_own_relay">Mit deinem eigenen Relay verbinden</string>
<string name="relay_auth_allow_once">Einmal erlauben</string>
<string name="relay_auth_always_allow">Dieses Relay immer erlauben</string>
<string name="relay_auth_always_deliver">Meine Nachrichten immer zustellen</string>
<string name="relay_auth_block">Dieses Relay blockieren</string>
<string name="relay_auth_per_relay_overrides">Relay-spezifische Ausnahmen</string>
<string name="relay_auth_forget">Vergessen</string>
<string name="relay_auth_last_used">Zuletzt verwendet vor %1$s</string>
<string name="relay_auth_no_overrides">Hier ist noch nichts — deine globale Richtlinie gilt für jedes Relay.</string>
<string name="relay_auth_decision_allow">Erlauben</string>
<string name="relay_auth_decision_deny">Verweigern</string>
<string name="nip82_repository_label">Quelle: %1$s</string>
<string name="nip82_version_label">v%1$s</string>
<string name="nip82_download">Herunterladen</string>
@@ -883,6 +984,103 @@
<string name="route_podcasts">Podcasts</string>
<string name="podcast_view_episodes">Folgen ansehen</string>
<string name="podcast_no_episodes">Noch keine Folgen gefunden</string>
<string name="podcast_trailer_season">Staffel %1$d</string>
<string name="podcast_explicit">Anstößig</string>
<string name="podcast_completed">Abgeschlossen</string>
<string name="podcast_support_show">Die Show unterstützen</string>
<string name="podcast_by_author">von %1$s</string>
<string name="podcast_season">Staffel %1$d</string>
<string name="podcast_transcript">Transkript</string>
<string name="podcast_chapters">Kapitel</string>
<string name="podcast_value_zap_split_hint">Zaps hierauf werden aufgeteilt zwischen:</string>
<string name="podcast_hosts_and_guests">Hosts &amp; Gäste</string>
<string name="podcast_play_soundbite">Highlight abspielen</string>
<string name="podcast_top_supporters">Top-Unterstützer</string>
<plurals name="podcast_chapters_count">
<item quantity="one">%1$d Kapitel</item>
<item quantity="other">%1$d Kapitel</item>
</plurals>
<string name="podcast_role_cohost">Co-Host</string>
<string name="podcast_role_editor">Redakteur</string>
<string name="podcast_author_verified">Verifizierter Autor</string>
<string name="podcast_value_error_title">Value-for-Value-Fehler</string>
<string name="podcast_value_no_recipients">Dieser Podcast hat keine zahlbaren Value-Empfänger.</string>
<string name="podcast_value_keysend_requires_nwc">Verbinde eine Nostr-Wallet-Connect-Wallet, um an Keysend-(Node-)Empfänger zu senden.</string>
<string name="podcast_value_stream">Sats streamen</string>
<string name="podcast_value_stream_rate">%1$d Sats/Min</string>
<string name="podcast_value_stream_hint">Sendet automatisch Value, während du zuhörst.</string>
<string name="podcast_value_streamed_total">%1$d Sats in dieser Sitzung gestreamt</string>
<string name="podcast_value_stream_requires_wallet">Verbinde eine Nostr-Wallet-Connect- oder Debit-Wallet, um Sats beim Zuhören zu streamen.</string>
<string name="podcast_new_episode">Neue Episode</string>
<string name="podcast_edit_episode">Episode bearbeiten</string>
<string name="podcast_publishing_banner">Wird veröffentlicht…</string>
<string name="podcast_cover_upload_cta">Cover hinzufügen</string>
<string name="podcast_cover_upload_hint">Quadratisches Bild, das für die Episode angezeigt wird</string>
<string name="podcast_episode_title_label">Titel</string>
<string name="podcast_episode_title_placeholder">Episodentitel</string>
<string name="podcast_episode_summary_label">Zusammenfassung</string>
<string name="podcast_episode_duration_label">Dauer (Sekunden)</string>
<string name="podcast_episode_more_details">Weitere Details</string>
<string name="podcast_episode_season_label">Staffel</string>
<string name="podcast_episode_video_label">Video-URL</string>
<string name="podcast_episode_transcript_label">Transkript-URL</string>
<string name="podcast_episode_chapters_label">Kapitel-URL</string>
<string name="podcast_episode_topics_label">Themen</string>
<string name="podcast_episode_topics_placeholder">durch, Komma, getrennte, Tags</string>
<string name="podcast_episode_audio_url_label">Audio-URL</string>
<string name="podcast_episode_audio_picked">Audiodatei bereit zum Hochladen</string>
<string name="podcast_episode_audio_upload_cta">Audiodatei hinzufügen</string>
<string name="podcast_episode_audio_upload_hint">MP3, M4A oder anderes Audio</string>
<string name="podcast_episode_delete">Episode löschen</string>
<string name="podcast_episode_delete_confirm">Diese Episode löschen? Das kann nicht rückgängig gemacht werden.</string>
<string name="podcast_edit_show">Dein Podcast</string>
<string name="podcast_show_cover_cta">Cover hinzufügen</string>
<string name="podcast_show_cover_hint">Quadratisches Cover für deine Show</string>
<string name="podcast_show_title_label">Show-Titel</string>
<string name="podcast_show_title_placeholder">Mein Podcast</string>
<string name="podcast_show_description_label">Beschreibung</string>
<string name="podcast_show_author_label">Autor</string>
<string name="podcast_show_email_label">Kontakt-E-Mail</string>
<string name="podcast_show_categories_label">Kategorien</string>
<string name="podcast_show_categories_placeholder">Technik, Nachrichten</string>
<string name="podcast_show_funding_label">Finanzierungslinks</string>
<string name="podcast_show_language_label">Sprache</string>
<string name="podcast_show_language_placeholder">de</string>
<string name="podcast_show_type_label">Show-Typ</string>
<string name="podcast_show_type_episodic">Episodisch</string>
<string name="podcast_show_type_serial">Serie</string>
<string name="podcast_show_explicit">Anstößige Inhalte</string>
<string name="podcast_show_complete">Show abgeschlossen (keine weiteren Episoden)</string>
<string name="podcast_show_locked">Gesperrt (Premium)</string>
<string name="podcast_new_trailer">Neuer Trailer</string>
<string name="podcast_trailer_upload_cta">Trailer-Clip hinzufügen</string>
<string name="podcast_trailer_upload_hint">Kurze Audio- oder Videovorschau</string>
<string name="podcast_trailer_title_placeholder">Trailer-Titel</string>
<string name="podcast_trailer_url_label">Medien-URL</string>
<string name="podcast_your_podcast">Dein Podcast</string>
<string name="podcast_untitled">Ohne Titel</string>
<string name="podcast_no_episodes_yet">Noch keine Episoden. Tippe auf Neue Episode, um deine erste zu veröffentlichen.</string>
<string name="podcast_create_your_show">Erstelle deinen Podcast</string>
<string name="podcast_tap_to_edit_show">Tippen, um Show-Details zu bearbeiten</string>
<string name="podcast_create_show_hint">Lege Titel, Cover und Details deiner Show fest</string>
<plurals name="podcast_trailer_count">
<item quantity="one">%1$d Trailer</item>
<item quantity="other">%1$d Trailer</item>
</plurals>
<string name="podcast_value_editor_hint">Füge Empfänger hinzu, um eingehende Sats nach Gewichtung aufzuteilen. Hörer boosten oder streamen Value an diese Ziele.</string>
<string name="podcast_value_add_recipient">Empfänger hinzufügen</string>
<string name="podcast_value_add_address">Adresse manuell hinzufügen</string>
<string name="podcast_value_search_user">Nostr-Nutzer hinzufügen</string>
<string name="podcast_value_search_user_hint">Nach Name oder @Handle suchen</string>
<string name="podcast_value_user_no_lnaddress">Dieser Nutzer hat keine Lightning-Adresse</string>
<string name="podcast_value_remove_recipient">Empfänger entfernen</string>
<string name="podcast_value_type_lnaddress">Lightning-Adresse</string>
<string name="podcast_value_type_node">Node (Keysend)</string>
<string name="podcast_value_lnaddress">Lightning-Adresse</string>
<string name="podcast_value_node_pubkey">Node-Pubkey</string>
<string name="podcast_value_node_pubkey_hint">02abc… (33-Byte-Hex)</string>
<string name="podcast_value_weight">Gewichtung</string>
<string name="podcast_value_fee">Gebühr</string>
<plurals name="podcast_episode_count">
<item quantity="one">%1$d Folge</item>
<item quantity="other">%1$d Folgen</item>
@@ -911,6 +1109,9 @@
</plurals>
<string name="private_bookmarks">Private Lesezeichen</string>
<string name="public_bookmarks">Öffentliche Lesezeichen</string>
<string name="repository_bookmarks">Repositorys</string>
<string name="repository_bookmarks_explainer">Deine gespeicherten Git-Repositorys</string>
<string name="podcast_bookmarks_explainer">Deine gespeicherten Podcasts und Episoden</string>
<string name="add_to_private_bookmarks">Zu den privaten Lesezeichen hinzufügen</string>
<string name="add_to_public_bookmarks">Zu den öffentlichen Lesezeichen hinzufügen</string>
<string name="remove_from_private_bookmarks">Aus den privaten Lesezeichen entfernen</string>
@@ -1456,6 +1657,21 @@
<string name="wallet_connect">Wallet Verbindung</string>
<string name="language">Sprache</string>
<string name="theme">Design</string>
<string name="accent_color">Akzentfarbe</string>
<string name="accent_color_description">Hauptfarbe für Schaltflächen und Links</string>
<string name="accent_color_purple">Lila</string>
<string name="accent_color_blue">Blau</string>
<string name="accent_color_green">Grün</string>
<string name="accent_color_red">Rot</string>
<string name="font_family">Schriftart</string>
<string name="font_family_description">Schrift, die in der gesamten App verwendet wird</string>
<string name="font_family_system">Systemstandard</string>
<string name="font_family_sans_serif">Serifenlos</string>
<string name="font_size">Schriftgröße</string>
<string name="font_size_description">Skaliert die Textgröße in der gesamten App</string>
<string name="font_size_small">Klein</string>
<string name="font_size_large">Groß</string>
<string name="font_size_huge">Riesig</string>
<string name="automatically_load_images_gifs">Bilder/GIFs automatisch laden</string>
<string name="automatically_play_videos">Videos automatisch abspielen</string>
<string name="autoplay_videos">Videos automatisch abspielen</string>
@@ -1528,6 +1744,104 @@
<string name="messages_create_public_chat">Öffentlich</string>
<string name="messages_create_group">Gruppe</string>
<string name="messages_create_public_private_chat_description">Neue öffentliche oder private Gruppe</string>
<string name="relay_groups_title">Relay-Gruppen</string>
<string name="relay_group_view_grouped">Nach Relay</string>
<string name="relay_group_view_inline_desc">Zeigt jede Gruppe als eigene Unterhaltung, gemischt mit deinen Chats.</string>
<string name="relay_group_view_grouped_desc">Fasst die Gruppen jedes Relays in einer einzigen Zeile zusammen, platziert bei seiner neuesten Nachricht.</string>
<string name="relay_group_view_mode_title">NIP-29-Gruppenanzeige</string>
<string name="relay_group_server_label">Relay-Gruppen</string>
<string name="relay_groups_button">Gruppen</string>
<string name="messages_settings">Nachrichten</string>
<string name="relay_group_create_title">Eine Gruppe erstellen</string>
<string name="relay_group_relay_no_nip29">Dieses Relay wirbt nicht mit Unterstützung für NIP-29-Relay-Gruppen. Eine hier erstellte Gruppe funktioniert nicht — ihr Name, ihre Mitglieder und Nachrichten werden nicht vom Relay verwaltet. Wähle ein Relay, das relaybasierte Gruppen unterstützt.</string>
<string name="relay_group_create_name">Gruppenname</string>
<string name="relay_group_create_topic">Thema (optional)</string>
<string name="relay_group_create_private">Privat (nur Mitglieder lesen)</string>
<string name="relay_group_create_invite_only">Nur mit Einladung</string>
<string name="relay_group_create_confirm">Erstellen</string>
<string name="relay_group_invite_title">Personen einladen</string>
<string name="relay_group_invite_description">Teile diesen Code, damit Personen dieser Gruppe beitreten können.</string>
<string name="relay_group_invite_generating">Einladung wird erstellt…</string>
<string name="relay_group_invite_copied">Einladungscode kopiert</string>
<string name="relay_group_invite_code_label">Einladungscode (für diese Gruppe nur mit Einladung):</string>
<string name="relay_group_join_title">Gruppe beitreten</string>
<string name="relay_group_join_code_label">Einladungscode</string>
<string name="relay_group_join_code_hint">Diese Gruppe ist nur mit Einladung. Gib den Code ein, den du erhalten hast.</string>
<string name="relay_group_join_confirm">Beitreten</string>
<string name="relay_group_pending">Angefragt</string>
<string name="relay_group_role_member">Mitglied</string>
<string name="relay_group_members_title">Mitglieder</string>
<string name="relay_group_make_admin">Zum Admin machen</string>
<string name="relay_group_make_moderator">Zum Moderator machen</string>
<string name="relay_group_demote_member">Rolle entfernen</string>
<string name="relay_group_remove_user">Aus Gruppe entfernen</string>
<string name="relay_group_remove_user_confirm">%1$s aus dieser Gruppe entfernen? Sie verlieren den Zugriff, bis sie erneut hinzugefügt oder eingeladen werden.</string>
<string name="relay_group_edit_title">Gruppe bearbeiten</string>
<string name="relay_group_edit_name">Gruppenname</string>
<string name="relay_group_edit_topic">Thema (optional)</string>
<string name="relay_group_edit_private">Privat (nur Mitglieder lesen)</string>
<string name="relay_group_edit_invite_only">Nur mit Einladung</string>
<string name="relay_group_edit_confirm">Speichern</string>
<string name="relay_group_menu_members">Mitglieder</string>
<string name="relay_group_menu_edit">Gruppe bearbeiten</string>
<string name="relay_group_open">Gruppe öffnen</string>
<string name="relay_group_channels_empty">Noch keine Gruppen auf diesem Relay.</string>
<string name="relay_group_invite_preparing">Einladung wird vorbereitet…</string>
<string name="relay_group_badge_private">Privat</string>
<string name="relay_group_badge_invite_only">Nur mit Einladung</string>
<string name="relay_group_browse_invalid_url">Gib eine gültige Relay-URL ein (wss://…).</string>
<string name="relay_group_field_about">Beschreibung</string>
<string name="relay_group_field_picture">Gruppenbild</string>
<string name="relay_group_add_photo">Foto hinzufügen</string>
<string name="relay_group_change_photo">Foto ändern</string>
<string name="relay_group_section_discovery">Entdeckung</string>
<string name="relay_group_section_discovery_desc">Hilf Personen, diese Gruppe zu finden. Themen und ein Ort lassen sie unter den passenden Entdeckungsfiltern erscheinen (falls das Host-Relay sie unterstützt).</string>
<string name="relay_group_field_topics">Themen</string>
<string name="relay_group_field_topics_hint">bitcoin, nostr, kunst</string>
<string name="relay_group_field_geohash">Ort (Geohash)</string>
<string name="relay_group_section_permissions">Berechtigungen</string>
<string name="relay_group_flag_private">Privat</string>
<string name="relay_group_flag_private_desc">Nur Mitglieder können Nachrichten lesen.</string>
<string name="relay_group_flag_invite_only">Nur mit Einladung</string>
<string name="relay_group_flag_invite_only_desc">Personen müssen eingeladen oder genehmigt werden, um beizutreten.</string>
<string name="relay_group_flag_restricted">Nur Mitglieder posten</string>
<string name="relay_group_flag_restricted_desc">Nur Mitglieder können Nachrichten posten.</string>
<string name="relay_group_flag_hidden">Nicht gelistet</string>
<string name="relay_group_flag_hidden_desc">Diese Gruppe aus dem öffentlichen Verzeichnis des Relays ausblenden.</string>
<string name="relay_group_discovery_empty">Es wird nach Gruppen über deine Relays gesucht…</string>
<string name="relay_group_discovery_empty_filtered">Noch keine Gruppen für diesen Filter gefunden.</string>
<string name="relay_group_favorite_relay">Dieses Relay favorisieren</string>
<string name="relay_group_threads_empty">Noch keine Threads. Starte einen mit der +-Schaltfläche.</string>
<string name="relay_group_thread_new">Neuer Thread</string>
<string name="relay_group_thread_untitled">Ohne Titel</string>
<string name="relay_group_thread_title_label">Titel</string>
<string name="relay_group_thread_body_label">Schreibe etwas…</string>
<string name="relay_group_thread_post">Posten</string>
<string name="relay_group_browse_title">Gruppen finden</string>
<string name="relay_group_browse_description">Durchsuche die auf einem Relay gehosteten Gruppen. Füge eine Relay-Adresse ein oder wähle unten eine aus.</string>
<string name="relay_group_browse_relay_label">Relay-Adresse</string>
<string name="relay_group_browse_go">Durchsuchen</string>
<string name="relay_group_browse_your_relays">Relays, auf denen du bist</string>
<string name="relay_group_browse_popular">Beliebte Relays</string>
<string name="relay_group_no_messages_yet">Noch keine Nachrichten</string>
<string name="relay_group_join_to_post">Tritt dieser Gruppe bei, um Nachrichten zu senden.</string>
<string name="relay_group_invite_only_to_post">Diese Gruppe ist nur mit Einladung — du brauchst eine Einladung, um zu posten.</string>
<plurals name="relay_group_member_count">
<item quantity="one">%1$d Mitglied</item>
<item quantity="other">%1$d Mitglieder</item>
</plurals>
<plurals name="relay_group_message_count">
<item quantity="one">%1$d Nachricht</item>
<item quantity="other">%1$d Nachrichten</item>
</plurals>
<plurals name="relay_group_message_count_capped">
<item quantity="one">%1$d+ Nachricht</item>
<item quantity="other">%1$d+ Nachrichten</item>
</plurals>
<plurals name="relay_group_follows_participating">
<item quantity="one">%1$d Person, der du folgst</item>
<item quantity="other">%1$d Personen, denen du folgst</item>
</plurals>
<string name="messages_new_message">Privat</string>
<string name="messages_new_message_to">An</string>
<string name="messages_new_message_subject">Betreff</string>
@@ -1767,12 +2081,41 @@
<string name="cashu_no_wallet_description">Erstelle eine Cashu-Wallet, um Ecash-Tokens zu halten und Nutzaps zu empfangen.</string>
<string name="cashu_discovering">Suche nach deiner Wallet…</string>
<string name="cashu_discovering_description">NIP-60-Wallets werden über Clients hinweg synchronisiert. Wenn du in einer anderen App eine mit diesem Nostr-Schlüssel erstellt hast, sollte sie in wenigen Sekunden erscheinen.</string>
<string name="cashu_wizard_title">Richte deine Wallet ein</string>
<string name="cashu_wizard_searching">Deine Wallet wird gesucht…</string>
<string name="cashu_wizard_searching_description">Wir durchsuchen jedes Relay nach einer Cashu-Wallet, die unter deinem Nostr-Schlüssel veröffentlicht wurde.</string>
<string name="cashu_wizard_searching_progress">Relays werden durchsucht… %1$d / %2$d</string>
<string name="cashu_wizard_analyzing">Die gefundenen Wallets werden überprüft…</string>
<string name="cashu_wizard_none_title">Keine Wallet gefunden</string>
<string name="cashu_wizard_none_description">Wir konnten auf keinem Relay eine bestehende Cashu-Wallet unter deinem Nostr-Schlüssel finden. Erstelle eine neue, um zu beginnen.</string>
<string name="cashu_wizard_create">Neue Wallet erstellen</string>
<string name="cashu_wizard_single_title">Wir haben deine Wallet gefunden</string>
<string name="cashu_wizard_single_description">Diese Cashu-Wallet ist im Nostr-Netzwerk unter deinem Schlüssel veröffentlicht. Nutze sie auf diesem Gerät — wir senden sie erneut an deine Relays, damit sie beim nächsten Mal leicht zu finden ist.</string>
<string name="cashu_wizard_use_wallet">Diese Wallet verwenden</string>
<string name="cashu_wizard_multiple_title">Wir haben mehrere Wallets gefunden</string>
<string name="cashu_wizard_multiple_description">Du hast mehr als eine Cashu-Wallet im Netzwerk — höchstwahrscheinlich von verschiedenen Apps erstellt. Die neueste wird zu deiner Haupt-Wallet; übertrage alle Guthaben aus den älteren in sie.</string>
<string name="cashu_wizard_main_label">Neueste — deine Haupt-Wallet</string>
<string name="cashu_wizard_old_label">Ältere Wallet</string>
<string name="cashu_wizard_set_main">Als Haupt-Wallet festlegen</string>
<string name="cashu_wizard_recover_funds">Guthaben in Haupt-Wallet übertragen</string>
<string name="cashu_wizard_recoverable">%1$s Sats wiederherstellbar</string>
<string name="cashu_wizard_recovered">%1$s Sats wiederhergestellt</string>
<string name="cashu_wizard_no_funds">Keine wiederherstellbaren Guthaben</string>
<string name="cashu_wizard_invalid">Diese Wallet konnte nicht gelesen werden</string>
<string name="cashu_wizard_set_main_first">Lege zuerst deine Haupt-Wallet fest, übertrage dann die Guthaben aus den älteren.</string>
<string name="cashu_wizard_adopting">Deine Wallet wird eingerichtet…</string>
<string name="cashu_wizard_retry">Erneut suchen</string>
<string name="cashu_created_title">Wallet erstellt</string>
<string name="cashu_created_subtitle">Wähle nun ein paar Mints, die deine Sats verwahren.</string>
<string name="cashu_created_pick_mints">Mints auswählen</string>
<string name="cashu_balance">Guthaben</string>
<string name="cashu_mints">Mints</string>
<string name="cashu_mint_url">Mint-URL</string>
<string name="cashu_remove_mint">Mint entfernen</string>
<string name="cashu_add_mint">Mint hinzufügen</string>
<string name="cashu_history">Verlauf</string>
<string name="cashu_wallet_autosaves">Deine Wallet wird automatisch gespeichert, während du Mints hinzufügst oder entfernst. Ein Nutzap-Schlüssel wird für dich erstellt, sobald du das erste Mint hinzufügst.</string>
<string name="cashu_wallet_saving">Wird gespeichert…</string>
<string name="cashu_p2pk_section">Nutzap-Schlüssel (erweitert)</string>
<string name="cashu_p2pk_explainer">Ein separater privater Schlüssel, der nur zum Empfangen von NIP-61-Nutzaps dient. Nicht dein Nostr-Identitätsschlüssel.</string>
<string name="cashu_p2pk_autogen">Neuen Schlüssel erzeugen</string>
@@ -2106,6 +2449,7 @@
<string name="profile_ui_setting_app_recommendations">App-Empfehlungen</string>
<string name="profile_ui_setting_zap_received_feed">Erhaltene-Zaps-Feed</string>
<string name="profile_ui_setting_followers_feed">Follower-Feed</string>
<string name="profile_ui_setting_onchain_wallet">Bitcoin-(On-Chain-)Wallet</string>
<string name="reactions_settings">Reaktions-Einstellungen</string>
<string name="reactions_settings_description">Konfigurieren Sie, welche Reaktionsschaltflächen angezeigt werden, ihre Reihenfolge und ob Zähler angezeigt werden sollen.</string>
<string name="reactions_settings_enabled">Aktiviert</string>
@@ -2254,6 +2598,8 @@
<string name="forked_from">Geforkt von</string>
<string name="git_web_address">Internet:</string>
<string name="git_clone_address">Klonen:</string>
<string name="git_merge_base">Merge-Basis</string>
<string name="git_pr_update_description">Der Pull-Request wurde auf einen neuen Commit aktualisiert.</string>
<string name="git_status_open">Offen</string>
<string name="git_status_merged">Zusammengeführt</string>
<string name="git_status_closed">Geschlossen</string>
@@ -2261,8 +2607,18 @@
<string name="git_repo_tab_overview">Übersicht</string>
<string name="git_repo_tab_issues">Tickets</string>
<string name="git_repo_tab_patches">Patches und PRs</string>
<string name="git_repo_filter_open">Offen</string>
<string name="git_repo_filter_closed">Geschlossen &amp; erledigt</string>
<string name="git_repo_label_all">Alle</string>
<string name="git_repo_bookmark">Repository als Lesezeichen speichern</string>
<string name="git_repo_stat_files">Dateien</string>
<string name="git_repo_stat_updated">Aktualisiert</string>
<string name="git_repo_recent_activity">Letzte Aktivität</string>
<string name="git_repo_maintained_by">Betreut von</string>
<string name="git_repo_external_host_title">Extern gehostet</string>
<string name="git_repo_external_host_body">Dieses Repository kann nicht über http(s) geklont werden, daher ist die Code-Ansicht hier nicht verfügbar.</string>
<string name="git_repo_open_in_browser">Im Browser öffnen</string>
<string name="git_untitled">Ohne Titel</string>
<string name="git_repo_section_about">Über</string>
<string name="git_repo_section_links">Links</string>
<string name="git_repo_section_maintainers">Maintainer</string>
@@ -2270,18 +2626,55 @@
<string name="git_repo_personal_fork">Persönlicher Fork</string>
<string name="git_repo_tab_readme">Readme</string>
<string name="git_repo_tab_code">Code</string>
<string name="git_repo_code_loading">Repository wird geladen…</string>
<string name="git_repo_code_error">Das Repository konnte nicht von seiner Klon-URL geladen werden.</string>
<string name="git_repo_no_clone_url">Diese Repository-Ankündigung enthält keine http(s)-Klon-URL zum Durchsuchen.</string>
<string name="git_repo_readme_missing">Dieses Repository hat keine README-Datei.</string>
<string name="git_repo_file_load_error">Diese Datei konnte nicht geladen werden.</string>
<string name="git_repo_binary_file">Binärdatei (%1$s) — keine Vorschau verfügbar.</string>
<string name="git_repo_empty_folder">Dieser Ordner ist leer.</string>
<string name="git_repo_root">Root</string>
<string name="git_repo_retry">Erneut versuchen</string>
<string name="git_repo_default_branch">default</string>
<string name="git_repo_branches">Branches</string>
<string name="git_repo_search_files">Dateien durchsuchen…</string>
<string name="git_repo_no_search_results">Keine passenden Dateien.</string>
<string name="git_repo_commits">Commits</string>
<string name="git_repo_no_commits">Kein Commit-Verlauf verfügbar.</string>
<string name="git_repo_copy_file">Dateiinhalt kopieren</string>
<string name="git_repo_plain_text">Text</string>
<plurals name="git_repo_item_count">
<item quantity="one">%1$d Element</item>
<item quantity="other">%1$d Elemente</item>
</plurals>
<plurals name="git_diff_files_changed">
<item quantity="one">Datei geändert</item>
<item quantity="other">Dateien geändert</item>
</plurals>
<string name="git_diff_binary">Binärdatei wird nicht angezeigt.</string>
<string name="git_new_issue_button">Neu</string>
<string name="git_new_issue_title">Neues Issue</string>
<string name="git_new_issue_subject">Titel</string>
<string name="git_new_issue_body">Beschreibung</string>
<string name="git_new_issue_create">Erstellen</string>
<string name="git_new_issue_cancel">Abbrechen</string>
<string name="git_new_issue_labels_hint">Bug, Verbesserung…</string>
<string name="git_issue_close">Issue schließen</string>
<string name="git_issue_reopen">Wieder öffnen</string>
<string name="git_status_close">Schließen</string>
<string name="git_status_reopen">Wieder öffnen</string>
<string name="git_status_mark_merged">Als gemergt markieren</string>
<string name="git_pr_view_changes">Änderungen ansehen</string>
<string name="git_pr_loading_changes">Änderungen werden geladen…</string>
<string name="git_pr_no_changes">Keine Dateiänderungen gefunden.</string>
<string name="git_pr_changes_retry">Änderungen erneut laden</string>
<string name="git_pr_revised">Überarbeitet</string>
<string name="git_repo_settings_title">Repository bearbeiten</string>
<string name="git_repo_settings_name">Name</string>
<string name="git_repo_settings_description">Beschreibung</string>
<string name="git_repo_settings_clone_urls">Klon-URLs (eine pro Zeile)</string>
<string name="git_repo_settings_web_urls">Web-URLs (eine pro Zeile)</string>
<string name="git_repo_settings_topics">Themen (durch Komma getrennt)</string>
<string name="git_repo_settings_save">Speichern</string>
<string name="git_repositories">Git Repositories</string>
<string name="nsite_title">Statische Website: %1$s</string>
@@ -2856,6 +3249,7 @@
<string name="goal_progress">%1$s finanziert von %2$s Sats Ziel</string>
<string name="fundraiser_ends">Endet %1$s</string>
<string name="fundraiser_onchain_donation">On-Chain-Spende</string>
<string name="bird_detection_title">Vogelerkennung</string>
<plurals name="birdex_species_count">
<item quantity="one">Birdex · %1$d Art</item>
<item quantity="other">Birdex · %1$d Arten</item>
@@ -2865,6 +3259,9 @@
<item quantity="other">%1$s +%2$d weitere</item>
</plurals>
<!-- PS1 memory-card saves over nostr (kind 38192). "PS1" is the PlayStation 1, do not translate. -->
<string name="ps1_save_title">PS1-Memory-Card-Spielstand</string>
<string name="ps1_save_block">Block %1$d</string>
<string name="ps1_save_empty_slot">Leerer Slot</string>
<!-- Roadstr road event reports (kinds 1315/1316). "Roadstr" is a proper noun, do not translate. -->
<string name="road_event_police">Polizei</string>
<string name="road_event_speed_camera">Blitzer</string>
@@ -2993,6 +3390,85 @@
<string name="compose_settings">Editor-Einstellungen</string>
<string name="auto_create_drafts_setting_title">Entwürfe automatisch erstellen</string>
<string name="auto_create_drafts_setting_description">Speichert automatisch ein Entwurfsereignis, wenn du tippst oder den Editor mit ungesendetem Text verlässt, und sendet es an deine privaten ausgehenden Relays.</string>
<string name="compose_signature_setting_title">Signatur</string>
<string name="compose_signature_setting_description">Wird am Ende der Nachricht angefügt, wenn du einen neuen Beitrag, eine Antwort, ein Zitat oder einen Artikel öffnest. Leer lassen, um zu deaktivieren.</string>
<string name="compose_signature_setting_hint">Deine Signatur</string>
<string name="pow_settings_title">Arbeitsnachweis</string>
<string name="pow_difficulty_title">Schwierigkeit</string>
<string name="pow_difficulty_explainer">Schürft vor der Veröffentlichung einen NIP-13-Arbeitsnachweis in deine Beiträge, damit Relays und Leser sie gegen Spam gewichten können. Höhere Werte dauern exponentiell länger zum Schürfen. Beiträge werden nach dem Schürfen im Hintergrund veröffentlicht.</string>
<string name="pow_difficulty_off">Aus</string>
<string name="pow_custom_difficulty_title">Benutzerdefinierte Schwierigkeit</string>
<string name="pow_custom_difficulty_explainer">Feinabstimmung des Ziels in führenden Nullbits.</string>
<string name="pow_categories_title">Was geschürft wird</string>
<string name="pow_categories_explainer">Zeitkritische Ereignisse (Relay-Authentifizierung, Zap-Anfragen, Wallet- und Signierer-Nachrichten, Entwürfe, Listen) werden nie gemint.</string>
<string name="pow_category_short_notes">Kurze Notizen &amp; Antworten</string>
<string name="pow_category_short_notes_explainer">Die primäre öffentliche Spam-Fläche</string>
<string name="pow_category_comments">Kommentare</string>
<string name="pow_category_comments_explainer">Antworten auf Artikel, Dateien und andere Inhalte</string>
<string name="pow_category_reports">Meldungen</string>
<string name="pow_category_reports_explainer">Relays gewichten Meldungen nach ihren Kosten</string>
<string name="pow_category_long_form">Langform &amp; Highlights</string>
<string name="pow_category_long_form_explainer">Artikel und Highlights; selten, die Kosten sind vernachlässigbar</string>
<string name="pow_category_voice">Sprachnachrichten</string>
<string name="pow_category_voice_explainer">Öffentliche Sprachbeiträge und -antworten</string>
<string name="pow_category_reposts_explainer">Hohes Volumen bei aktiven Nutzern</string>
<string name="pow_category_reactions">Reaktionen</string>
<string name="pow_category_reactions_explainer">Häufigster Typ; jedes Like zu schürfen kostet Akku</string>
<string name="pow_category_public_chat">Öffentlicher &amp; Live-Chat</string>
<string name="pow_category_public_chat_explainer">Schürf-Verzögerungen stören den Gesprächsfluss</string>
<string name="pow_category_gift_wraps">Verpackungen privater Nachrichten</string>
<string name="pow_category_gift_wraps_explainer">Ermöglicht DM-Relays das Filtern von Posteingangs-Spam; nur die äußere Verpackung wird gemint, nie deine Nachricht</string>
<string name="pow_category_other_public">Andere öffentliche Inhalte</string>
<string name="pow_category_other_public_explainer">Umfragen, Live-Status, Kleinanzeigen und alles andere Öffentliche</string>
<string name="pow_mining_title">Arbeitsnachweis wird geschürft</string>
<plurals name="pow_mining_progress">
<item quantity="one">Arbeitsnachweis wird geschürft… (%1$d Beitrag in der Warteschlange)</item>
<item quantity="other">Arbeitsnachweis wird geschürft… (%1$d Beiträge in der Warteschlange)</item>
</plurals>
<plurals name="pow_mining_job">
<item quantity="one">%1$s • schürft bei %2$d Bit</item>
<item quantity="other">%1$s • schürft bei %2$d Bits</item>
</plurals>
<plurals name="pow_queued_job">
<item quantity="one">%1$s • wartet auf Schürfen bei %2$d Bit</item>
<item quantity="other">%1$s • wartet auf Schürfen bei %2$d Bits</item>
</plurals>
<plurals name="pow_option_default_on">
<item quantity="one">Standard (%1$d Bit)</item>
<item quantity="other">Standard (%1$d Bits)</item>
</plurals>
<string name="pow_option_default_off">Standard (aus)</string>
<string name="pow_option_off">Für diesen Beitrag aus</string>
<plurals name="pow_option_bits">
<item quantity="one">%1$d Bit</item>
<item quantity="other">%1$d Bits</item>
</plurals>
<string name="pow_notification_channel_name">Arbeitsnachweis-Schürfen</string>
<string name="pow_notification_channel_description">Zeigt Beiträge an, die noch ihren NIP-13-Arbeitsnachweis schürfen, damit sie fertig werden können, nachdem du die App verlässt.</string>
<string name="pow_notification_cancel_all">Abbrechen</string>
<string name="pow_difficulty_estimate">≈ %1$s pro Beitrag auf diesem Gerät</string>
<plurals name="pow_estimate_seconds">
<item quantity="one">%1$d Sekunde</item>
<item quantity="other">%1$d Sekunden</item>
</plurals>
<plurals name="pow_estimate_minutes">
<item quantity="one">%1$d Minute</item>
<item quantity="other">%1$d Minuten</item>
</plurals>
<plurals name="pow_estimate_hours">
<item quantity="one">%1$d Stunde</item>
<item quantity="other">%1$d Stunden</item>
</plurals>
<plurals name="pow_estimate_days">
<item quantity="one">%1$d Tag</item>
<item quantity="other">%1$d Tage</item>
</plurals>
<string name="pow_time_left">≈ %1$s verbleibend</string>
<string name="pow_time_left_soon">jeden Moment</string>
<string name="pow_publish_failed">Dein %1$s wurde fertig geschürft, konnte aber nicht veröffentlicht werden: %2$s</string>
<string name="pow_publish_failed_retry">Dein %1$s wurde fertig geschürft, konnte aber nicht veröffentlicht werden. Es wird beim nächsten Start der App erneut versucht.</string>
<string name="pow_kind_chat_message">Chat-Nachricht</string>
<string name="pow_kind_report">Meldung</string>
<string name="ai_writing_use_this">Verwenden</string>
<string name="ai_writing_dismiss">Schließen</string>
<string name="ai_tone_correct">Korrigieren</string>
+96 -23
View File
@@ -663,7 +663,7 @@
<string name="favorite_app_remove">पसंदीदा से हटाएँ</string>
<string name="favorite_app_open_window">अपनी विंडो में खोलें</string>
<string name="favorite_app_access_title">इस क्रमक के लिए क्या अभिगम्य है</string>
<string name="favorite_app_access_static">पृथक पर्यावरण में चलता है। आपके लेखा तक कोई विशेष अभिगमन अधिकार नहीं।</string>
<string name="favorite_app_access_static">पृथक्कृत पर्यावरण में चलता है। आपके लेखा तक कोई विशेष अभिगमन अधिकार नहीं।</string>
<string name="favorite_app_access_show">इसके लिए क्या अभिगम्य है</string>
<string name="favorite_app_network_tor">Tor पर लोड होता है।</string>
<string name="favorite_app_network_open">खुले वेब पर लोड होता है।</string>
@@ -791,7 +791,7 @@
<string name="relay_auth_policy_custom">अनुकूलित</string>
<string name="relay_auth_policy_custom_desc">स्पष्ट चयन करें किन पुनःप्रसारकों में प्रवेशांकन करना चाहिए। नीचे जिसको अनुमति नहीं दी गई उन सब के विषय में आप पूछे जाएँगे।</string>
<string name="relay_auth_toggle_my_relays">मेरे पुनःप्रसारक तथा आयोजन स्थल</string>
<string name="relay_auth_toggle_my_relays_desc">प्रवेशांकन करें आपके अपने पुनःप्रसारक तथा सार्वजनिक चर्चाएँ तथा समुदाय तथा सीधे प्रवाहों को जिनसे आप जुडे हैं अथवा प्रियचिह्नित किए हैं।</string>
<string name="relay_auth_toggle_my_relays_desc">प्रवेशांकन करें आपके अपने पुनःप्रसारक तथा सार्वजनिक चर्चाएँ तथा समुदाय तथा वर्तमानप्रवाहों को जिनसे आप जुडे हैं अथवा प्रियचिह्नित किए हैं।</string>
<string name="relay_auth_toggle_read_follows">मेरे द्वारा अनुचरित लोगों के पत्र पढें</string>
<string name="relay_auth_toggle_read_follows_desc">अनुचरित के पुनःप्रसारकों में प्रवेशांकन करें उनके पत्र प्राप्त करने के लिए।</string>
<string name="relay_auth_toggle_message_follows">मेरे द्वारा अनुचरित लोगों को सन्देश भेजें</string>
@@ -799,20 +799,23 @@
<string name="relay_auth_toggle_message_strangers">किसी को भी सन्देश भेजें</string>
<string name="relay_auth_toggle_message_strangers_desc">अज्ञात लोगों के पुनःप्रसारकों में प्रवेशांकन करें सीधेसन्देश तथा प्रत्युत्तर तथा सूचनाएँ भेजने के लिए। मूलविकल्पतः निष्क्रिय। प्रत्येक बार आप से पूछा जाएगा।</string>
<string name="relay_auth_prompt_title">क्या इस पुनःप्रसारक को पुष्टि करें कि यह आप हैं।</string>
<string name="relay_auth_prompt_message">यह पुनःप्रसारक पहले पुष्टि करना चाहता है कि यह वस्तुतः आप हैं। इसक परिचालक देखेगा आपका लेखा कौनसा है।</string>
<string name="relay_auth_prompt_message">यह पुनःप्रसारक पहले पुष्टि करना चाहता है कि यह वस्तुतः आप हैं। इसक परिचालक देखेगा आपका लेखा कौनसा है।</string>
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">क्या आपका सन्देश %1$s को भेजें।</string>
<string name="relay_auth_title_notify">क्या %1$s को सूचित करें।</string>
<string name="relay_auth_title_read">क्या %1$s से परिचय पत्र तथा गतिविधियों का आवहन करें।</string>
<string name="relay_auth_title_post_venue">क्या %1$s को पत्र भेजें।</string>
<string name="relay_auth_title_read_venue">क्या %1$s को खोलें।</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">यदि आप पुष्टि नहीं करते तो %1$s को आपका सन्देश नहीं भेजा जाएगा।</string>
<string name="relay_auth_consequence_notify">यदि आप नहीं स्वीकारते तो %1$s को इस विषय पर सूचित नहीं किया जाएगा।</string>
<string name="relay_auth_consequence_read">यदि नहीं स्वीकारते तो %1$s से परिचय पत्र अथवा गतिविधियाँ आपको यहाँ नहीं दिखेगा।</string>
<string name="relay_auth_consequence_post_venue">यदि आप स्वीकारते नहीं तो %1$s को आपका सन्देश प्रकाशित नहीं किया जाएगा।</string>
<string name="relay_auth_consequence_read_venue">यदि आप स्वीकारते नहीं तो आप यहाँ %1$s को नहीं देखेंगे।</string>
<string name="relay_auth_name_and_others">%1$s तथा अन्य</string>
<string name="relay_auth_reason_send_dm">आपका निजी सन्देश भेजें इनको :</string>
<string name="relay_auth_reason_notify_inbox">इनको सूचित करें :</string>
<string name="relay_auth_reason_read_outbox">परिचय जानकारी पत्र तथा गतिविधियों का अवरोहण करें यहाँ से :</string>
<string name="relay_auth_reason_post_venue">इस शाला को पत्र भेजें</string>
<string name="relay_auth_reason_read_venue">इस शाला को खोलें</string>
<string name="relay_auth_reason_other">इस पुनःप्रसारक का उपयोग करें</string>
@@ -842,7 +845,7 @@
<string name="shorts">लघु चलचित्र</string>
<string name="public_chats">सार्वजनिक चर्चा</string>
<string name="follow_packs">अनुचरण पोटलियाँ</string>
<string name="live_streams">सीधा प्रसारण</string>
<string name="live_streams">वर्तमानप्रवाह</string>
<string name="nests">ध्वनि शाला</string>
<string name="meeting_room_in_space">%1$s में</string>
<string name="meeting_room_in_space_unknown">एक निलय</string>
@@ -868,14 +871,14 @@
<string name="nest_leave_stage">मंच छोडें</string>
<string name="nest_mic_mute">ध्वनिग्राहक मौन</string>
<string name="nest_mic_unmute">ध्वनिग्राहक सक्रिय</string>
<string name="nest_broadcast_connecting">सीधा प्रसारण प्रारम्भ…</string>
<string name="nest_broadcast_connecting">वर्तमानप्रवाह प्रारम्भ…</string>
<string name="nest_broadcast_failed">प्रसारण असफल : %1$s</string>
<string name="nest_mute_failed">मौनकरण असफल : %1$s</string>
<string name="nest_open_settings">कोई अनुमति नहीं</string>
<string name="nest_notification_channel">निलय</string>
<string name="nest_notification_channel_description">ध्वनि चालू रखता है जब शाला खुला है।</string>
<string name="nest_notification_listening">निलय संयोजित</string>
<string name="nest_notification_broadcasting">निलय - सीधाप्रसार</string>
<string name="nest_notification_broadcasting">निलय - वर्तमान</string>
<string name="nest_notification_text">लौटने के लिए दबाएँ।</string>
<string name="nest_notification_stop">अवरोधन</string>
<string name="nest_join">निलय जुडें</string>
@@ -903,7 +906,7 @@
<item quantity="one">%1$d श्रोता</item>
<item quantity="other">%1$d श्रोतागण</item>
</plurals>
<string name="nest_live_chip">सीधाप्रसार</string>
<string name="nest_live_chip">वर्तमान</string>
<string name="nest_tab_chat">चर्चा</string>
<string name="nest_tab_audience">श्रोतागण</string>
<string name="nest_tab_hands">हाथ</string>
@@ -948,7 +951,7 @@
<string name="nest_unjoinable_body">इस शाला में ध्वनि सेवा अथवा गन्तव्य उपलब्ध नहीं। निमन्त्रक को इसके विवरणों का शोधन करना चाहिए श्रोतागण जुडने से पहले।</string>
<string name="nest_unjoinable_back">पीछे</string>
<string name="nest_create_fab">स्थान आरम्भण</string>
<string name="nests_section_live_now">सीधाप्रसार चालू</string>
<string name="nests_section_live_now">वर्तमानप्रवाह चालू</string>
<string name="nests_section_scheduled">समयनिर्धारित</string>
<string name="nests_section_recently_ended">निकटकाल समाप्त</string>
<string name="nests_ended_ago">समाप्त %1$s पूर्व</string>
@@ -1602,7 +1605,7 @@
<string name="content_size">विषयवस्तु आकार</string>
<string name="connectivity">संयोजकता</string>
<string name="access_control">अभिगमन नियन्त्रण</string>
<string name="minimum_pow">न्यूनतम श्रमप्रमाण</string>
<string name="minimum_pow">न्यूनतम श्रमप्रमाण कठिनाई</string>
<string name="auth_required">प्रमाणीकरण आवश्यक</string>
<string name="payment_required">भुगतान आवश्यक</string>
<string name="max_message_length">अधिकतम संदेश लम्बाई</string>
@@ -1616,13 +1619,13 @@
<string name="cashu_copy_token">Token कॉपी करें</string>
<string name="quick_actions_open_in_another_app">अन्य क्रमक में खोलें</string>
<string name="no_lightning_address_set">कोई लैटनिंग पता स्थापित नहीं</string>
<string name="live_stream_live_tag">तत्क्षणप्रसार</string>
<string name="live_stream_offline_tag">ालरहित</string>
<string name="live_stream_live_tag">वर्तमान</string>
<string name="live_stream_offline_tag">असंयोजित</string>
<string name="live_stream_ended_tag">समाप्त</string>
<string name="live_stream_planned_tag">समय निर्धारित</string>
<string name="live_stream_private_tag">निजी</string>
<string name="live_stream_is_offline">तत्क्षणप्रसार कट गया</string>
<string name="live_stream_has_ended">तत्क्षणप्रसार समाप्त</string>
<string name="live_stream_is_offline">वर्तमानप्रवाह कट गया</string>
<string name="live_stream_has_ended">वर्तमानप्रवाह समाप्त</string>
<string name="meeting_space_open_tag">खुला</string>
<string name="meeting_space_private_tag">निजी</string>
<string name="meeting_space_closed_tag">आवृत</string>
@@ -1636,7 +1639,7 @@
<string name="discover_reads">पठितव्य</string>
<string name="discover_content_v2">सूचनावली विधियाँ</string>
<string name="discover_marketplace">व्यापारक्षेत्र</string>
<string name="discover_live_v2">तत्क्षणप्रसार</string>
<string name="discover_live_v2">वर्तमानप्रवाह</string>
<string name="discover_community_v2">समुदाय</string>
<string name="discover_chat">चर्चाएँ</string>
<string name="community_approved_posts">अनुमति प्राप्त पत्र</string>
@@ -1792,7 +1795,7 @@
<string name="relay_group_invite_description">इस अक्षरराशि को बाँटें जिससे लोग इस समूह से जुड सकें।</string>
<string name="relay_group_invite_generating">आमन्त्रण बनाया जा रहा है…</string>
<string name="relay_group_invite_copied">आमन्त्रण अक्षरराशि अनुकृत</string>
<string name="relay_group_invite_code_label">आमन्त्रण अक्षरराशि (इस केवल आमन्त्रित समूह के लिए):</string>
<string name="relay_group_invite_code_label">आमन्त्रण अक्षरराशि (इस आमन्त्रण सीमित समूह के लिए):</string>
<string name="relay_group_join_title">समूह से जुडें</string>
<string name="relay_group_join_code_label">आमन्त्रण अक्षरराशि</string>
<string name="relay_group_join_code_hint">यह समूह आमन्त्रण सीमित है। आपको दी गई अक्षरराशि प्रविष्ट करें।</string>
@@ -2517,7 +2520,7 @@
<string name="video_player_settings_action_share">बाँटें अथवा अभिलेखन करें</string>
<string name="video_player_settings_action_share_description">चलचित्र योजक बाहर बाँटें</string>
<string name="video_player_settings_action_download">संचारयन्त्र में अभिलेखन करें</string>
<string name="video_player_settings_action_download_description">चलचित्र का अवरोहण करें आपके यन्त्र तक (सीधे प्रसारों में अदृश्य)</string>
<string name="video_player_settings_action_download_description">चलचित्र का अवरोहण करें आपके यन्त्र तक (वर्तमानप्रवाहों में अदृश्य)</string>
<string name="video_player_settings_action_pip">चित्र में चित्र</string>
<string name="video_player_settings_action_pip_description">चलचित्र दिखाएँ तैरते गवाक्ष में (अदृश्य यदि अनालम्बित)</string>
<string name="video_player_settings_action_cast">यन्त्र पर निक्षेपण</string>
@@ -3020,8 +3023,8 @@
<string name="kind_adventure_scene">साहसिक दृश्य</string>
<string name="kind_adventure_reading">साहसिक पठन</string>
<string name="kind_named_bookmarks">नाम युक्त स्मर्त्तव्य सूची</string>
<string name="kind_live_chats">सीधी बातचीत</string>
<string name="kind_live_streams">सीधा प्रसारण</string>
<string name="kind_live_chats">वर्तमान बातचीत</string>
<string name="kind_live_streams">वर्तमानप्रवाह</string>
<string name="kind_zaps">ज्साप</string>
<string name="kind_nwc_request">नोस्टर धनकोष अनुरोध</string>
<string name="kind_nwc_response">नोस्टर धनकोष प्रत्युत्तर</string>
@@ -3243,7 +3246,7 @@
<string name="hls_state_uploaded_format">आरोहण कृत %2$d में से %1$d</string>
<string name="hls_state_publishing">घटना प्रकाशन चालू…</string>
<string name="hls_state_success_title">दृश्याभिलेख प्रकाशित</string>
<string name="hls_state_success_body">आपका उच्छनिरूपण दृश्याभिलेख नोस्टर पर चलन्त है।</string>
<string name="hls_state_success_body">आपका उच्छनिरूपण दृश्याभिलेख नोस्टर पर वर्तमान है।</string>
<string name="hls_state_failure_title">कुछ गडबड हुआ</string>
<string name="hls_done">हो गया</string>
<string name="hls_try_again">पुनः प्रयास करें</string>
@@ -3303,7 +3306,7 @@
<item quantity="other">%1$s सं॰ %2$d अधिक</item>
</plurals>
<!-- PS1 memory-card saves over nostr (kind 38192). "PS1" is the PlayStation 1, do not translate. -->
<string name="ps1_save_title">पीएस१ स्मृति पट्टि अभिलेखन</string>
<string name="ps1_save_title">पीएस१ स्मृति पत्रक अभिलेखन</string>
<string name="ps1_save_block">खण्ड %1$d</string>
<string name="ps1_save_empty_slot">रिक्त छेद</string>
<!-- Roadstr road event reports (kinds 1315/1316). "Roadstr" is a proper noun, do not translate. -->
@@ -3428,7 +3431,7 @@
<string name="ai_writing_setting_title">लेख शोधन प्रस्ताव करें</string>
<string name="ai_writing_setting_description">यन्त्र स्थित एआई॰ प्रतिरूप का प्रयोग करता है लेख सुधार तथा स्वर परिवर्तन प्रस्तावों के लिए।</string>
<string name="tracked_broadcasts_setting_title">पदचिह्न युक्त प्रसारण</string>
<string name="tracked_broadcasts_setting_description">पदचिह्न युक्त प्रसारक का उपयोग करें घटनाओं को भेजते समय। तत्काल प्रगति दिखाता है तथा प्रत्येक पुनःप्रसारक की स्थिति प्रसारण करते समय।</string>
<string name="tracked_broadcasts_setting_description">पदचिह्न युक्त प्रसारक का उपयोग करें घटनाओं को भेजते समय। वर्तमान प्रगति दिखाता है तथा प्रत्येक पुनःप्रसारक की स्थिति प्रसारण करते समय।</string>
<string name="suggest_workouts_setting_title">व्यायामों का सुझाव बाँटनें के लिए</string>
<string name="suggest_workouts_setting_description">सम्पन्न व्यायाम पढता है स्वास्थ्य संयोजन से (सामसंग स्वास्थ्य तथा गूगिल फिट तथा फिटबिट तथा गार्मिन इत्यादि) तथा पत्र के रूप में बाँटने का सुझाव देता है। अनुमति अनुरोध केवल संयोजन करने पर।</string>
<string name="compose_settings">सम्पादन स्थापना विकल्प</string>
@@ -3437,14 +3440,84 @@
<string name="compose_signature_setting_title">हस्ताक्षर</string>
<string name="compose_signature_setting_description">सन्देश के अन्त में जोडा जाएगा नए पत्र प्रत्युत्तर उद्धरण अथवा निबन्ध खोलते समय। रिक्त छोड दें अक्षम करने के लिए।</string>
<string name="compose_signature_setting_hint">आपका हस्ताक्षर</string>
<string name="pow_settings_title">श्रम प्रमाण</string>
<string name="pow_settings_title">श्रमप्रमाण</string>
<string name="pow_difficulty_title">कठिनाई</string>
<string name="pow_difficulty_explainer">एक निप॰१३ श्रमप्रमाण का खनन करता है आपके पत्रों के लिए प्रकाशन पूर्व जिससे पुनःप्रसारक तथा पढनेवाले उसका तोलन कर सके कचरालेख के प्रति। उच्चतर मूल्यों के लिए घातांकीय अधिक समय लगेगा। पत्र प्रकाशित होंगे अदृश्यतः खनन पश्चात।</string>
<string name="pow_difficulty_explainer">एक निप॰१३ श्रमप्रमाण का खनन करता है आपके पत्रों के लिए प्रकाशन पूर्व जिससे पुनःप्रसारक तथा पढनेवाले उसका तोलन कर सके कचरालेख के प्रति। उच्चतर मूल्यों के लिए घातांकीयतः अधिक समय लगेगा। पत्र प्रकाशित होंगे अदृश्यतः खनन पश्चात।</string>
<string name="pow_difficulty_off">निष्क्रिय</string>
<string name="pow_custom_difficulty_title">विशिष्ट कठिनाई</string>
<string name="pow_custom_difficulty_explainer">लक्ष्य का सूक्ष्मानुकूलन अग्रतम शून्य द्व्यंकों में।</string>
<string name="pow_categories_title">क्या खनन करना चाहिए</string>
<string name="pow_categories_explainer">समयसंकट घटनाओं (पुनःप्रसारक प्रमाणीकरण ज्साप अनुरोध धनकोष तथा हस्ताक्षरकर्ता सन्देश पाण्डुलिपियाँ सूचियाँ) के लिए खनन कभी नहीं।</string>
<string name="pow_category_short_notes">लघु टीकाएँ तथा प्रत्युत्तर</string>
<string name="pow_category_short_notes_explainer">प्राथमिक सार्वजनिक कचरालेख रूप</string>
<string name="pow_category_comments">टिप्पणियाँ</string>
<string name="pow_category_comments_explainer">निबन्ध अभिलेख तथा अन्य विषयवस्तुओं के लिए प्रत्युत्तर</string>
<string name="pow_category_reports">सूचनाएँ</string>
<string name="pow_category_reports_explainer">पुनःप्रसारक सूचनाओं का तोलन करते हैं उनके लागत के अनुसार</string>
<string name="pow_category_long_form">दीर्घरूप तथा उद्दीप्तव्य</string>
<string name="pow_category_long_form_explainer">निबन्ध तथा उद्दीप्तव्य। विरल। लागत नगण्य</string>
<string name="pow_category_voice">ध्वनि सन्देश</string>
<string name="pow_category_voice_explainer">सार्वजनिक ध्वनि पत्र तथा प्रत्युत्तर</string>
<string name="pow_category_reposts">पुनःप्रकाशन</string>
<string name="pow_category_reposts_explainer">उच्च मात्रा सक्रिय प्रयोक्ताओं के लिए</string>
<string name="pow_category_reactions">प्रतिक्रियाएँ</string>
<string name="pow_category_reactions_explainer">उच्चतम मात्रा प्रकार। प्रत्येक इष्टसूचक के लिए खनन का परिणाम विद्युत्कोष का व्यय</string>
<string name="pow_category_public_chat">सार्वजनिक तथा वर्तमान चर्चा</string>
<string name="pow_category_public_chat_explainer">खनन विलम्बता से वार्तालाप प्रवाह आहत</string>
<string name="pow_category_gift_wraps">निजी सन्देश कोष</string>
<string name="pow_category_gift_wraps_explainer">सीधासन्देश पुनःप्रसारकों को आगतपेटिका कचरालेख छालन करने में सक्षम करता है। केवल बाहरी कोष का खनन होता है। आपका सन्देश कभी नहीं</string>
<string name="pow_category_other_public">अन्य सार्वजनिक विषयवस्तु</string>
<string name="pow_category_other_public_explainer">मतदान वर्तमानस्थितियाँ वर्गीकृतविज्ञापन तथा अन्य सभी सार्वजनिक</string>
<string name="pow_mining_title">श्रमप्रमाण खनन</string>
<plurals name="pow_mining_progress">
<item quantity="one">श्रमप्रमाण खनन… (%1$d पत्र पंक्ति में)</item>
<item quantity="other">श्रमप्रमाण खनन… (%1$d पत्र पंक्ति में)</item>
</plurals>
<plurals name="pow_mining_job">
<item quantity="one">%1$s। खनन %2$d द्व्यंक पर</item>
<item quantity="other">%1$s। खनन %2$d द्व्यंक पर</item>
</plurals>
<plurals name="pow_queued_job">
<item quantity="one">%1$s। %2$d द्व्यंक पर खनन की प्रतीक्षा</item>
<item quantity="other">%1$s। %2$d द्व्यंक पर खनन की प्रतीक्षा</item>
</plurals>
<plurals name="pow_option_default_on">
<item quantity="one">मूलविकल्प (%1$d द्व्यंक)</item>
<item quantity="other">मूलविकल्प (%1$d द्व्यंक)</item>
</plurals>
<string name="pow_option_default_off">मूलविकल्प (निष्क्रिय)</string>
<string name="pow_option_off">इस पत्र के लिए निष्क्रिय</string>
<plurals name="pow_option_bits">
<item quantity="one">%1$d द्व्यंक</item>
<item quantity="other">%1$d द्व्यंक</item>
</plurals>
<string name="pow_notification_channel_name">श्रमप्रमाण खनन</string>
<string name="pow_notification_channel_description">उन पत्रों को दिखाता है जो अपने निप॰१३ श्रमप्रमाण का खनन कर रहे हैं जिससे कि वे सम्पन्न हो सके आप क्रमक छोडने के पश्चात।</string>
<string name="pow_notification_cancel_all">निरस्त</string>
<string name="pow_difficulty_estimate">लगभग %1$s प्रति पत्र इस यन्त्र पर</string>
<string name="pow_estimate_instant">१ से॰ से न्यून</string>
<plurals name="pow_estimate_seconds">
<item quantity="one">%1$d सेकण्ड</item>
<item quantity="other">%1$d सेकण्ड</item>
</plurals>
<plurals name="pow_estimate_minutes">
<item quantity="one">%1$d मिनुट</item>
<item quantity="other">%1$d मिनुट</item>
</plurals>
<plurals name="pow_estimate_hours">
<item quantity="one">%1$d घण्टा</item>
<item quantity="other">%1$d घण्टे</item>
</plurals>
<plurals name="pow_estimate_days">
<item quantity="one">%1$d दिन</item>
<item quantity="other">%1$d दिन</item>
</plurals>
<string name="pow_time_left">लगभग %1$s शेष</string>
<string name="pow_time_left_soon">अब किसी भी क्षण</string>
<string name="pow_publish_failed">आपका %1$s खनन समाप्त हुआ पर प्रकाशित नहीं हो सका : %2$s</string>
<string name="pow_publish_failed_retry">आपका %1$s खनन समाप्त हुआ पर प्रकाशित नहीं हो सका। अगली बार क्रमक आरम्भ होने पर इसका पुनःप्रयास किया जाएगा।</string>
<string name="pow_kind_chat_message">चर्चा सन्देश</string>
<string name="pow_kind_report">सूचना</string>
<string name="ai_writing_use_this">इसका प्रयोग करें</string>
<string name="ai_writing_dismiss">हटाएँ</string>
<string name="ai_tone_correct">सम्यक</string>
@@ -139,7 +139,8 @@
<string name="send_payment_receipt_section">Zap-igazolás</string>
<string name="send_payment_receipt_clink">Közvetlen lightning-fizetés - nem lesz zapigazolás közzétéve a Nostr-on.</string>
<string name="send_payment_receipt_onchain">Egy láncon belüli zapigazolás közzé lesz téve a Nostr-on, így a címzett megtalálhatja a kifizetést.</string>
<string name="send_payment_receipt_onchain_address">Fizetés közvetlenül a láncon belüli pénztárcából a profil megadott bitcoin-címére (%1$s) - nem lesz zapigazolás közzétéve.</string>
<string name="send_payment_receipt_onchain_address">Fizetés közvetlenül a láncon belüli pénztárcából a profil megadott bitcoin-címére (%1$s) - nem lesz zapigazolás közzétéve.
</string>
<string name="send_payment_receipt_cashu">A nutzap-esemény magát az ecasht kézbesíti, így az mindig közzé lesz téve.</string>
<string name="send_payment_requesting_invoice">Számla kérése…</string>
<string name="send_payment_requesting_invoice_nostr">Számla kérése a Nostr hálózaton keresztül…</string>
@@ -793,7 +794,7 @@
<string name="relay_auth_toggle_my_relays">Saját átjátszók és helyszínek</string>
<string name="relay_auth_toggle_my_relays_desc">Bejelentkezés a saját átjátszóiba, valamint azokba a nyilvános csevegésekbe, közösségekbe és élő közvetítésekbe, amelyekhez csatlakozott vagy amelyeket kedvelt.</string>
<string name="relay_auth_toggle_read_follows">Követett személyek bejegyzéseinek olvasása</string>
<string name="relay_auth_toggle_read_follows_desc">Bejelentkezés egy követett személy átjátszóiba a bejegyzéseinek letöltéséhez.</string>
<string name="relay_auth_toggle_read_follows_desc">Bejelentkezés egy követett felhasználó átjátszóiba, hogy letölthesse a profiladatait, bejegyzéseit és a bejegyzéseihez kapcsolódó interakciókat.</string>
<string name="relay_auth_toggle_message_follows">Üzenet küldése a követett személyeknek</string>
<string name="relay_auth_toggle_message_follows_desc">Bejelentkezés egy követett személy átjátszóiba a közvetlen üzenetek, válaszok és értesítések küldéséhez.</string>
<string name="relay_auth_toggle_message_strangers">Üzenet küldése bárkinek</string>
@@ -803,13 +804,13 @@
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">Elküldi az üzenetet neki: %1$s?</string>
<string name="relay_auth_title_notify">Értesíti őt: %1$s?</string>
<string name="relay_auth_title_read">Betölti a bejegyzéseket tőle: %1$s?</string>
<string name="relay_auth_title_read">Profil, bejegyzések és interakciók betöltése tőle: %1$s?</string>
<string name="relay_auth_title_post_venue">Közzéteszi itt: %1$s?</string>
<string name="relay_auth_title_read_venue">Megnyitja ezt: %1$s?</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">Ha nem teszi meg, az üzenete nem lesz kézbesítve neki: %1$s.</string>
<string name="relay_auth_consequence_notify">Ha nem teszi meg, %1$s nem kap erről értesítést.</string>
<string name="relay_auth_consequence_read">Ha nem teszi meg, nem fogja itt látni a bejegyzéseket tőle: %1$s.</string>
<string name="relay_auth_consequence_read">Ha nem teszi meg, akkor nem fogja itt látni %1$s profilját, bejegyzéseit és interakcióit.</string>
<string name="relay_auth_consequence_post_venue">Ha nem teszi meg, az üzenete nem lesz közzétéve itt: %1$s.</string>
<string name="relay_auth_consequence_read_venue">Ha nem teszi meg, nem fogja itt látni ezt: %1$s.</string>
<string name="relay_auth_name_and_others">%1$s és mások</string>
@@ -583,6 +583,10 @@
<string name="app_definition_handles">Manipula</string>
<string name="app_definition_by">por</string>
<string name="app_definition_available_on">Disponível em</string>
<string name="app_definition_categories">Categorias</string>
<string name="app_definition_related">Relacionados</string>
<string name="app_definition_implements">Implementa</string>
<string name="app_definition_supported_nips">NIPs suportados</string>
<string name="platform_web">Web</string>
<string name="platform_android">Android</string>
<string name="platform_ios">iOS</string>
@@ -637,6 +641,9 @@
<string name="browser_go">Abrir</string>
<string name="browser_clear">Limpar</string>
<string name="browser_favorites">Favoritos</string>
<string name="browser_suggested">Descobrir web apps</string>
<string name="browser_discover_nsites">Sites de pessoas que você segue</string>
<string name="browser_discover_napplets">Apps de pessoas que você segue</string>
<string name="browser_recent_options">Opções</string>
<string name="browser_recent_remove">Remover do histórico</string>
<string name="favorite_apps">Apps favoritos</string>
@@ -662,6 +669,7 @@
<string name="napplet_permissions_forget">Esquecer este nApplet</string>
<string name="napplet_permissions_blocked">Bloqueado</string>
<string name="napplet_permissions_revoke">Revogar</string>
<string name="napplet_permissions_ask_each_time">Perguntar sempre</string>
<string name="napplet_none_found">Nenhum nApplet encontrado ainda.</string>
<!-- Napplet sandbox chrome (host top bar + live action notices) -->
<!-- Napplet capability names -->
@@ -707,14 +715,106 @@
<item quantity="other">Este nApplet quer pagar uma fatura Lightning de %1$d sats.</item>
</plurals>
<!-- Signer permissions: first-connect dialog -->
<string name="napplet_connect_title">Conectar ao Nostr</string>
<string name="napplet_connect_subtitle">quer se conectar à sua conta Nostr</string>
<string name="napplet_connect_how_handle">Como as solicitações deste app devem ser tratadas?</string>
<string name="napplet_connect_button">Conectar</string>
<string name="napplet_connect_block">Bloquear e ignorar %1$s</string>
<!-- Signer trust levels -->
<string name="napplet_policy_full_trust">Confio totalmente</string>
<string name="napplet_policy_full_trust_desc">Assinar automaticamente todas as solicitações (exceto pagamentos)</string>
<string name="napplet_policy_reasonable">Vamos ser razoáveis</string>
<string name="napplet_policy_reasonable_desc">Aprovar automaticamente as solicitações mais comuns</string>
<string name="napplet_policy_paranoid">Sou um pouco paranoico</string>
<string name="napplet_policy_paranoid_desc">Não assine nada sem me perguntar!</string>
<!-- Signer per-op consent dialog -->
<string name="napplet_consent_wants_to">quer %1$s</string>
<string name="napplet_consent_show_event">Mostrar evento</string>
<string name="napplet_consent_hide_event">Ocultar evento</string>
<string name="napplet_consent_more_options">Mais opções</string>
<string name="napplet_consent_fewer_options">Menos opções</string>
<string name="napplet_signer_allow_once">Permitir uma vez</string>
<string name="napplet_signer_allow_session">Permitir nesta sessão</string>
<string name="napplet_signer_allow_24h">Permitir por 24 horas</string>
<string name="napplet_signer_allow_30d">Permitir por 30 dias</string>
<string name="napplet_signer_allow_op">Não perguntar novamente para %1$s</string>
<string name="napplet_signer_allow_all">Não perguntar novamente para nenhuma solicitação Nostr</string>
<string name="napplet_signer_deny_once">Negar</string>
<string name="napplet_signer_deny_op">Sempre negar %1$s</string>
<string name="napplet_signer_last_used">Usado por último</string>
<string name="napplet_signer_expires">Expira</string>
<!-- Signer op labels -->
<string name="napplet_op_sign_kind">assinar evento kind %1$d</string>
<string name="napplet_op_sign_kind_named">assinar para %1$s (kind: %2$d)</string>
<string name="napplet_op_encrypt">criptografar uma mensagem</string>
<!-- Decrypt: the message is already decrypted by Amethyst; the permission is to expose it to the app -->
<string name="napplet_op_decrypt">ler suas mensagens privadas</string>
<!-- Permissions management screen -->
<string name="napplet_permissions_title">Apps conectados</string>
<string name="napplet_permissions_revoke_all">Revogar todas as permissões</string>
<string name="napplet_permissions_overrides">Substituições de operação</string>
<string name="napplet_signer_permissions_empty">Nenhum app se conectou ainda.</string>
<string name="napplet_signer_permissions_revoke_all">Revogar todas as permissões</string>
<string name="napplet_decision_allow">Permitir</string>
<string name="napplet_decision_ask">Perguntar</string>
<string name="napplet_decision_deny">Negar</string>
<string name="napplet_connected_apps_search_keywords">apps permissões assinador napplet nsite webapp confiança conectados</string>
<string name="napplet_connected_app_trust_level">Nível de confiança para assinatura</string>
<string name="napplet_connected_app_capabilities">Capacidades</string>
<string name="napplet_connected_app_forget">Esquecer este app</string>
<string name="napplet_connected_app_op_overrides">Substituições de operação de assinatura</string>
<string name="napplet_connected_app_empty">Nenhum app se conectou ainda.\n\nQuando um web app se conectar à sua chave Nostr, ele aparecerá aqui.</string>
<!-- Relay Authentication (NIP-42) settings -->
<string name="relay_auth_settings_title">Autenticação de relay</string>
<string name="relay_auth_search_keywords">auth autenticação relay assinar verificar nip-42 identidade</string>
<string name="relay_auth_global_policy">Quando autenticar</string>
<string name="relay_auth_custom_section">Em qual fazer login</string>
<string name="relay_auth_policy_always">Sempre autenticar</string>
<string name="relay_auth_policy_always_desc">Assinar desafios de autenticação de todos os relays que solicitarem</string>
<string name="relay_auth_policy_never">Nunca autenticar</string>
<string name="relay_auth_policy_never_desc">Ignorar desafios de autenticação de todos os relays</string>
<string name="relay_auth_policy_custom">Personalizado</string>
<string name="relay_auth_policy_custom_desc">Escolha exatamente em quais relays fazer login. Você será perguntado sobre qualquer um que não tenha permitido abaixo.</string>
<string name="relay_auth_toggle_my_relays">Meus relays e salas</string>
<string name="relay_auth_toggle_my_relays_desc">Fazer login nos seus próprios relays e em chats públicos, comunidades e transmissões ao vivo que você entrou ou favoritou.</string>
<string name="relay_auth_toggle_read_follows">Ler publicações de pessoas que sigo</string>
<string name="relay_auth_toggle_read_follows_desc">Fazer login nos relays de quem você segue para baixar as publicações deles.</string>
<string name="relay_auth_toggle_message_follows">Enviar mensagem a pessoas que sigo</string>
<string name="relay_auth_toggle_message_follows_desc">Fazer login nos relays de quem você segue para enviar DMs, respostas e notificações.</string>
<string name="relay_auth_toggle_message_strangers">Enviar mensagem a qualquer pessoa</string>
<string name="relay_auth_toggle_message_strangers_desc">Fazer login nos relays de desconhecidos para enviar DMs, respostas e notificações. Desativado por padrão; em vez disso, você será perguntado a cada vez.</string>
<string name="relay_auth_prompt_title">Confirmar que é você para este relay?</string>
<string name="relay_auth_prompt_message">Este relay quer confirmar que é realmente você primeiro. Seu operador verá qual conta você é.</string>
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">Enviar sua mensagem para %1$s?</string>
<string name="relay_auth_title_notify">Notificar %1$s?</string>
<string name="relay_auth_title_read">Carregar publicações de %1$s?</string>
<string name="relay_auth_title_post_venue">Publicar em %1$s?</string>
<string name="relay_auth_title_read_venue">Abrir %1$s?</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">Se não fizer isso, sua mensagem para %1$s não será entregue.</string>
<string name="relay_auth_consequence_notify">Se não fizer isso, %1$s não será notificado sobre isto.</string>
<string name="relay_auth_consequence_read">Se não fizer isso, você não verá publicações de %1$s aqui.</string>
<string name="relay_auth_consequence_post_venue">Se não fizer isso, sua mensagem para %1$s não será publicada.</string>
<string name="relay_auth_consequence_read_venue">Se não fizer isso, você não verá %1$s aqui.</string>
<string name="relay_auth_name_and_others">%1$s e outros</string>
<string name="relay_auth_reason_send_dm">Enviar sua mensagem privada para:</string>
<string name="relay_auth_reason_notify_inbox">Notificar:</string>
<string name="relay_auth_reason_read_outbox">Baixar publicações de:</string>
<string name="relay_auth_reason_post_venue">Publicar nesta sala</string>
<string name="relay_auth_reason_read_venue">Abrir esta sala</string>
<string name="relay_auth_reason_other">Usar este relay</string>
<string name="relay_auth_reason_my_own_relay">Conectar ao seu próprio relay</string>
<string name="relay_auth_allow_once">Permitir uma vez</string>
<string name="relay_auth_always_allow">Sempre permitir este relay</string>
<string name="relay_auth_always_deliver">Sempre entregar minhas mensagens</string>
<string name="relay_auth_block">Bloquear este relay</string>
<string name="relay_auth_per_relay_overrides">Substituições por relay</string>
<string name="relay_auth_forget">Esquecer</string>
<string name="relay_auth_last_used">Usado por último há %1$s</string>
<string name="relay_auth_no_overrides">Nada aqui ainda — sua política global se aplica a todos os relays.</string>
<string name="relay_auth_decision_allow">Permitir</string>
<string name="relay_auth_decision_deny">Negar</string>
<string name="nip82_repository_label">Fonte: %1$s</string>
<string name="nip82_version_label">v%1$s</string>
<string name="nip82_download">Baixar</string>
@@ -879,6 +979,105 @@
<string name="route_podcasts">Podcasts</string>
<string name="podcast_view_episodes">Ver episódios</string>
<string name="podcast_no_episodes">Nenhum episódio encontrado ainda</string>
<string name="podcast_trailer_season">Temporada %1$d</string>
<string name="podcast_explicit">Explícito</string>
<string name="podcast_completed">Concluído</string>
<string name="podcast_support_show">Apoiar o programa</string>
<string name="podcast_by_author">por %1$s</string>
<string name="podcast_season_episode">T%1$d · E%2$d</string>
<string name="podcast_season">Temporada %1$d</string>
<string name="podcast_video">Vídeo</string>
<string name="podcast_transcript">Transcrição</string>
<string name="podcast_chapters">Capítulos</string>
<string name="podcast_value_zap_split_hint">Os zaps para isto são divididos entre:</string>
<string name="podcast_hosts_and_guests">Apresentadores &amp; Convidados</string>
<string name="podcast_play_soundbite">Reproduzir destaque</string>
<string name="podcast_top_supporters">Principais apoiadores</string>
<plurals name="podcast_chapters_count">
<item quantity="one">%1$d capítulo</item>
<item quantity="other">%1$d capítulos</item>
</plurals>
<string name="podcast_role_host">Apresentador</string>
<string name="podcast_role_cohost">Coapresentador</string>
<string name="podcast_author_verified">Autor verificado</string>
<string name="podcast_value_error_title">Erro de Value-for-Value</string>
<string name="podcast_value_no_recipients">Este podcast não tem destinatários de valor pagáveis.</string>
<string name="podcast_value_keysend_requires_nwc">Conecte uma carteira Nostr Wallet Connect para enviar a destinatários keysend (nó).</string>
<string name="podcast_value_stream">Transmitir sats</string>
<string name="podcast_value_stream_hint">Envia valor automaticamente enquanto você ouve.</string>
<string name="podcast_value_streamed_total">%1$d sats transmitidos nesta sessão</string>
<string name="podcast_value_stream_requires_wallet">Conecte uma carteira Nostr Wallet Connect ou de débito para transmitir sats enquanto ouve.</string>
<string name="podcast_new_episode">Novo episódio</string>
<string name="podcast_edit_episode">Editar episódio</string>
<string name="podcast_publishing_banner">Publicando…</string>
<string name="podcast_cover_upload_cta">Adicionar capa</string>
<string name="podcast_cover_upload_hint">Imagem quadrada exibida para o episódio</string>
<string name="podcast_episode_title_label">Título</string>
<string name="podcast_episode_title_placeholder">Título do episódio</string>
<string name="podcast_episode_summary_label">Resumo</string>
<string name="podcast_episode_duration_label">Duração (segundos)</string>
<string name="podcast_episode_more_details">Mais detalhes</string>
<string name="podcast_episode_season_label">Temporada</string>
<string name="podcast_episode_number_label">Episódio nº</string>
<string name="podcast_episode_video_label">URL do vídeo</string>
<string name="podcast_episode_transcript_label">URL da transcrição</string>
<string name="podcast_episode_chapters_label">URL dos capítulos</string>
<string name="podcast_episode_topics_label">Tópicos</string>
<string name="podcast_episode_topics_placeholder">tags, separadas, por vírgula</string>
<string name="podcast_episode_audio_url_label">URL do áudio</string>
<string name="podcast_episode_audio_url_placeholder">https://…/episodio.mp3</string>
<string name="podcast_episode_audio_picked">Arquivo de áudio pronto para upload</string>
<string name="podcast_episode_audio_upload_cta">Adicionar arquivo de áudio</string>
<string name="podcast_episode_audio_upload_hint">MP3, M4A ou outro áudio</string>
<string name="podcast_episode_delete">Excluir episódio</string>
<string name="podcast_episode_delete_confirm">Excluir este episódio? Isso não pode ser desfeito.</string>
<string name="podcast_edit_show">Seu podcast</string>
<string name="podcast_show_cover_cta">Adicionar capa</string>
<string name="podcast_show_cover_hint">Arte quadrada para o seu programa</string>
<string name="podcast_show_title_label">Título do programa</string>
<string name="podcast_show_title_placeholder">Meu Podcast</string>
<string name="podcast_show_description_label">Descrição</string>
<string name="podcast_show_author_label">Autor</string>
<string name="podcast_show_email_label">E-mail de contato</string>
<string name="podcast_show_website_label">Site</string>
<string name="podcast_show_categories_label">Categorias</string>
<string name="podcast_show_categories_placeholder">Tecnologia, Notícias</string>
<string name="podcast_show_funding_label">Links de financiamento</string>
<string name="podcast_show_language_label">Idioma</string>
<string name="podcast_show_language_placeholder">pt</string>
<string name="podcast_show_copyright_label">Direitos autorais</string>
<string name="podcast_show_type_label">Tipo de programa</string>
<string name="podcast_show_type_episodic">Episódico</string>
<string name="podcast_show_explicit">Conteúdo explícito</string>
<string name="podcast_show_complete">Programa concluído (sem mais episódios)</string>
<string name="podcast_show_locked">Bloqueado (premium)</string>
<string name="podcast_new_trailer">Novo trailer</string>
<string name="podcast_trailer_upload_cta">Adicionar clipe de trailer</string>
<string name="podcast_trailer_upload_hint">Prévia curta de áudio ou vídeo</string>
<string name="podcast_trailer_title_placeholder">Título do trailer</string>
<string name="podcast_trailer_url_label">URL da mídia</string>
<string name="podcast_your_podcast">Seu podcast</string>
<string name="podcast_untitled">Sem título</string>
<string name="podcast_no_episodes_yet">Nenhum episódio ainda. Toque em Novo episódio para publicar o primeiro.</string>
<string name="podcast_create_your_show">Crie seu podcast</string>
<string name="podcast_tap_to_edit_show">Toque para editar os detalhes do programa</string>
<string name="podcast_create_show_hint">Configure o título, a arte e os detalhes do seu programa</string>
<string name="podcast_value_editor_hint">Adicione destinatários para dividir os sats recebidos por peso. Os ouvintes impulsionam ou transmitem valor para esses destinos.</string>
<string name="podcast_value_add_recipient">Adicionar destinatário</string>
<string name="podcast_value_add_address">Adicionar endereço manualmente</string>
<string name="podcast_value_search_user">Adicionar um usuário Nostr</string>
<string name="podcast_value_search_user_hint">Pesquise por nome ou @handle</string>
<string name="podcast_value_user_no_lnaddress">Este usuário não tem endereço Lightning</string>
<string name="podcast_value_remove_recipient">Remover destinatário</string>
<string name="podcast_value_recipient_name">Nome (opcional)</string>
<string name="podcast_value_type_lnaddress">Endereço Lightning</string>
<string name="podcast_value_type_node">Nó (keysend)</string>
<string name="podcast_value_lnaddress">Endereço Lightning</string>
<string name="podcast_value_lnaddress_hint">nome@exemplo.com</string>
<string name="podcast_value_node_pubkey">Chave pública do nó</string>
<string name="podcast_value_node_pubkey_hint">02abc… (33 bytes em hex)</string>
<string name="podcast_value_weight">Peso</string>
<string name="podcast_value_fee">Taxa</string>
<plurals name="podcast_episode_count">
<item quantity="one">%1$d episódio</item>
<item quantity="other">%1$d episódios</item>
@@ -907,6 +1106,9 @@
</plurals>
<string name="private_bookmarks">Itens Salvos Privados</string>
<string name="public_bookmarks">Itens Salvos Públicos</string>
<string name="repository_bookmarks">Repositórios</string>
<string name="repository_bookmarks_explainer">Seus repositórios git marcados</string>
<string name="podcast_bookmarks_explainer">Seus podcasts e episódios marcados</string>
<string name="add_to_private_bookmarks">Adicionar aos Itens Salvos Privados</string>
<string name="add_to_public_bookmarks">Adicionar aos Itens Salvos Públicos</string>
<string name="remove_from_private_bookmarks">Remover dos Itens Salvos Privados</string>
@@ -1452,6 +1654,25 @@
<string name="wallet_connect">Conectar Carteira</string>
<string name="language">Linguagem</string>
<string name="theme">Tema</string>
<string name="accent_color">Cor de destaque</string>
<string name="accent_color_description">Cor principal usada em botões e links</string>
<string name="accent_color_purple">Roxo</string>
<string name="accent_color_blue">Azul</string>
<string name="accent_color_green">Verde</string>
<string name="accent_color_orange">Laranja</string>
<string name="accent_color_red">Vermelho</string>
<string name="accent_color_pink">Rosa</string>
<string name="font_family">Fonte</string>
<string name="font_family_description">Tipo de letra usado em todo o app</string>
<string name="font_family_system">Padrão do sistema</string>
<string name="font_family_sans_serif">Sem serifa</string>
<string name="font_family_serif">Serifada</string>
<string name="font_family_monospace">Monoespaçada</string>
<string name="font_size">Tamanho da fonte</string>
<string name="font_size_description">Ajuste o tamanho do texto em todo o app</string>
<string name="font_size_small">Pequeno</string>
<string name="font_size_large">Grande</string>
<string name="font_size_huge">Enorme</string>
<string name="automatically_load_images_gifs">Pré-visualizar imagens</string>
<string name="automatically_play_videos">Reproduzir vídeos automaticamente</string>
<string name="autoplay_videos">Reprodução automática de vídeos</string>
@@ -1524,6 +1745,107 @@
<string name="messages_create_public_chat">Público</string>
<string name="messages_create_group">Grupo</string>
<string name="messages_create_public_private_chat_description">Novo Grupo Público ou Privado</string>
<string name="relay_groups_title">Grupos de relay</string>
<string name="relay_group_view_inline">Em linha</string>
<string name="relay_group_view_grouped">Por relay</string>
<string name="relay_group_view_inline_desc">Mostra cada grupo como sua própria conversa, misturado com seus chats.</string>
<string name="relay_group_view_grouped_desc">Agrupa os grupos de cada relay em uma única linha, posicionada na sua mensagem mais recente.</string>
<string name="relay_group_view_mode_title">Exibição de grupos NIP-29</string>
<string name="relay_group_server_label">Grupos de relay</string>
<string name="relay_groups_button">Grupos</string>
<string name="messages_settings">Mensagens</string>
<string name="relay_group_create_title">Criar um grupo</string>
<string name="relay_group_relay_no_nip29">Este relay não anuncia suporte a grupos NIP-29. Um grupo criado aqui não funcionará — seu nome, membros e mensagens não serão gerenciados pelo relay. Escolha um relay que suporte grupos baseados em relay.</string>
<string name="relay_group_create_name">Nome do grupo</string>
<string name="relay_group_create_topic">Tópico (opcional)</string>
<string name="relay_group_create_private">Privado (leitura somente para membros)</string>
<string name="relay_group_create_invite_only">Somente por convite</string>
<string name="relay_group_create_confirm">Criar</string>
<string name="relay_group_invite_title">Convidar pessoas</string>
<string name="relay_group_invite_description">Compartilhe este código para que as pessoas possam entrar neste grupo.</string>
<string name="relay_group_invite_generating">Criando um convite…</string>
<string name="relay_group_invite_copied">Código de convite copiado</string>
<string name="relay_group_invite_code_label">Código de convite (para este grupo somente por convite):</string>
<string name="relay_group_join_title">Entrar no grupo</string>
<string name="relay_group_join_code_label">Código de convite</string>
<string name="relay_group_join_code_hint">Este grupo é somente por convite. Insira o código que você recebeu.</string>
<string name="relay_group_join_confirm">Entrar</string>
<string name="relay_group_pending">Solicitado</string>
<string name="relay_group_role_moderator">Moderador</string>
<string name="relay_group_role_member">Membro</string>
<string name="relay_group_members_title">Membros</string>
<string name="relay_group_make_admin">Tornar admin</string>
<string name="relay_group_make_moderator">Tornar moderador</string>
<string name="relay_group_demote_member">Remover função</string>
<string name="relay_group_remove_user">Remover do grupo</string>
<string name="relay_group_remove_user_confirm">Remover %1$s deste grupo? A pessoa perderá o acesso até ser readicionada ou reconvidada.</string>
<string name="relay_group_edit_title">Editar grupo</string>
<string name="relay_group_edit_name">Nome do grupo</string>
<string name="relay_group_edit_topic">Tópico (opcional)</string>
<string name="relay_group_edit_private">Privado (leitura somente para membros)</string>
<string name="relay_group_edit_invite_only">Somente por convite</string>
<string name="relay_group_edit_confirm">Salvar</string>
<string name="relay_group_menu_members">Membros</string>
<string name="relay_group_menu_edit">Editar grupo</string>
<string name="relay_group_open">Abrir grupo</string>
<string name="relay_group_channels_empty">Nenhum grupo neste relay ainda.</string>
<string name="relay_group_invite_preparing">Preparando convite…</string>
<string name="relay_group_badge_private">Privado</string>
<string name="relay_group_badge_invite_only">Somente por convite</string>
<string name="relay_group_browse_invalid_url">Insira uma URL de relay válida (wss://…).</string>
<string name="relay_group_field_name">Nome</string>
<string name="relay_group_field_about">Descrição</string>
<string name="relay_group_field_picture">Imagem do grupo</string>
<string name="relay_group_add_photo">Adicionar foto</string>
<string name="relay_group_change_photo">Alterar foto</string>
<string name="relay_group_section_discovery">Descoberta</string>
<string name="relay_group_section_discovery_desc">Ajude as pessoas a encontrar este grupo. Tópicos e uma localização fazem-no aparecer nos filtros de descoberta correspondentes (se o relay host os suportar).</string>
<string name="relay_group_field_topics">Tópicos</string>
<string name="relay_group_field_topics_hint">bitcoin, nostr, arte</string>
<string name="relay_group_field_geohash">Localização (geohash)</string>
<string name="relay_group_section_permissions">Permissões</string>
<string name="relay_group_flag_private">Privado</string>
<string name="relay_group_flag_private_desc">Apenas membros podem ler as mensagens.</string>
<string name="relay_group_flag_invite_only">Somente por convite</string>
<string name="relay_group_flag_invite_only_desc">As pessoas precisam ser convidadas ou aprovadas para entrar.</string>
<string name="relay_group_flag_restricted">Publicação somente para membros</string>
<string name="relay_group_flag_restricted_desc">Apenas membros podem publicar mensagens.</string>
<string name="relay_group_flag_hidden">Não listado</string>
<string name="relay_group_flag_hidden_desc">Ocultar este grupo do diretório público do relay.</string>
<string name="relay_group_discovery_empty">Procurando grupos nos seus relays…</string>
<string name="relay_group_discovery_empty_filtered">Nenhum grupo encontrado para este filtro ainda.</string>
<string name="relay_group_favorite_relay">Favoritar este relay</string>
<string name="relay_group_threads_empty">Nenhuma thread ainda. Comece uma com o botão +.</string>
<string name="relay_group_thread_new">Nova thread</string>
<string name="relay_group_thread_untitled">Sem título</string>
<string name="relay_group_thread_title_label">Título</string>
<string name="relay_group_thread_body_label">Escreva algo…</string>
<string name="relay_group_thread_post">Publicar</string>
<string name="relay_group_browse_title">Encontrar grupos</string>
<string name="relay_group_browse_description">Explore os grupos hospedados em um relay. Cole um endereço de relay ou escolha um abaixo.</string>
<string name="relay_group_browse_relay_label">Endereço do relay</string>
<string name="relay_group_browse_go">Explorar</string>
<string name="relay_group_browse_your_relays">Relays em que você está</string>
<string name="relay_group_browse_popular">Relays populares</string>
<string name="relay_group_no_messages_yet">Nenhuma mensagem ainda</string>
<string name="relay_group_join_to_post">Entre neste grupo para enviar mensagens.</string>
<string name="relay_group_invite_only_to_post">Este grupo é somente por convite — você precisa de um convite para publicar.</string>
<plurals name="relay_group_member_count">
<item quantity="one">%1$d membro</item>
<item quantity="other">%1$d membros</item>
</plurals>
<plurals name="relay_group_message_count">
<item quantity="one">%1$d mensagem</item>
<item quantity="other">%1$d mensagens</item>
</plurals>
<plurals name="relay_group_message_count_capped">
<item quantity="one">%1$d+ mensagem</item>
<item quantity="other">%1$d+ mensagens</item>
</plurals>
<plurals name="relay_group_follows_participating">
<item quantity="one">%1$d pessoa que você segue</item>
<item quantity="other">%1$d pessoas que você segue</item>
</plurals>
<string name="messages_new_message">Privado</string>
<string name="messages_new_message_to">Para</string>
<string name="messages_new_message_subject">Assunto</string>
@@ -1763,12 +2085,41 @@
<string name="cashu_no_wallet_description">Crie uma carteira Cashu para guardar tokens ecash e receber nutzaps.</string>
<string name="cashu_discovering">Procurando sua carteira…</string>
<string name="cashu_discovering_description">Carteiras NIP-60 sincronizam entre clientes. Se você criou uma em outro app com esta chave Nostr, ela deve aparecer em alguns segundos.</string>
<string name="cashu_wizard_title">Configure sua carteira</string>
<string name="cashu_wizard_searching">Procurando sua carteira…</string>
<string name="cashu_wizard_searching_description">Procurando em todos os relays por uma carteira Cashu publicada sob sua chave Nostr.</string>
<string name="cashu_wizard_searching_progress">Procurando em relays… %1$d / %2$d</string>
<string name="cashu_wizard_analyzing">Verificando as carteiras que encontramos…</string>
<string name="cashu_wizard_none_title">Nenhuma carteira encontrada</string>
<string name="cashu_wizard_none_description">Não encontramos uma carteira Cashu existente sob sua chave Nostr em nenhum relay. Crie uma nova para começar.</string>
<string name="cashu_wizard_create">Criar uma nova carteira</string>
<string name="cashu_wizard_single_title">Encontramos sua carteira</string>
<string name="cashu_wizard_single_description">Esta carteira Cashu está publicada na rede Nostr sob sua chave. Use-a neste dispositivo — vamos retransmiti-la para seus relays para que seja fácil encontrá-la da próxima vez.</string>
<string name="cashu_wizard_use_wallet">Usar esta carteira</string>
<string name="cashu_wizard_multiple_title">Encontramos várias carteiras</string>
<string name="cashu_wizard_multiple_description">Você tem mais de uma carteira Cashu na rede — provavelmente criadas por apps diferentes. A mais recente se torna sua carteira principal; recupere para ela os fundos das mais antigas.</string>
<string name="cashu_wizard_main_label">Mais recente — sua carteira principal</string>
<string name="cashu_wizard_old_label">Carteira mais antiga</string>
<string name="cashu_wizard_set_main">Definir como carteira principal</string>
<string name="cashu_wizard_recover_funds">Recuperar fundos para a carteira principal</string>
<string name="cashu_wizard_recoverable">%1$s sats recuperáveis</string>
<string name="cashu_wizard_recovered">%1$s sats recuperados</string>
<string name="cashu_wizard_no_funds">Nenhum fundo recuperável</string>
<string name="cashu_wizard_invalid">Não foi possível ler esta carteira</string>
<string name="cashu_wizard_set_main_first">Defina primeiro sua carteira principal, depois recupere os fundos das mais antigas.</string>
<string name="cashu_wizard_adopting">Configurando sua carteira…</string>
<string name="cashu_wizard_retry">Buscar novamente</string>
<string name="cashu_created_title">Carteira criada</string>
<string name="cashu_created_subtitle">Agora escolha alguns mints para hospedar seus sats.</string>
<string name="cashu_created_pick_mints">Escolher mints</string>
<string name="cashu_balance">Saldo</string>
<string name="cashu_mints">Mints</string>
<string name="cashu_mint_url">URL do mint</string>
<string name="cashu_remove_mint">Remover mint</string>
<string name="cashu_add_mint">Adicionar mint</string>
<string name="cashu_history">Histórico</string>
<string name="cashu_wallet_autosaves">Sua carteira é salva automaticamente conforme você adiciona ou remove mints. Uma chave de nutzap é criada para você na primeira vez que adiciona um mint.</string>
<string name="cashu_wallet_saving">Salvando…</string>
<string name="cashu_p2pk_section">Chave de nutzap (avançado)</string>
<string name="cashu_p2pk_explainer">Uma chave privada separada, usada apenas para receber nutzaps NIP-61. Não é a chave da sua identidade Nostr.</string>
<string name="cashu_p2pk_autogen">Gerar uma nova chave</string>
@@ -2102,6 +2453,7 @@
<string name="profile_ui_setting_app_recommendations">Recomendações de Apps</string>
<string name="profile_ui_setting_zap_received_feed">Feed de Zaps Recebidos</string>
<string name="profile_ui_setting_followers_feed">Feed de Seguidores</string>
<string name="profile_ui_setting_onchain_wallet">Carteira Bitcoin (on-chain)</string>
<string name="reactions_settings">Configurações de Reações</string>
<string name="reactions_settings_description">Configure quais botões de reação são exibidos, sua ordem e se os contadores devem ser mostrados.</string>
<string name="reactions_settings_enabled">Ativado</string>
@@ -2250,6 +2602,8 @@
<string name="forked_from">Forkado de</string>
<string name="git_web_address">Site:</string>
<string name="git_clone_address">Clonar:</string>
<string name="git_merge_base">Base de merge</string>
<string name="git_pr_update_description">O pull request foi atualizado para um novo commit.</string>
<string name="git_status_open">Aberto</string>
<string name="git_status_merged">Mesclado</string>
<string name="git_status_closed">Fechado</string>
@@ -2257,11 +2611,69 @@
<string name="git_repo_tab_overview">Visão geral</string>
<string name="git_repo_tab_issues">Tickets</string>
<string name="git_repo_tab_patches">Patches e PRs</string>
<string name="git_repo_filter_open">Abertos</string>
<string name="git_repo_filter_closed">Fechados &amp; Resolvidos</string>
<string name="git_repo_label_all">Todos</string>
<string name="git_repo_bookmark">Marcar repositório</string>
<string name="git_repo_stat_files">Arquivos</string>
<string name="git_repo_stat_updated">Atualizado</string>
<string name="git_repo_recent_activity">Atividade recente</string>
<string name="git_repo_maintained_by">Mantido por</string>
<string name="git_repo_external_host_title">Hospedado externamente</string>
<string name="git_repo_external_host_body">Este repositório não pode ser clonado via http(s), então a visualização de código não está disponível aqui.</string>
<string name="git_repo_open_in_browser">Abrir no navegador</string>
<string name="git_untitled">Sem título</string>
<string name="git_repo_section_about">Sobre</string>
<string name="git_repo_section_links">Links</string>
<string name="git_repo_section_maintainers">Mantenedores</string>
<string name="git_repo_section_topics">Tópicos</string>
<string name="git_repo_personal_fork">Fork pessoal</string>
<string name="git_repo_tab_code">Código</string>
<string name="git_repo_code_loading">Carregando repositório…</string>
<string name="git_repo_code_error">Não foi possível carregar o repositório a partir da sua URL de clone.</string>
<string name="git_repo_no_clone_url">Este anúncio de repositório não tem URL de clone http(s) para navegar.</string>
<string name="git_repo_readme_missing">Este repositório não tem arquivo README.</string>
<string name="git_repo_file_load_error">Não foi possível carregar este arquivo.</string>
<string name="git_repo_binary_file">Arquivo binário (%1$s) — prévia não disponível.</string>
<string name="git_repo_empty_folder">Esta pasta está vazia.</string>
<string name="git_repo_root">raiz</string>
<string name="git_repo_retry">Tentar novamente</string>
<string name="git_repo_default_branch">padrão</string>
<string name="git_repo_search_files">Pesquisar arquivos…</string>
<string name="git_repo_no_search_results">Nenhum arquivo correspondente.</string>
<string name="git_repo_no_commits">Nenhum histórico de commits disponível.</string>
<string name="git_repo_copy_file">Copiar conteúdo do arquivo</string>
<string name="git_repo_plain_text">Texto</string>
<plurals name="git_diff_files_changed">
<item quantity="one">%1$d arquivo alterado</item>
<item quantity="other">%1$d arquivos alterados</item>
</plurals>
<string name="git_diff_binary">Arquivo binário não exibido.</string>
<string name="git_new_issue_button">Nova</string>
<string name="git_new_issue_title">Nova issue</string>
<string name="git_new_issue_subject">Título</string>
<string name="git_new_issue_body">Descrição</string>
<string name="git_new_issue_create">Criar</string>
<string name="git_new_issue_cancel">Cancelar</string>
<string name="git_new_issue_labels_hint">bug, melhoria…</string>
<string name="git_issue_close">Fechar issue</string>
<string name="git_issue_reopen">Reabrir</string>
<string name="git_status_close">Fechar</string>
<string name="git_status_reopen">Reabrir</string>
<string name="git_status_mark_merged">Marcar como merged</string>
<string name="git_pr_view_changes">Ver alterações</string>
<string name="git_pr_loading_changes">Carregando alterações…</string>
<string name="git_pr_no_changes">Nenhuma alteração de arquivo encontrada.</string>
<string name="git_pr_changes_retry">Tentar carregar alterações novamente</string>
<string name="git_pr_revised">Revisado</string>
<string name="git_repo_settings_title">Editar repositório</string>
<string name="git_repo_settings_name">Nome</string>
<string name="git_repo_settings_description">Descrição</string>
<string name="git_repo_settings_clone_urls">URLs de clone (uma por linha)</string>
<string name="git_repo_settings_web_urls">URLs web (uma por linha)</string>
<string name="git_repo_settings_topics">Tópicos (separados por vírgula)</string>
<string name="git_repo_settings_save">Salvar</string>
<string name="git_repositories">Repositórios Git</string>
<string name="nsite_title">Site Estático: %1$s</string>
<string name="napplet_card_permissions">Permissões:</string>
<string name="nsite_root_site">Site Raiz</string>
@@ -2550,6 +2962,7 @@
<string name="kind_git_patch">Patch do Git</string>
<string name="kind_git_repo">Repositório Git</string>
<string name="kind_git_reply">Resposta do Git</string>
<string name="kind_git_pr_update">Atualização de PR</string>
<string name="kind_zap_goals">Metas de Zap</string>
<string name="kind_hashtag_follows">Hashtags seguidas</string>
<string name="kind_highlights">Destaques</string>
@@ -2832,6 +3245,7 @@
<string name="goal_progress">%1$s financiado de %2$s sats da meta</string>
<string name="fundraiser_ends">Termina %1$s</string>
<string name="fundraiser_onchain_donation">Doação on-chain</string>
<string name="bird_detection_title">Detecção de pássaros</string>
<plurals name="birdex_species_count">
<item quantity="one">Birdex · %1$d espécie</item>
<item quantity="other">Birdex · %1$d espécies</item>
@@ -2841,6 +3255,9 @@
<item quantity="other">%1$s +%2$d a mais</item>
</plurals>
<!-- PS1 memory-card saves over nostr (kind 38192). "PS1" is the PlayStation 1, do not translate. -->
<string name="ps1_save_title">Salvamento em cartão de memória PS1</string>
<string name="ps1_save_block">bloco %1$d</string>
<string name="ps1_save_empty_slot">Espaço vazio</string>
<!-- Roadstr road event reports (kinds 1315/1316). "Roadstr" is a proper noun, do not translate. -->
<string name="road_event_police">Polícia</string>
<string name="road_event_speed_camera">Radar de velocidade</string>
@@ -2969,6 +3386,82 @@
<string name="compose_settings">Configurações de composição</string>
<string name="auto_create_drafts_setting_title">Criar rascunhos automaticamente</string>
<string name="auto_create_drafts_setting_description">Salva um evento de rascunho automaticamente quando você digita ou sai do compositor com texto não enviado e envia para seus relays de saída privados.</string>
<string name="compose_signature_setting_title">Assinatura</string>
<string name="compose_signature_setting_description">Adicionado ao final da mensagem ao abrir uma nova publicação, resposta, citação ou artigo. Deixe em branco para desativar.</string>
<string name="compose_signature_setting_hint">Sua assinatura</string>
<string name="pow_settings_title">Prova de trabalho</string>
<string name="pow_difficulty_title">Dificuldade</string>
<string name="pow_difficulty_explainer">Minera uma prova de trabalho NIP-13 nas suas publicações antes de publicar, para que relays e leitores possam ponderá-las contra spam. Valores mais altos levam exponencialmente mais tempo para minerar. As publicações são publicadas em segundo plano depois de mineradas.</string>
<string name="pow_difficulty_off">Desligado</string>
<string name="pow_custom_difficulty_title">Dificuldade personalizada</string>
<string name="pow_custom_difficulty_explainer">Ajuste com precisão o alvo em bits zero à esquerda.</string>
<string name="pow_categories_title">O que minerar</string>
<string name="pow_categories_explainer">Eventos com prazo crítico (autenticação de relay, solicitações de zap, mensagens de carteira e assinador, rascunhos, listas) nunca são minerados.</string>
<string name="pow_category_short_notes">Notas curtas &amp; respostas</string>
<string name="pow_category_short_notes_explainer">A principal superfície de spam público</string>
<string name="pow_category_comments">Comentários</string>
<string name="pow_category_comments_explainer">Respostas a artigos, arquivos e outros conteúdos</string>
<string name="pow_category_reports">Denúncias</string>
<string name="pow_category_reports_explainer">Os relays ponderam as denúncias pelo seu custo</string>
<string name="pow_category_long_form">Conteúdo longo &amp; destaques</string>
<string name="pow_category_long_form_explainer">Artigos e destaques; pouco frequentes, o custo é insignificante</string>
<string name="pow_category_voice">Mensagens de voz</string>
<string name="pow_category_voice_explainer">Publicações e respostas de voz públicas</string>
<string name="pow_category_reposts">Republicações</string>
<string name="pow_category_reposts_explainer">Alto volume para usuários ativos</string>
<string name="pow_category_reactions">Reações</string>
<string name="pow_category_reactions_explainer">Kind de maior volume; minerar cada curtida gasta bateria</string>
<string name="pow_category_public_chat">Chat público &amp; ao vivo</string>
<string name="pow_category_public_chat_explainer">Atrasos de mineração prejudicam o fluxo da conversa</string>
<string name="pow_category_gift_wraps">Envelopes de mensagens privadas</string>
<string name="pow_category_gift_wraps_explainer">Permite que os relays de DM filtrem spam da caixa de entrada; apenas o envelope externo é minerado, nunca sua mensagem</string>
<string name="pow_category_other_public">Outro conteúdo público</string>
<string name="pow_category_other_public_explainer">Enquetes, status ao vivo, classificados e tudo mais que for público</string>
<string name="pow_mining_title">Minerando prova de trabalho</string>
<plurals name="pow_mining_progress">
<item quantity="one">Minerando prova de trabalho… (%1$d publicação na fila)</item>
<item quantity="other">Minerando prova de trabalho… (%1$d publicações na fila)</item>
</plurals>
<plurals name="pow_mining_job">
<item quantity="one">%1$s • minerando em %2$d bit</item>
<item quantity="other">%1$s • minerando em %2$d bits</item>
</plurals>
<plurals name="pow_queued_job">
<item quantity="one">%1$s • aguardando para minerar em %2$d bit</item>
<item quantity="other">%1$s • aguardando para minerar em %2$d bits</item>
</plurals>
<plurals name="pow_option_default_on">
<item quantity="one">Padrão (%1$d bit)</item>
<item quantity="other">Padrão (%1$d bits)</item>
</plurals>
<string name="pow_option_default_off">Padrão (desligado)</string>
<string name="pow_option_off">Desligado para esta publicação</string>
<string name="pow_notification_channel_name">Mineração de prova de trabalho</string>
<string name="pow_notification_channel_description">Mostra publicações que ainda estão minerando sua prova de trabalho NIP-13 para que possam terminar depois que você sair do app.</string>
<string name="pow_notification_cancel_all">Cancelar</string>
<string name="pow_difficulty_estimate">≈ %1$s por publicação neste dispositivo</string>
<plurals name="pow_estimate_seconds">
<item quantity="one">%1$d segundo</item>
<item quantity="other">%1$d segundos</item>
</plurals>
<plurals name="pow_estimate_minutes">
<item quantity="one">%1$d minuto</item>
<item quantity="other">%1$d minutos</item>
</plurals>
<plurals name="pow_estimate_hours">
<item quantity="one">%1$d hora</item>
<item quantity="other">%1$d horas</item>
</plurals>
<plurals name="pow_estimate_days">
<item quantity="one">%1$d dia</item>
<item quantity="other">%1$d dias</item>
</plurals>
<string name="pow_time_left">≈ %1$s restante</string>
<string name="pow_time_left_soon">a qualquer momento</string>
<string name="pow_publish_failed">Seu %1$s terminou de minerar, mas não pôde ser publicado: %2$s</string>
<string name="pow_publish_failed_retry">Seu %1$s terminou de minerar, mas não pôde ser publicado. Uma nova tentativa será feita na próxima vez que o app iniciar.</string>
<string name="pow_kind_chat_message">Mensagem de chat</string>
<string name="pow_kind_report">Denúncia</string>
<string name="ai_writing_use_this">Usar isto</string>
<string name="ai_writing_dismiss">Dispensar</string>
<string name="ai_tone_correct">Corrigir</string>
+178 -9
View File
@@ -811,13 +811,50 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="relay_auth_settings_title">Avtentikacija releja</string>
<string name="relay_auth_search_keywords">Preverjanje pristnosti (Auth), rele (Relay), podpis (Sign), preverjanje (Verify), NIP-42, identiteta</string>
<string name="relay_auth_global_policy">Globalna pravila</string>
<string name="relay_auth_custom_section">V kaj se prijaviti</string>
<string name="relay_auth_policy_always">Vedno zahtevaj avtentikacijo</string>
<string name="relay_auth_policy_always_desc">Podpiši avtentikacijske izzive za vsak relej, ki to zahteva</string>
<string name="relay_auth_policy_never">Nikoli ne avtenticiraj</string>
<string name="relay_auth_policy_never_desc">Prezri avtentikacijske izzive vseh relejev</string>
<string name="relay_auth_policy_custom">Po meri</string>
<string name="relay_auth_policy_custom_desc">Izberite natančno, v katere releje se želite prijaviti. Za vse, česar spodaj niste dovolili, boste vprašani naknadno.</string>
<string name="relay_auth_toggle_my_relays">Moji releji in prizorišča</string>
<string name="relay_auth_toggle_my_relays_desc">Prijavite se v svoje releje ter v javne klepete, skupnosti in prenose v živo, ki jim sledite ali ste jih dodali med priljubljene.</string>
<string name="relay_auth_toggle_read_follows">Preberi objave ljudi, ki jim sledim</string>
<string name="relay_auth_toggle_read_follows_desc">Prijavite se v releje oseb, ki jim sledite, za prenos podatkov njihovega profila, objav in odzivov na objave.</string>
<string name="relay_auth_toggle_message_follows">Pošlji sporočila osebam, ki jim sledim</string>
<string name="relay_auth_toggle_message_follows_desc">Prijavite se v releje oseb, ki jim sledite, da jim lahko pošiljate zasebna sporočila (ZS), odgovore in obvestila.</string>
<string name="relay_auth_toggle_message_strangers">Pošlji sporočilo vsem</string>
<string name="relay_auth_toggle_message_strangers_desc">Prijavite se v releje neznanih oseb za pošiljanje zasebnih sporočil, odgovorov in obvestil. Privzeto izklopljeno; vsakič boste vprašani za dovoljenje.</string>
<string name="relay_auth_prompt_title">Potrdite temu releju, da ste to vi?</string>
<string name="relay_auth_prompt_message">Ta rele želi najprej potrditi, da ste to vi. Upravljavec releja bo videl, kateri račun uporabljate.</string>
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">Pošljem sporočilo %1$s?</string>
<string name="relay_auth_title_notify">Obvestim %1$s?</string>
<string name="relay_auth_title_read">Naložim profil, objave in odzive iz %1$s?</string>
<string name="relay_auth_title_post_venue">Pošljem v %1$s?</string>
<string name="relay_auth_title_read_venue">Odprem %1$s?</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">V nasprotnem primeru sporočilo za %1$s ne bo dostavljeno.</string>
<string name="relay_auth_consequence_notify">V nasprotnem primeru %1$s o tem ne bo obveščen.</string>
<string name="relay_auth_consequence_read">V nasprotnem primeru tukaj ne boste videli profila, objav ali odzivov od %1$s.</string>
<string name="relay_auth_consequence_post_venue">V nasprotnem primeru vaše sporočilo za %1$s ne bo objavljeno.</string>
<string name="relay_auth_consequence_read_venue">V nasprotnem primeru tukaj ne boste videli %1$s.</string>
<string name="relay_auth_name_and_others">%1$s in ostali</string>
<string name="relay_auth_reason_send_dm">Pošlji zasebno sporočilo:</string>
<string name="relay_auth_reason_notify_inbox">Obvesti:</string>
<string name="relay_auth_reason_read_outbox">Prenesi podatke o profilu, objave in odzive iz:</string>
<string name="relay_auth_reason_post_venue">Pošlji v to sobo</string>
<string name="relay_auth_reason_read_venue">Odpri to sobo</string>
<string name="relay_auth_reason_other">Uporabi ta rele</string>
<string name="relay_auth_reason_my_own_relay">Poveži se z lastnim relejem</string>
<string name="relay_auth_allow_once">Dovoli tokrat</string>
<string name="relay_auth_always_allow">Vedno dovoli ta rele</string>
<string name="relay_auth_always_deliver">Vedno dostavi moja sporočila</string>
<string name="relay_auth_block">Blokiraj ta rele</string>
<string name="relay_auth_per_relay_overrides">Prilagoditve po posameznem releju</string>
<string name="relay_auth_forget">Pozabi</string>
<string name="relay_auth_last_used">Zadnjič uporabljen pred %1$s</string>
<string name="relay_auth_no_overrides">Brez preglasitev na posameznih relejih — globalna politika velja povsod</string>
<string name="relay_auth_decision_allow">Dovoli</string>
<string name="relay_auth_decision_deny">Zavrni</string>
@@ -855,7 +892,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="nest_chat_send_failed_title">Sporočila ni bilo mogoče poslati</string>
<string name="nest_no_app_to_open_link">Nimate nameščene aplikacije za odpiranje te povezave.</string>
<string name="nest_close_room_confirm_title">Zaprem to sobo?</string>
<string name="nest_close_room_confirm_body">Vsi udeleženci bodo odklopljeni. Soba bo v viru vsebin prikazana kot ZAPRTA.</string>
<string name="nest_close_room_confirm_body">Vsi udeleženci bodo odklopljeni. Soba bo v viru vsebin prikazana kot KONČANA.</string>
<string name="nest_close_room_confirm_action">Zapri sobo</string>
<string name="nest_audio_failed">Napaka pri zvoku: %1$s</string>
<string name="nest_talk">Govori</string>
@@ -1331,7 +1368,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="follow_list_kind3_follows_users_only">Privzeti seznam sledenih</string>
<string name="follow_list_aroundme">V moji okolici</string>
<string name="follow_list_global">Globalno</string>
<string name="follow_list_curated">Urejeno</string>
<string name="follow_list_curated">Izbrani</string>
<string name="follow_list_mine">Moje</string>
<string name="follow_list_mute_list">Seznam utišanih</string>
<string name="follow_sets">Seznam sledenih</string>
@@ -1418,7 +1455,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="app_notification_mark_read_label">Označi kot prebrano</string>
<string name="app_notification_dms_summary">Novo sporočilo</string>
<string name="app_notification_zaps_summary">Novi zapi</string>
<string name="app_notification_reactions_channel_name">Odzivi</string>
<string name="app_notification_reactions_channel_name">Odzivne ikone</string>
<string name="app_notification_reactions_channel_description">Prejmi obvestila o odzivih na objave</string>
<string name="app_notification_reactions_channel_message">%1$s se je odzval na vašo objavo</string>
<string name="app_notification_reactions_channel_message_for">za %1$s</string>
@@ -1625,11 +1662,11 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="quick_actions_open_in_another_app">Odpri z drugo aplikacijo</string>
<string name="no_lightning_address_set">Lightning naslov ni nastavljen</string>
<string name="live_stream_live_tag">V ŽIVO</string>
<string name="live_stream_offline_tag">ODKLOPLEN</string>
<string name="live_stream_offline_tag">NEDOSEGLJIV</string>
<string name="live_stream_ended_tag">KONČANO</string>
<string name="live_stream_planned_tag">PLANIRANO</string>
<string name="live_stream_private_tag">ZASEBNO</string>
<string name="live_stream_is_offline">Prenos v živo je odklopljen</string>
<string name="live_stream_is_offline">Prenos v živo je končan</string>
<string name="live_stream_has_ended">Prenos v živo je končan</string>
<string name="meeting_space_open_tag">ODPRTO</string>
<string name="meeting_space_private_tag">ZASEBNO</string>
@@ -1656,7 +1693,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="preferences">Nastavitve aplikacije</string>
<string name="user_preferences">Nastavitve uporabnika</string>
<string name="translations">Prevodi</string>
<string name="reactions">Reakcije</string>
<string name="reactions">Odzivi</string>
<string name="settings">Nastavitve</string>
<string name="account_settings">Nastavitve računa</string>
<string name="app_settings">Nastavitve aplikacije</string>
@@ -1791,6 +1828,7 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="relay_group_view_grouped_desc">Strni skupine posameznega releja v eno vrstico, prikazano pri njegovem najnovejšem sporočilu.</string>
<string name="relay_group_view_mode_title">Prikaz skupin NIP-29</string>
<string name="relay_group_server_label">Skupine relejev</string>
<string name="relay_groups_button">Skupine</string>
<string name="messages_settings">Sporočila</string>
<string name="relay_group_create_title">Ustvari skupino</string>
<string name="relay_group_relay_no_nip29">Ta relej ne oglašuje podpore za skupine NIP-29. Skupina, ustvarjena tukaj, ne bo delovala relej ne bo upravljal njenega imena, članov in sporočil. Izberite rele, ki podpira skupine na ravni releja.</string>
@@ -1860,6 +1898,41 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="relay_group_thread_new">Nov niz objav</string>
<string name="relay_group_thread_untitled">Brez naslova</string>
<string name="relay_group_thread_title_label">Naslov</string>
<string name="relay_group_thread_body_label">Napiši kaj…</string>
<string name="relay_group_thread_post">Pošlji</string>
<string name="relay_group_browse_title">Najdi skupine</string>
<string name="relay_group_browse_description">Brskajte po skupinah, ki jih gosti rele. Prilepite naslov releja ali izberite enega spodaj.</string>
<string name="relay_group_browse_relay_label">Naslov releja</string>
<string name="relay_group_browse_go">Brskaj</string>
<string name="relay_group_browse_your_relays">Releji na katerih ste vi</string>
<string name="relay_group_browse_popular">Popularni releji</string>
<string name="relay_group_no_messages_yet">Ni sporočil</string>
<string name="relay_group_join_to_post">Pridružite se tej skupini, da boste lahko pošiljali sporočila.</string>
<string name="relay_group_invite_only_to_post">Ta skupina je zaprtega tipa za objavljanje potrebujete povabilo.</string>
<plurals name="relay_group_member_count">
<item quantity="one">%1$d član</item>
<item quantity="two">%1$d člana</item>
<item quantity="few">%1$d člani</item>
<item quantity="other">%1$d članov</item>
</plurals>
<plurals name="relay_group_message_count">
<item quantity="one">%1$d sporočilo</item>
<item quantity="two">%1$d sporočila</item>
<item quantity="few">%1$d sporočila</item>
<item quantity="other">%1$d sporočil</item>
</plurals>
<plurals name="relay_group_message_count_capped">
<item quantity="one">%1$d+ sporočilo</item>
<item quantity="two">%1$d+ sporočila</item>
<item quantity="few">%1$d+ sporočila</item>
<item quantity="other">%1$d+ sporočil</item>
</plurals>
<plurals name="relay_group_follows_participating">
<item quantity="one">%1$d uporabnik, ki mu sledite</item>
<item quantity="two">%1$d uporabnika, ki jima sledite</item>
<item quantity="few">%1$d uporabniki, ki jim sledite</item>
<item quantity="other">%1$d uporabnikov, ki jim sledite</item>
</plurals>
<string name="messages_new_message">Zasebno</string>
<string name="messages_new_message_to">Za</string>
<string name="messages_new_message_subject">Zadeva</string>
@@ -3026,7 +3099,7 @@ Za ohranitev zasebnosti to denarnico polni in prazni prek ne-zasebnih računov,
<string name="kind_git_pr_update">Posodobitev zahtevka (PR)</string>
<string name="kind_zap_goals">Ciljni znesek zapov</string>
<string name="kind_hashtag_follows">Sledeni ključniki</string>
<string name="kind_highlights">Osvetlitve</string>
<string name="kind_highlights">Poudarki</string>
<string name="kind_http_auth">Http Auth</string>
<string name="kind_index_relay_list">Indeksiraj seznam relejev</string>
<string name="kind_adventure_prologue">Pustolovski prolog</string>
@@ -3067,7 +3140,7 @@ Za ohranitev zasebnosti to denarnico polni in prazni prek ne-zasebnih računov,
<string name="kind_private_relays">Zasebni releji</string>
<string name="kind_proxy_relays">Proxy releji</string>
<string name="kind_public_message">Javno sporočilo</string>
<string name="kind_reactions">Odzivne ikone</string>
<string name="kind_reactions">Odzivi</string>
<string name="kind_contact_card">Kartica kontakta</string>
<string name="kind_relay_auth">Avtorizacija releja</string>
<string name="kind_relay_discovery">Odkrivanje relejev</string>
@@ -3160,7 +3233,7 @@ Za ohranitev zasebnosti to denarnico polni in prazni prek ne-zasebnih računov,
<string name="profiles">profili</string>
<string name="relay_settings_lower2">izhodni seznami</string>
<string name="last_seen">Nazadnje viden pred %1$s</string>
<string name="last_seen_on_date">Nazadje viden na %1$s (%2$s nazaj)</string>
<string name="last_seen_on_date">Nazadje viden %1$s (pred %2$s)</string>
<string name="last_seen_just_now">Nazadnje viden prav zdaj</string>
<string name="last_seen_never">Nikoli viden</string>
<plurals name="duration_minutes">
@@ -3472,6 +3545,102 @@ Za ohranitev zasebnosti to denarnico polni in prazni prek ne-zasebnih računov,
<string name="compose_signature_setting_title">Podpis</string>
<string name="compose_signature_setting_description">Doda se na konec sporočila pri ustvarjanju nove objave, odgovora, citata ali članka. Pustite prazno, da onemogočite.</string>
<string name="compose_signature_setting_hint">Vaš podpis</string>
<string name="pow_settings_title">Dokazilo o delu (PoW)</string>
<string name="pow_difficulty_title">Težavnost</string>
<string name="pow_difficulty_explainer">Pred objavo sporočila, rudari (NIP-13) dokaz o delu (PoW), da jih lahko releji in bralci ločijo od neželene vsebine (spam). Višje vrednosti zahtevajo eksponentno več časa za rudarjenje. Objave se po končanem rudarjenju samodejno objavijo v ozadju.</string>
<string name="pow_difficulty_off">Ugasni</string>
<string name="pow_custom_difficulty_title">Težavnost po meri</string>
<string name="pow_custom_difficulty_explainer">Nastavite cilj v številu začetnih ničel</string>
<string name="pow_categories_title">Kaj rudarit</string>
<string name="pow_categories_explainer">Časovno kritični dogodki (avtentikacija relejev, zahteve za zap-e, sporočila denarnice in podpisnika, osnutki, seznami) se nikoli ne rudarijo.</string>
<string name="pow_category_short_notes">Kratki zapiski in odgovori</string>
<string name="pow_category_short_notes_explainer">Glavno javni vir za vsiljeno vsebino</string>
<string name="pow_category_comments">Komentarji</string>
<string name="pow_category_comments_explainer">Odgovori na članke, datoteke in drugo vsebino</string>
<string name="pow_category_reports">Prijave</string>
<string name="pow_category_reports_explainer">Releji ocenjujejo poročila glede na njihove stroške</string>
<string name="pow_category_long_form">Dolg zapis in poudarki</string>
<string name="pow_category_long_form_explainer">Članki in poudarki; redko, strošek je zanemarljiv</string>
<string name="pow_category_voice">Glasovna sporočila</string>
<string name="pow_category_voice_explainer">Javna glasovna sporočila in odgovori</string>
<string name="pow_category_reposts">Deli dalje</string>
<string name="pow_category_reposts_explainer">Višja glasnost za aktivne uporabnike</string>
<string name="pow_category_reactions">Odzivi</string>
<string name="pow_category_reactions_explainer">Tip (kind) z najvišjim obsegom; rudarjenje vsakega všečka porablja baterijo</string>
<string name="pow_category_public_chat">Javni in pogovori v živo</string>
<string name="pow_category_public_chat_explainer">Zamik zaradi rudarjenja, moti tekočemu pogovoru</string>
<string name="pow_category_gift_wraps">Ovoji zasebnih sporočil</string>
<string name="pow_category_gift_wraps_explainer">Releji za zasebna sporočila filtrirajo vsiljeno vsebino; rudari se le zunanji ovoj, nikoli vaše sporočilo.</string>
<string name="pow_category_other_public">Ostala javna vsebina</string>
<string name="pow_category_other_public_explainer">Ankete, statusi v živo, mali oglasi in vse ostalo javno</string>
<string name="pow_mining_title">Rudarjenje dokaza o delu (PoW)</string>
<plurals name="pow_mining_progress">
<item quantity="one">Rudarjenje dokaza o delu… (%1$d objava v čakalni vrsti)</item>
<item quantity="two">Rudarjenje dokaza o delu… (%1$d objavi v čakalni vrsti)</item>
<item quantity="few">Rudarjenje dokaza o delu… (%1$d objave v čakalni vrsti)</item>
<item quantity="other">Rudarjenje dokaza o delu… (%1$d objav v čakalni vrsti)</item>
</plurals>
<plurals name="pow_mining_job">
<item quantity="one">%1$s • rudarjenje pri %2$d bitu</item>
<item quantity="two">%1$s • rudarjenje pri %2$d bitih</item>
<item quantity="few">%1$s • rudarjenje pri %2$d bitih</item>
<item quantity="other">%1$s • rudarjenje pri %2$d bitih</item>
</plurals>
<plurals name="pow_queued_job">
<item quantity="one">%1$s • čakanje na rudarjenje pri %2$d bitu</item>
<item quantity="two">%1$s • čakanje na rudarjenje pri %2$d bitih</item>
<item quantity="few">%1$s • čakanje na rudarjenje pri %2$d bitih</item>
<item quantity="other">%1$s • čakanje na rudarjenje pri %2$d bitih</item>
</plurals>
<plurals name="pow_option_default_on">
<item quantity="one">Privzeto (%1$d bit)</item>
<item quantity="two">Privzeto (%1$d bita)</item>
<item quantity="few">Privzeto (%1$d biti)</item>
<item quantity="other">Privzeto (%1$d bitov)</item>
</plurals>
<string name="pow_option_default_off">Privzeto (izklopljeno)</string>
<string name="pow_option_off">Izklopljeno za ta zapisek</string>
<plurals name="pow_option_bits">
<item quantity="one">%1$d bit</item>
<item quantity="two">%1$d bita</item>
<item quantity="few">%1$d biti</item>
<item quantity="other">%1$d bitov</item>
</plurals>
<string name="pow_notification_channel_name">Rudarjenje z dokazom o delu (PoW)</string>
<string name="pow_notification_channel_description">Prikazuje objave, ki še rudarijo svoj NIP-13 dokaz o delu, da lahko zaključijo postopek, potem ko zapustite aplikacijo.</string>
<string name="pow_notification_cancel_all">Prekliči</string>
<string name="pow_difficulty_estimate">≈ %1$s na objavo v tej napravi</string>
<string name="pow_estimate_instant">&lt;1 s</string>
<plurals name="pow_estimate_seconds">
<item quantity="one">%1$d sekunda</item>
<item quantity="two">%1$d sekundi</item>
<item quantity="few">%1$d sekunde</item>
<item quantity="other">%1$d sekund</item>
</plurals>
<plurals name="pow_estimate_minutes">
<item quantity="one">%1$d minuta</item>
<item quantity="two">%1$d minuti</item>
<item quantity="few">%1$d minut</item>
<item quantity="other">%1$d minut</item>
</plurals>
<plurals name="pow_estimate_hours">
<item quantity="one">%1$d ura</item>
<item quantity="two">%1$d uri</item>
<item quantity="few">%1$d ure</item>
<item quantity="other">%1$d ur</item>
</plurals>
<plurals name="pow_estimate_days">
<item quantity="one">%1$d dan</item>
<item quantity="two">%1$d dneva</item>
<item quantity="few">%1$d dni</item>
<item quantity="other">%1$d dni</item>
</plurals>
<string name="pow_time_left">≈ %1$s še ostane</string>
<string name="pow_time_left_soon">Vsak čas bo</string>
<string name="pow_publish_failed">Vaš %1$s je zaključil rudarjenje, vendar ga ni bilo mogoče objaviti: %2$s</string>
<string name="pow_publish_failed_retry">Vaš %1$s je končal z rudarjenjem, vendar ga ni bilo mogoče objaviti. Ponovni poskus bo izveden ob naslednjem zagonu aplikacije.</string>
<string name="pow_kind_chat_message">Sporočilo klepeta</string>
<string name="pow_kind_report">Prijavi</string>
<string name="ai_writing_use_this">Uporabi to</string>
<string name="ai_writing_dismiss">Prekliči</string>
<string name="ai_tone_correct">Pravilno</string>
@@ -583,6 +583,10 @@
<string name="app_definition_handles">Hanterar</string>
<string name="app_definition_by">av</string>
<string name="app_definition_available_on">Tillgänglig på</string>
<string name="app_definition_categories">Kategorier</string>
<string name="app_definition_related">Relaterat</string>
<string name="app_definition_implements">Implementerar</string>
<string name="app_definition_supported_nips">NIP:er som stöds</string>
<string name="platform_web">Web</string>
<string name="platform_android">Android</string>
<string name="platform_ios">iOS</string>
@@ -638,6 +642,9 @@
<string name="browser_go">Öppna</string>
<string name="browser_clear">Rensa</string>
<string name="browser_favorites">Favoriter</string>
<string name="browser_suggested">Upptäck webbappar</string>
<string name="browser_discover_nsites">Webbplatser från personer du följer</string>
<string name="browser_discover_napplets">Appar från personer du följer</string>
<string name="browser_recent_options">Alternativ</string>
<string name="browser_recent_remove">Ta bort från historik</string>
<string name="favorite_apps">Favoritappar</string>
@@ -663,6 +670,7 @@
<string name="napplet_permissions_forget">Glöm det här nApplet</string>
<string name="napplet_permissions_blocked">Blockerad</string>
<string name="napplet_permissions_revoke">Återkalla</string>
<string name="napplet_permissions_ask_each_time">Fråga mig varje gång</string>
<string name="napplet_none_found">Inga nApplets hittades ännu.</string>
<!-- Napplet sandbox chrome (host top bar + live action notices) -->
<!-- Napplet capability names -->
@@ -710,14 +718,106 @@
<item quantity="other">Det här nApplet vill betala en Lightning-faktura på %1$d sats.</item>
</plurals>
<!-- Signer permissions: first-connect dialog -->
<string name="napplet_connect_title">Anslut till Nostr</string>
<string name="napplet_connect_subtitle">vill ansluta till ditt Nostr-konto</string>
<string name="napplet_connect_how_handle">Hur ska den här appens förfrågningar hanteras?</string>
<string name="napplet_connect_button">Anslut</string>
<string name="napplet_connect_block">Blockera och ignorera %1$s</string>
<!-- Signer trust levels -->
<string name="napplet_policy_full_trust">Jag litar helt på den</string>
<string name="napplet_policy_full_trust_desc">Signera automatiskt alla förfrågningar (utom betalningar)</string>
<string name="napplet_policy_reasonable">Låt oss vara rimliga</string>
<string name="napplet_policy_reasonable_desc">Godkänn automatiskt de vanligaste förfrågningarna</string>
<string name="napplet_policy_paranoid">Jag är lite paranoid</string>
<string name="napplet_policy_paranoid_desc">Signera inget utan att fråga mig!</string>
<!-- Signer per-op consent dialog -->
<string name="napplet_consent_wants_to">vill %1$s</string>
<string name="napplet_consent_show_event">Visa händelse</string>
<string name="napplet_consent_hide_event">Dölj händelse</string>
<string name="napplet_consent_more_options">Fler alternativ</string>
<string name="napplet_consent_fewer_options">Färre alternativ</string>
<string name="napplet_signer_allow_once">Tillåt en gång</string>
<string name="napplet_signer_allow_session">Tillåt för den här sessionen</string>
<string name="napplet_signer_allow_24h">Tillåt i 24 timmar</string>
<string name="napplet_signer_allow_30d">Tillåt i 30 dagar</string>
<string name="napplet_signer_allow_op">Fråga inte igen om att %1$s</string>
<string name="napplet_signer_allow_all">Fråga inte igen för några Nostr-förfrågningar</string>
<string name="napplet_signer_deny_once">Neka</string>
<string name="napplet_signer_deny_op">Neka alltid %1$s</string>
<string name="napplet_signer_last_used">Senast använd</string>
<string name="napplet_signer_expires">Upphör</string>
<!-- Signer op labels -->
<string name="napplet_op_sign_kind">signera en händelse av typ %1$d</string>
<string name="napplet_op_sign_kind_named">signera för %1$s (typ: %2$d)</string>
<string name="napplet_op_encrypt">kryptera ett meddelande</string>
<!-- Decrypt: the message is already decrypted by Amethyst; the permission is to expose it to the app -->
<string name="napplet_op_decrypt">läsa dina privata meddelanden</string>
<!-- Permissions management screen -->
<string name="napplet_permissions_title">Anslutna appar</string>
<string name="napplet_permissions_revoke_all">Återkalla alla behörigheter</string>
<string name="napplet_permissions_overrides">Åsidosättningar för operationer</string>
<string name="napplet_signer_permissions_empty">Inga appar har anslutit ännu.</string>
<string name="napplet_signer_permissions_revoke_all">Återkalla alla behörigheter</string>
<string name="napplet_decision_allow">Tillåt</string>
<string name="napplet_decision_ask">Fråga</string>
<string name="napplet_decision_deny">Neka</string>
<string name="napplet_connected_apps_search_keywords">appar behörigheter signerare napplet nsite webapp förtroende anslutna</string>
<string name="napplet_connected_app_trust_level">Förtroendenivå för signering</string>
<string name="napplet_connected_app_capabilities">Behörigheter</string>
<string name="napplet_connected_app_forget">Glöm den här appen</string>
<string name="napplet_connected_app_op_overrides">Åsidosättningar för signeringsoperationer</string>
<string name="napplet_connected_app_empty">Inga appar har anslutit ännu.\n\nNär en webbapp ansluter till din Nostr-nyckel visas den här.</string>
<!-- Relay Authentication (NIP-42) settings -->
<string name="relay_auth_settings_title">Reläautentisering</string>
<string name="relay_auth_search_keywords">auth autentisering relä signera verifiera nip-42 identitet</string>
<string name="relay_auth_global_policy">När autentisering ska ske</string>
<string name="relay_auth_custom_section">Vad du ska logga in på</string>
<string name="relay_auth_policy_always">Autentisera alltid</string>
<string name="relay_auth_policy_always_desc">Signera autentiseringsutmaningar för varje relä som begär det</string>
<string name="relay_auth_policy_never">Autentisera aldrig</string>
<string name="relay_auth_policy_never_desc">Ignorera autentiseringsutmaningar från alla reläer</string>
<string name="relay_auth_policy_custom">Anpassad</string>
<string name="relay_auth_policy_custom_desc">Välj exakt vilka reläer du vill logga in på. Du tillfrågas om allt du inte har tillåtit nedan.</string>
<string name="relay_auth_toggle_my_relays">Mina reläer och platser</string>
<string name="relay_auth_toggle_my_relays_desc">Logga in på dina egna reläer och på offentliga chattar, communities och livestreams som du har gått med i eller favoritmarkerat.</string>
<string name="relay_auth_toggle_read_follows">Läs inlägg från personer jag följer</string>
<string name="relay_auth_toggle_read_follows_desc">Logga in på en följd persons reläer för att ladda ner deras inlägg.</string>
<string name="relay_auth_toggle_message_follows">Meddela personer jag följer</string>
<string name="relay_auth_toggle_message_follows_desc">Logga in på en följd persons reläer för att skicka DM, svar och notiser.</string>
<string name="relay_auth_toggle_message_strangers">Meddela vem som helst</string>
<string name="relay_auth_toggle_message_strangers_desc">Logga in på främlingars reläer för att skicka DM, svar och notiser. Av som standard; du tillfrågas i stället varje gång.</string>
<string name="relay_auth_prompt_title">Bekräfta att det är du för det här reläet?</string>
<string name="relay_auth_prompt_message">Det här reläet vill först bekräfta att det verkligen är du. Dess operatör ser vilket konto du är.</string>
<!-- Action-aware titles: %1$s is the person (or "Alice and others"). -->
<string name="relay_auth_title_send_dm">Skicka ditt meddelande till %1$s?</string>
<string name="relay_auth_title_notify">Meddela %1$s?</string>
<string name="relay_auth_title_read">Läs in inlägg från %1$s?</string>
<string name="relay_auth_title_post_venue">Publicera till %1$s?</string>
<string name="relay_auth_title_read_venue">Öppna %1$s?</string>
<!-- What happens if the user doesn\'t confirm, tied to what they were doing. %1$s is the person. -->
<string name="relay_auth_consequence_send_dm">Om du inte gör det levereras inte ditt meddelande till %1$s.</string>
<string name="relay_auth_consequence_notify">Om du inte gör det meddelas inte %1$s om detta.</string>
<string name="relay_auth_consequence_read">Om du inte gör det ser du inte inlägg från %1$s här.</string>
<string name="relay_auth_consequence_post_venue">Om du inte gör det publiceras inte ditt meddelande till %1$s.</string>
<string name="relay_auth_consequence_read_venue">Om du inte gör det ser du inte %1$s här.</string>
<string name="relay_auth_name_and_others">%1$s med flera</string>
<string name="relay_auth_reason_send_dm">Skicka ditt privata meddelande till:</string>
<string name="relay_auth_reason_notify_inbox">Meddela:</string>
<string name="relay_auth_reason_read_outbox">Ladda ner inlägg från:</string>
<string name="relay_auth_reason_post_venue">Publicera till det här rummet</string>
<string name="relay_auth_reason_read_venue">Öppna det här rummet</string>
<string name="relay_auth_reason_other">Använd det här reläet</string>
<string name="relay_auth_reason_my_own_relay">Anslut till ditt eget relä</string>
<string name="relay_auth_allow_once">Tillåt en gång</string>
<string name="relay_auth_always_allow">Tillåt alltid det här reläet</string>
<string name="relay_auth_always_deliver">Leverera alltid mina meddelanden</string>
<string name="relay_auth_block">Blockera det här reläet</string>
<string name="relay_auth_per_relay_overrides">Åsidosättningar per relä</string>
<string name="relay_auth_forget">Glöm</string>
<string name="relay_auth_last_used">Senast använd för %1$s sedan</string>
<string name="relay_auth_no_overrides">Inget här ännu — din globala policy gäller för varje relä.</string>
<string name="relay_auth_decision_allow">Tillåt</string>
<string name="relay_auth_decision_deny">Neka</string>
<string name="nip82_repository_label">Källa: %1$s</string>
<string name="nip82_version_label">v%1$s</string>
<string name="nip82_download">Ladda ner</string>
@@ -882,6 +982,105 @@
<string name="route_podcasts">Poddar</string>
<string name="podcast_view_episodes">Visa avsnitt</string>
<string name="podcast_no_episodes">Inga avsnitt hittades än</string>
<string name="podcast_trailer_season">Säsong %1$d</string>
<string name="podcast_completed">Slutförd</string>
<string name="podcast_support_show">Stöd podden</string>
<string name="podcast_by_author">av %1$s</string>
<string name="podcast_season_episode">S%1$d · A%2$d</string>
<string name="podcast_episode_number">Avs %1$d</string>
<string name="podcast_season">Säsong %1$d</string>
<string name="podcast_transcript">Transkription</string>
<string name="podcast_chapters">Kapitel</string>
<string name="podcast_value_zap_split_hint">Zaps till detta fördelas mellan:</string>
<string name="podcast_hosts_and_guests">Värdar &amp; gäster</string>
<string name="podcast_play_soundbite">Spela höjdpunkt</string>
<string name="podcast_top_supporters">Främsta supportrar</string>
<plurals name="podcast_chapters_count">
<item quantity="one">%1$d kapitel</item>
<item quantity="other">%1$d kapitel</item>
</plurals>
<string name="podcast_role_host">Värd</string>
<string name="podcast_role_cohost">Medvärd</string>
<string name="podcast_role_editor">Redaktör</string>
<string name="podcast_author_verified">Verifierad författare</string>
<string name="podcast_value_error_title">Value-for-Value-fel</string>
<string name="podcast_value_no_recipients">Den här podden har inga betalbara värdemottagare.</string>
<string name="podcast_value_keysend_requires_nwc">Anslut en Nostr Wallet Connect-plånbok för att skicka till keysend-mottagare (noder).</string>
<string name="podcast_value_stream">Streama sats</string>
<string name="podcast_value_stream_hint">Skickar värde automatiskt medan du lyssnar.</string>
<string name="podcast_value_streamed_total">Streamade %1$d sats denna session</string>
<string name="podcast_value_stream_requires_wallet">Anslut en Nostr Wallet Connect- eller debiteringsplånbok för att streama sats medan du lyssnar.</string>
<string name="podcast_new_episode">Nytt avsnitt</string>
<string name="podcast_edit_episode">Redigera avsnitt</string>
<string name="podcast_publishing_banner">Publicerar…</string>
<string name="podcast_cover_upload_cta">Lägg till omslagsbild</string>
<string name="podcast_cover_upload_hint">Kvadratisk bild som visas för avsnittet</string>
<string name="podcast_episode_title_label">Titel</string>
<string name="podcast_episode_title_placeholder">Avsnittstitel</string>
<string name="podcast_episode_summary_label">Sammanfattning</string>
<string name="podcast_episode_duration_label">Längd (sekunder)</string>
<string name="podcast_episode_more_details">Fler detaljer</string>
<string name="podcast_episode_season_label">Säsong</string>
<string name="podcast_episode_number_label">Avsnitt #</string>
<string name="podcast_episode_video_label">Video-URL</string>
<string name="podcast_episode_transcript_label">Transkriptions-URL</string>
<string name="podcast_episode_chapters_label">Kapitel-URL</string>
<string name="podcast_episode_topics_label">Ämnen</string>
<string name="podcast_episode_topics_placeholder">komma, separerade, taggar</string>
<string name="podcast_episode_audio_url_label">Ljud-URL</string>
<string name="podcast_episode_audio_url_placeholder">https://…/avsnitt.mp3</string>
<string name="podcast_episode_audio_picked">Ljudfil redo att laddas upp</string>
<string name="podcast_episode_audio_upload_cta">Lägg till ljudfil</string>
<string name="podcast_episode_audio_upload_hint">MP3, M4A eller annat ljud</string>
<string name="podcast_episode_delete">Ta bort avsnitt</string>
<string name="podcast_episode_delete_confirm">Ta bort det här avsnittet? Detta kan inte ångras.</string>
<string name="podcast_edit_show">Din podd</string>
<string name="podcast_show_cover_cta">Lägg till omslagsbild</string>
<string name="podcast_show_cover_hint">Kvadratisk bild för din podd</string>
<string name="podcast_show_title_label">Poddtitel</string>
<string name="podcast_show_title_placeholder">Min podd</string>
<string name="podcast_show_description_label">Beskrivning</string>
<string name="podcast_show_author_label">Författare</string>
<string name="podcast_show_email_label">Kontakt-e-post</string>
<string name="podcast_show_website_label">Webbplats</string>
<string name="podcast_show_categories_label">Kategorier</string>
<string name="podcast_show_categories_placeholder">Teknik, Nyheter</string>
<string name="podcast_show_funding_label">Finansieringslänkar</string>
<string name="podcast_show_language_label">Språk</string>
<string name="podcast_show_language_placeholder">sv</string>
<string name="podcast_show_copyright_label">Upphovsrätt</string>
<string name="podcast_show_type_label">Poddtyp</string>
<string name="podcast_show_type_episodic">Fristående avsnitt</string>
<string name="podcast_show_type_serial">Seriell</string>
<string name="podcast_show_explicit">Explicit innehåll</string>
<string name="podcast_show_complete">Podden är komplett (inga fler avsnitt)</string>
<string name="podcast_show_locked">Låst (premium)</string>
<string name="podcast_new_trailer">Ny trailer</string>
<string name="podcast_trailer_upload_cta">Lägg till trailerklipp</string>
<string name="podcast_trailer_upload_hint">Kort ljud- eller videoförhandsvisning</string>
<string name="podcast_trailer_title_placeholder">Trailertitel</string>
<string name="podcast_trailer_url_label">Media-URL</string>
<string name="podcast_your_podcast">Din podd</string>
<string name="podcast_untitled">Namnlös</string>
<string name="podcast_no_episodes_yet">Inga avsnitt ännu. Tryck på Nytt avsnitt för att publicera ditt första.</string>
<string name="podcast_create_your_show">Skapa din podd</string>
<string name="podcast_tap_to_edit_show">Tryck för att redigera podddetaljer</string>
<string name="podcast_create_show_hint">Ange din podds titel, bild och detaljer</string>
<string name="podcast_value_editor_hint">Lägg till mottagare för att fördela inkommande sats efter vikt. Lyssnare boostar eller streamar värde till dessa destinationer.</string>
<string name="podcast_value_add_recipient">Lägg till mottagare</string>
<string name="podcast_value_add_address">Lägg till adress manuellt</string>
<string name="podcast_value_search_user">Lägg till en Nostr-användare</string>
<string name="podcast_value_search_user_hint">Sök efter namn eller @handtag</string>
<string name="podcast_value_user_no_lnaddress">Den här användaren har ingen Lightning-adress</string>
<string name="podcast_value_remove_recipient">Ta bort mottagare</string>
<string name="podcast_value_recipient_name">Namn (valfritt)</string>
<string name="podcast_value_type_lnaddress">Lightning-adress</string>
<string name="podcast_value_type_node">Nod (keysend)</string>
<string name="podcast_value_lnaddress">Lightning-adress</string>
<string name="podcast_value_lnaddress_hint">namn@example.com</string>
<string name="podcast_value_node_pubkey">Nodens publika nyckel</string>
<string name="podcast_value_weight">Vikt</string>
<string name="podcast_value_fee">Avgift</string>
<plurals name="podcast_episode_count">
<item quantity="one">%1$d avsnitt</item>
<item quantity="other">%1$d avsnitt</item>
@@ -910,6 +1109,9 @@
</plurals>
<string name="private_bookmarks">Privata Bokmärken</string>
<string name="public_bookmarks">Publika Bokmärken</string>
<string name="repository_bookmarks_explainer">Dina bokmärkta git-repositories</string>
<string name="podcast_bookmarks">Poddar</string>
<string name="podcast_bookmarks_explainer">Dina bokmärkta poddar och avsnitt</string>
<string name="add_to_private_bookmarks">Lägg till i Privata Bokmärken</string>
<string name="add_to_public_bookmarks">Lägg till i Publika Bokmärken</string>
<string name="remove_from_private_bookmarks">Ta bort från Privata Bokmärken</string>
@@ -1455,6 +1657,21 @@
<string name="wallet_connect">Plånboksanslut</string>
<string name="language">Språk</string>
<string name="theme">Tema</string>
<string name="accent_color">Accentfärg</string>
<string name="accent_color_description">Huvudfärg som används för knappar och länkar</string>
<string name="accent_color_purple">Lila</string>
<string name="accent_color_blue">Blå</string>
<string name="accent_color_green">Grön</string>
<string name="accent_color_red">Röd</string>
<string name="accent_color_pink">Rosa</string>
<string name="font_family">Typsnitt</string>
<string name="font_family_description">Teckensnitt som används genom hela appen</string>
<string name="font_family_system">Systemstandard</string>
<string name="font_size">Teckenstorlek</string>
<string name="font_size_description">Skala textstorleken i hela appen</string>
<string name="font_size_small">Liten</string>
<string name="font_size_large">Stor</string>
<string name="font_size_huge">Enorm</string>
<string name="automatically_load_images_gifs">Ladda automatiskt bilder/gif</string>
<string name="automatically_play_videos">Spela automatiskt videor</string>
<string name="autoplay_videos">Automatisk uppspelning av videor</string>
@@ -1527,6 +1744,106 @@
<string name="messages_create_public_chat">Publik</string>
<string name="messages_create_group">Grupp</string>
<string name="messages_create_public_private_chat_description">Ny offentlig eller privat grupp</string>
<string name="relay_groups_title">Relägrupper</string>
<string name="relay_group_view_grouped">Efter relä</string>
<string name="relay_group_view_inline_desc">Visa varje grupp som en egen konversation, blandad med dina chattar.</string>
<string name="relay_group_view_grouped_desc">Slå ihop varje reläs grupper till en enda rad, placerad vid dess nyaste meddelande.</string>
<string name="relay_group_view_mode_title">Visning av NIP-29-grupper</string>
<string name="relay_group_server_label">Relägrupper</string>
<string name="relay_groups_button">Grupper</string>
<string name="messages_settings">Meddelanden</string>
<string name="relay_group_create_title">Skapa en grupp</string>
<string name="relay_group_relay_no_nip29">Det här reläet annonserar inte stöd för NIP-29-relägrupper. En grupp som skapas här fungerar inte — dess namn, medlemmar och meddelanden hanteras inte av reläet. Välj ett relä som stöder reläbaserade grupper.</string>
<string name="relay_group_create_name">Gruppnamn</string>
<string name="relay_group_create_topic">Ämne (valfritt)</string>
<string name="relay_group_create_private">Privat (läsning endast för medlemmar)</string>
<string name="relay_group_create_invite_only">Endast inbjudan</string>
<string name="relay_group_create_confirm">Skapa</string>
<string name="relay_group_invite_title">Bjud in personer</string>
<string name="relay_group_invite_description">Dela den här koden så att personer kan gå med i gruppen.</string>
<string name="relay_group_invite_generating">Skapar en inbjudan…</string>
<string name="relay_group_invite_copied">Inbjudningskod kopierad</string>
<string name="relay_group_invite_code_label">Inbjudningskod (för den här gruppen med endast inbjudan):</string>
<string name="relay_group_join_title">Gå med i grupp</string>
<string name="relay_group_join_code_label">Inbjudningskod</string>
<string name="relay_group_join_code_hint">Den här gruppen är endast för inbjudna. Ange koden du fick.</string>
<string name="relay_group_join_confirm">Gå med</string>
<string name="relay_group_pending">Begärd</string>
<string name="relay_group_role_member">Medlem</string>
<string name="relay_group_members_title">Medlemmar</string>
<string name="relay_group_make_admin">Gör till admin</string>
<string name="relay_group_make_moderator">Gör till moderator</string>
<string name="relay_group_demote_member">Ta bort roll</string>
<string name="relay_group_remove_user">Ta bort från grupp</string>
<string name="relay_group_remove_user_confirm">Ta bort %1$s från den här gruppen? De förlorar åtkomst tills de läggs till eller bjuds in igen.</string>
<string name="relay_group_edit_title">Redigera grupp</string>
<string name="relay_group_edit_name">Gruppnamn</string>
<string name="relay_group_edit_topic">Ämne (valfritt)</string>
<string name="relay_group_edit_private">Privat (läsning endast för medlemmar)</string>
<string name="relay_group_edit_invite_only">Endast inbjudan</string>
<string name="relay_group_edit_confirm">Spara</string>
<string name="relay_group_menu_members">Medlemmar</string>
<string name="relay_group_menu_edit">Redigera grupp</string>
<string name="relay_group_threads_title">Trådar</string>
<string name="relay_group_open">Öppna grupp</string>
<string name="relay_group_channels_empty">Inga grupper på det här reläet ännu.</string>
<string name="relay_group_invite_preparing">Förbereder inbjudan…</string>
<string name="relay_group_badge_private">Privat</string>
<string name="relay_group_badge_invite_only">Endast inbjudan</string>
<string name="relay_group_browse_invalid_url">Ange en giltig relä-URL (wss://…).</string>
<string name="relay_group_field_name">Namn</string>
<string name="relay_group_field_about">Beskrivning</string>
<string name="relay_group_field_picture">Gruppbild</string>
<string name="relay_group_add_photo">Lägg till foto</string>
<string name="relay_group_change_photo">Ändra foto</string>
<string name="relay_group_section_discovery">Upptäckt</string>
<string name="relay_group_section_discovery_desc">Hjälp personer att hitta den här gruppen. Ämnen och en plats gör att den syns under matchande upptäcktsfilter (om värdreläet stöder dem).</string>
<string name="relay_group_field_topics">Ämnen</string>
<string name="relay_group_field_topics_hint">bitcoin, nostr, konst</string>
<string name="relay_group_field_geohash">Plats (geohash)</string>
<string name="relay_group_section_permissions">Behörigheter</string>
<string name="relay_group_flag_private">Privat</string>
<string name="relay_group_flag_private_desc">Endast medlemmar kan läsa meddelanden.</string>
<string name="relay_group_flag_invite_only">Endast inbjudan</string>
<string name="relay_group_flag_invite_only_desc">Personer måste bjudas in eller godkännas för att gå med.</string>
<string name="relay_group_flag_restricted">Publicering endast för medlemmar</string>
<string name="relay_group_flag_restricted_desc">Endast medlemmar kan publicera meddelanden.</string>
<string name="relay_group_flag_hidden">Ej listad</string>
<string name="relay_group_flag_hidden_desc">Dölj den här gruppen från reläets offentliga katalog.</string>
<string name="relay_group_discovery_empty">Söker efter grupper på dina reläer…</string>
<string name="relay_group_discovery_empty_filtered">Inga grupper hittades för det här filtret ännu.</string>
<string name="relay_group_favorite_relay">Favoritmarkera det här reläet</string>
<string name="relay_group_threads_empty">Inga trådar ännu. Starta en med +-knappen.</string>
<string name="relay_group_thread_new">Ny tråd</string>
<string name="relay_group_thread_untitled">Namnlös</string>
<string name="relay_group_thread_title_label">Titel</string>
<string name="relay_group_thread_body_label">Skriv något…</string>
<string name="relay_group_thread_post">Publicera</string>
<string name="relay_group_browse_title">Hitta grupper</string>
<string name="relay_group_browse_description">Bläddra bland grupperna som hostas på ett relä. Klistra in en reläadress eller välj en nedan.</string>
<string name="relay_group_browse_relay_label">Reläadress</string>
<string name="relay_group_browse_go">Bläddra</string>
<string name="relay_group_browse_your_relays">Reläer du är på</string>
<string name="relay_group_browse_popular">Populära reläer</string>
<string name="relay_group_no_messages_yet">Inga meddelanden ännu</string>
<string name="relay_group_join_to_post">Gå med i den här gruppen för att skicka meddelanden.</string>
<string name="relay_group_invite_only_to_post">Den här gruppen är endast för inbjudna — du behöver en inbjudan för att publicera.</string>
<plurals name="relay_group_member_count">
<item quantity="one">%1$d medlem</item>
<item quantity="other">%1$d medlemmar</item>
</plurals>
<plurals name="relay_group_message_count">
<item quantity="one">%1$d meddelande</item>
<item quantity="other">%1$d meddelanden</item>
</plurals>
<plurals name="relay_group_message_count_capped">
<item quantity="one">%1$d+ meddelande</item>
<item quantity="other">%1$d+ meddelanden</item>
</plurals>
<plurals name="relay_group_follows_participating">
<item quantity="one">%1$d person du följer</item>
<item quantity="other">%1$d personer du följer</item>
</plurals>
<string name="messages_new_message">Privat</string>
<string name="messages_new_message_to">Till</string>
<string name="messages_new_message_subject">Ämne</string>
@@ -1766,12 +2083,41 @@
<string name="cashu_no_wallet_description">Skapa en Cashu-plånbok för att hålla ecash-tokens och ta emot nutzaps.</string>
<string name="cashu_discovering">Letar efter din plånbok…</string>
<string name="cashu_discovering_description">NIP-60-plånböcker synkroniseras mellan klienter. Om du skapade en i en annan app med den här Nostr-nyckeln bör den dyka upp inom några sekunder.</string>
<string name="cashu_wizard_title">Konfigurera din plånbok</string>
<string name="cashu_wizard_searching">Söker efter din plånbok…</string>
<string name="cashu_wizard_searching_description">Söker på alla reläer efter en Cashu-plånbok publicerad under din Nostr-nyckel.</string>
<string name="cashu_wizard_searching_progress">Söker på reläer… %1$d / %2$d</string>
<string name="cashu_wizard_analyzing">Verifierar plånböckerna vi hittade…</string>
<string name="cashu_wizard_none_title">Ingen plånbok hittades</string>
<string name="cashu_wizard_none_description">Vi kunde inte hitta någon befintlig Cashu-plånbok under din Nostr-nyckel på något relä. Skapa en ny för att komma igång.</string>
<string name="cashu_wizard_create">Skapa en ny plånbok</string>
<string name="cashu_wizard_single_title">Vi hittade din plånbok</string>
<string name="cashu_wizard_single_description">Den här Cashu-plånboken är publicerad i Nostr-nätverket under din nyckel. Använd den på den här enheten — vi sänder om den till dina reläer så att den är lätt att hitta nästa gång.</string>
<string name="cashu_wizard_use_wallet">Använd den här plånboken</string>
<string name="cashu_wizard_multiple_title">Vi hittade flera plånböcker</string>
<string name="cashu_wizard_multiple_description">Du har mer än en Cashu-plånbok i nätverket — troligen skapade av olika appar. Den nyaste blir din huvudplånbok; återhämta eventuella medel från de äldre till den.</string>
<string name="cashu_wizard_main_label">Nyast — din huvudplånbok</string>
<string name="cashu_wizard_old_label">Äldre plånbok</string>
<string name="cashu_wizard_set_main">Ange som huvudplånbok</string>
<string name="cashu_wizard_recover_funds">Återhämta medel till huvudplånboken</string>
<string name="cashu_wizard_recoverable">%1$s sats kan återvinnas</string>
<string name="cashu_wizard_recovered">Återhämtade %1$s sats</string>
<string name="cashu_wizard_no_funds">Inga återvinningsbara medel</string>
<string name="cashu_wizard_invalid">Det gick inte att läsa den här plånboken</string>
<string name="cashu_wizard_set_main_first">Ange din huvudplånbok först, återhämta sedan medel från de äldre.</string>
<string name="cashu_wizard_adopting">Konfigurerar din plånbok…</string>
<string name="cashu_wizard_retry">Sök igen</string>
<string name="cashu_created_title">Plånbok skapad</string>
<string name="cashu_created_subtitle">Välj nu några mints som ska hosta dina sats.</string>
<string name="cashu_created_pick_mints">Välj mints</string>
<string name="cashu_balance">Saldo</string>
<string name="cashu_mints">Mints</string>
<string name="cashu_mint_url">Mint-URL</string>
<string name="cashu_remove_mint">Ta bort mint</string>
<string name="cashu_add_mint">Lägg till mint</string>
<string name="cashu_history">Historik</string>
<string name="cashu_wallet_autosaves">Din plånbok sparas automatiskt när du lägger till eller tar bort mints. En nutzap-nyckel skapas åt dig första gången du lägger till en mint.</string>
<string name="cashu_wallet_saving">Sparar…</string>
<string name="cashu_p2pk_section">Nutzap-nyckel (avancerat)</string>
<string name="cashu_p2pk_explainer">En separat privat nyckel som endast används för att ta emot NIP-61-nutzaps. Inte din Nostr-identitetsnyckel.</string>
<string name="cashu_p2pk_autogen">Generera en ny nyckel</string>
@@ -2105,6 +2451,7 @@
<string name="profile_ui_setting_app_recommendations">App-rekommendationer</string>
<string name="profile_ui_setting_zap_received_feed">Mottagna zaps-flöde</string>
<string name="profile_ui_setting_followers_feed">Följarflöde</string>
<string name="profile_ui_setting_onchain_wallet">Bitcoin-plånbok (on-chain)</string>
<string name="reactions_settings">Reaktionsinställningar</string>
<string name="reactions_settings_description">Konfigurera vilka reaktionsknappar som visas, deras ordning och om räknare ska visas.</string>
<string name="reactions_settings_enabled">Aktiverad</string>
@@ -2253,6 +2600,9 @@
<string name="forked_from">Forkad från</string>
<string name="git_web_address">Webbplats:</string>
<string name="git_clone_address">Klona:</string>
<string name="git_branch">Gren</string>
<string name="git_merge_base">Mergebas</string>
<string name="git_pr_update_description">Uppdaterade pull request till en ny commit.</string>
<string name="git_status_open">Öppen</string>
<string name="git_status_merged">Sammanfogad</string>
<string name="git_status_closed">Stängd</string>
@@ -2260,11 +2610,77 @@
<string name="git_repo_tab_overview">Översikt</string>
<string name="git_repo_tab_issues">Ärenden</string>
<string name="git_repo_tab_patches">Patchar och PR</string>
<string name="git_repo_filter_open">Öppna</string>
<string name="git_repo_filter_closed">Stängda &amp; lösta</string>
<string name="git_repo_label_all">Alla</string>
<string name="git_repo_bookmark">Bokmärk repository</string>
<string name="git_repo_stat_branches">Grenar</string>
<string name="git_repo_stat_tags">Taggar</string>
<string name="git_repo_stat_files">Filer</string>
<string name="git_repo_stat_updated">Uppdaterad</string>
<string name="git_repo_recent_activity">Senaste aktivitet</string>
<string name="git_repo_maintained_by">Underhålls av</string>
<string name="git_repo_external_host_title">Hostat externt</string>
<string name="git_repo_external_host_body">Det här repositoryt kan inte klonas över http(s), så kodvyn är inte tillgänglig här.</string>
<string name="git_repo_open_in_browser">Öppna i webbläsare</string>
<string name="git_untitled">Namnlös</string>
<string name="git_repo_section_about">Om</string>
<string name="git_repo_section_links">Länkar</string>
<string name="git_repo_section_maintainers">Underhållare</string>
<string name="git_repo_section_topics">Ämnen</string>
<string name="git_repo_personal_fork">Personlig fork</string>
<string name="git_repo_tab_code">Kod</string>
<string name="git_repo_code_loading">Läser in repository…</string>
<string name="git_repo_code_error">Det gick inte att läsa in repositoryt från dess klon-URL.</string>
<string name="git_repo_no_clone_url">Den här repository-annonseringen har ingen http(s)-klon-URL att bläddra i.</string>
<string name="git_repo_readme_missing">Det här repositoryt har ingen README-fil.</string>
<string name="git_repo_file_load_error">Det gick inte att läsa in den här filen.</string>
<string name="git_repo_binary_file">Binär fil (%1$s) — förhandsvisning ej tillgänglig.</string>
<string name="git_repo_empty_folder">Den här mappen är tom.</string>
<string name="git_repo_root">rot</string>
<string name="git_repo_retry">Försök igen</string>
<string name="git_repo_default_branch">standard</string>
<string name="git_repo_branches">Grenar</string>
<string name="git_repo_tags">Taggar</string>
<string name="git_repo_search_files">Sök filer…</string>
<string name="git_repo_no_search_results">Inga matchande filer.</string>
<string name="git_repo_no_commits">Ingen commit-historik tillgänglig.</string>
<string name="git_repo_copy_file">Kopiera filinnehåll</string>
<plurals name="git_repo_item_count">
<item quantity="one">%1$d objekt</item>
<item quantity="other">%1$d objekt</item>
</plurals>
<plurals name="git_diff_files_changed">
<item quantity="one">%1$d fil ändrad</item>
<item quantity="other">%1$d filer ändrade</item>
</plurals>
<string name="git_diff_binary">Binär fil visas inte.</string>
<string name="git_new_issue_button">Ny</string>
<string name="git_new_issue_title">Nytt ärende</string>
<string name="git_new_issue_subject">Titel</string>
<string name="git_new_issue_body">Beskrivning</string>
<string name="git_new_issue_create">Skapa</string>
<string name="git_new_issue_cancel">Avbryt</string>
<string name="git_new_issue_labels">Etiketter</string>
<string name="git_new_issue_labels_hint">bugg, förbättring…</string>
<string name="git_issue_close">Stäng ärende</string>
<string name="git_issue_reopen">Öppna igen</string>
<string name="git_status_close">Stäng</string>
<string name="git_status_reopen">Öppna igen</string>
<string name="git_status_mark_merged">Markera som mergad</string>
<string name="git_pr_view_changes">Visa ändringar</string>
<string name="git_pr_loading_changes">Läser in ändringar…</string>
<string name="git_pr_no_changes">Inga filändringar hittades.</string>
<string name="git_pr_changes_retry">Försök läsa in ändringar igen</string>
<string name="git_pr_revised">Reviderad</string>
<string name="git_repo_settings_title">Redigera repository</string>
<string name="git_repo_settings_name">Namn</string>
<string name="git_repo_settings_description">Beskrivning</string>
<string name="git_repo_settings_clone_urls">Klon-URL:er (en per rad)</string>
<string name="git_repo_settings_web_urls">Webb-URL:er (en per rad)</string>
<string name="git_repo_settings_topics">Ämnen (kommaseparerade)</string>
<string name="git_repo_settings_save">Spara</string>
<string name="git_repositories">Git-repositories</string>
<string name="nsite_title">Statisk webbplats: %1$s</string>
<string name="napplet_card_permissions">Behörigheter:</string>
<string name="profile_tab_apps">Appar &amp; webbplatser</string>
@@ -2554,6 +2970,7 @@
<string name="kind_git_patch">Git-patch</string>
<string name="kind_git_repo">Git-repository</string>
<string name="kind_git_reply">Git-svar</string>
<string name="kind_git_pr_update">PR-uppdatering</string>
<string name="kind_zap_goals">Zap-mål</string>
<string name="kind_hashtag_follows">Följda hashtaggar</string>
<string name="kind_highlights">Höjdpunkter</string>
@@ -2836,6 +3253,7 @@
<string name="goal_progress">%1$s finansierat av %2$s sats mål</string>
<string name="fundraiser_ends">Slutar %1$s</string>
<string name="fundraiser_onchain_donation">On-chain-donation</string>
<string name="bird_detection_title">Fågeldetektering</string>
<plurals name="birdex_species_count">
<item quantity="one">Birdex · %1$d art</item>
<item quantity="other">Birdex · %1$d arter</item>
@@ -2845,6 +3263,8 @@
<item quantity="other">%1$s +%2$d till</item>
</plurals>
<!-- PS1 memory-card saves over nostr (kind 38192). "PS1" is the PlayStation 1, do not translate. -->
<string name="ps1_save_title">PS1-minneskortsparning</string>
<string name="ps1_save_empty_slot">Tom plats</string>
<!-- Roadstr road event reports (kinds 1315/1316). "Roadstr" is a proper noun, do not translate. -->
<string name="road_event_police">Polis</string>
<string name="road_event_speed_camera">Fartkamera</string>
@@ -2973,6 +3393,82 @@
<string name="compose_settings">Skrivinställningar</string>
<string name="auto_create_drafts_setting_title">Skapa utkast automatiskt</string>
<string name="auto_create_drafts_setting_description">Sparar ett utkast automatiskt när du skriver eller lämnar redigeraren med osänd text och skickar det till dina privata utgående reläer.</string>
<string name="compose_signature_setting_title">Signatur</string>
<string name="compose_signature_setting_description">Läggs till i slutet av meddelandet när du öppnar ett nytt inlägg, svar, citat eller artikel. Lämna tomt för att inaktivera.</string>
<string name="compose_signature_setting_hint">Din signatur</string>
<string name="pow_settings_title">Bevis på arbete</string>
<string name="pow_difficulty_title">Svårighetsgrad</string>
<string name="pow_difficulty_explainer">Minar ett NIP-13-bevis på arbete i dina inlägg innan de publiceras så att reläer och läsare kan väga dem mot spam. Högre värden tar exponentiellt längre tid att mina. Inlägg publiceras i bakgrunden när de är minade.</string>
<string name="pow_difficulty_off">Av</string>
<string name="pow_custom_difficulty_title">Anpassad svårighetsgrad</string>
<string name="pow_custom_difficulty_explainer">Finjustera målet i inledande nollbitar.</string>
<string name="pow_categories_title">Vad som ska minas</string>
<string name="pow_categories_explainer">Tidskritiska händelser (relä-autentisering, zap-förfrågningar, plånboks- och signerarmeddelanden, utkast, listor) minas aldrig.</string>
<string name="pow_category_short_notes">Korta notiser &amp; svar</string>
<string name="pow_category_short_notes_explainer">Den primära offentliga spamytan</string>
<string name="pow_category_comments">Kommentarer</string>
<string name="pow_category_comments_explainer">Svar på artiklar, filer och annat innehåll</string>
<string name="pow_category_reports">Rapporter</string>
<string name="pow_category_reports_explainer">Reläer väger rapporter efter deras kostnad</string>
<string name="pow_category_long_form">Långform &amp; höjdpunkter</string>
<string name="pow_category_long_form_explainer">Artiklar och höjdpunkter; sällsynta, kostnaden är försumbar</string>
<string name="pow_category_voice">Röstmeddelanden</string>
<string name="pow_category_voice_explainer">Offentliga röstinlägg och svar</string>
<string name="pow_category_reposts">Reposter</string>
<string name="pow_category_reposts_explainer">Hög volym för aktiva användare</string>
<string name="pow_category_reactions">Reaktioner</string>
<string name="pow_category_reactions_explainer">Den mest högvolymiga typen; att mina varje gillning kostar batteri</string>
<string name="pow_category_public_chat">Offentlig &amp; livechatt</string>
<string name="pow_category_public_chat_explainer">Miningfördröjningar skadar konversationsflödet</string>
<string name="pow_category_gift_wraps">Omslag för privata meddelanden</string>
<string name="pow_category_gift_wraps_explainer">Låter DM-reläer filtrera inkorgsspam; endast det yttre omslaget minas, aldrig ditt meddelande</string>
<string name="pow_category_other_public">Annat offentligt innehåll</string>
<string name="pow_category_other_public_explainer">Omröstningar, livestatus, radannonser och allt annat offentligt</string>
<string name="pow_mining_title">Minar bevis på arbete</string>
<plurals name="pow_mining_progress">
<item quantity="one">Minar bevis på arbete… (%1$d inlägg i kön)</item>
<item quantity="other">Minar bevis på arbete… (%1$d inlägg i kön)</item>
</plurals>
<plurals name="pow_mining_job">
<item quantity="one">%1$s • minar vid %2$d bit</item>
<item quantity="other">%1$s • minar vid %2$d bitar</item>
</plurals>
<plurals name="pow_queued_job">
<item quantity="one">%1$s • väntar på att minas vid %2$d bit</item>
<item quantity="other">%1$s • väntar på att minas vid %2$d bitar</item>
</plurals>
<plurals name="pow_option_default_on">
<item quantity="one">Standard (%1$d bit)</item>
<item quantity="other">Standard (%1$d bitar)</item>
</plurals>
<string name="pow_option_default_off">Standard (av)</string>
<string name="pow_option_off">Av för det här inlägget</string>
<string name="pow_notification_channel_name">Mining av bevis på arbete</string>
<string name="pow_notification_channel_description">Visar inlägg som fortfarande minar sitt NIP-13-bevis på arbete så att de kan slutföras efter att du lämnat appen.</string>
<string name="pow_notification_cancel_all">Avbryt</string>
<string name="pow_difficulty_estimate">≈ %1$s per inlägg på den här enheten</string>
<plurals name="pow_estimate_seconds">
<item quantity="one">%1$d sekund</item>
<item quantity="other">%1$d sekunder</item>
</plurals>
<plurals name="pow_estimate_minutes">
<item quantity="one">%1$d minut</item>
<item quantity="other">%1$d minuter</item>
</plurals>
<plurals name="pow_estimate_hours">
<item quantity="one">%1$d timme</item>
<item quantity="other">%1$d timmar</item>
</plurals>
<plurals name="pow_estimate_days">
<item quantity="one">%1$d dag</item>
<item quantity="other">%1$d dagar</item>
</plurals>
<string name="pow_time_left">≈ %1$s kvar</string>
<string name="pow_time_left_soon">när som helst nu</string>
<string name="pow_publish_failed">Ditt %1$s slutförde miningen men kunde inte publiceras: %2$s</string>
<string name="pow_publish_failed_retry">Ditt %1$s slutförde miningen men kunde inte publiceras. Det görs ett nytt försök nästa gång appen startar.</string>
<string name="pow_kind_chat_message">Chattmeddelande</string>
<string name="pow_kind_report">Rapport</string>
<string name="ai_writing_use_this">Använd detta</string>
<string name="ai_writing_dismiss">Avvisa</string>
<string name="ai_tone_correct">Korrigera</string>
@@ -3055,6 +3551,10 @@
<string name="marmot_no_invitations">Inga inbjudningar</string>
<string name="marmot_no_invitations_desc">När någon lägger till dig i en grupp visas det här tills du svarar.</string>
<string name="marmot_no_messages_yet">Inga meddelanden ännu</string>
<plurals name="marmot_message_count">
<item quantity="one">%1$d medd</item>
<item quantity="other">%1$d medd</item>
</plurals>
<plurals name="marmot_member_count">
<item quantity="one">%1$d medlem</item>
<item quantity="other">%1$d medlemmar</item>
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.amethyst.service.relayClient.authCommand.model
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
/**
* The per-account NIP-42 signing gate: on the shared client, an account signs a relay's AUTH only
* when the relay is in its own relay list, or it is publishing its own event there. The bug these
* lock down: an unpaid/bystander account being AUTH'd (and billed by inbox.nostr.wine) purely
* because another account uses that relay including via a merged filter that names it.
*/
class RelayAuthFirstPartyTest {
private val relay = NormalizedRelayUrl("wss://inbox.nostr.wine/")
private val me = "a".repeat(64)
private val other = "b".repeat(64)
private fun event(pubkey: String) =
Event(
id = "0".repeat(64),
pubKey = pubkey,
createdAt = 0,
kind = 1059,
tags = emptyArray(),
content = "",
sig = "",
)
@Test
fun aRelayNotInMyListWithNothingOfMineIsNotFirstParty() {
// The exact inbox.nostr.wine case: a relay another account uses, which a merged read filter
// names me on, but which is in none of my lists and where I publish nothing → must NOT sign.
assertFalse(RelayAuthFirstParty.hasReason(me, relay, emptyList(), emptySet()))
}
@Test
fun publishingSomeoneElsesEventIsNotFirstParty() {
assertFalse(RelayAuthFirstParty.hasReason(me, relay, listOf(event(other)), emptySet()))
}
@Test
fun aRelayIConfiguredIsFirstParty() {
// Own inbox/outbox reads qualify this way: the relay serving them is in my own relay list.
assertTrue(RelayAuthFirstParty.hasReason(me, relay, emptyList(), setOf(relay)))
}
@Test
fun publishingMyOwnEventIsFirstParty() {
// Delivering my own DM/post to the recipient's relay, even one not in my list.
assertTrue(RelayAuthFirstParty.hasReason(me, relay, listOf(event(me)), emptySet()))
}
}
-53
View File
@@ -45,50 +45,6 @@ plugins {
alias(libs.plugins.androidKotlinMultiplatformLibrary) apply false
alias(libs.plugins.serialization)
alias(libs.plugins.googleKsp) apply false
alias(libs.plugins.kotlinxKover)
}
// Aggregated code coverage: `./gradlew koverXmlReportCoverage` runs the unit
// test suites of the modules below and merges their coverage into
// build/reports/kover/reportCoverage.xml (JaCoCo-compatible XML, importable by
// SonarQube — see BUILDING.md). `koverHtmlReportCoverage` renders the same
// data for humans. A named variant is used instead of Kover's default total
// report because the total for an Android project unconditionally merges
// EVERY build variant — compiling all release/benchmark variants of
// :amethyst just to measure unit tests. The "coverage" variant below picks
// one representative compilation per project: the `jvm` target for KMP/JVM
// modules and `playDebug` for :amethyst — play is the primary flavor and the
// larger code surface (both `add`s are optional so the one block fits every
// project). :nappletHost stays out — it has no tests.
dependencies {
kover(project(":amethyst"))
kover(project(":quartz"))
kover(project(":commons"))
kover(project(":quic"))
kover(project(":nestsClient"))
kover(project(":geode"))
kover(project(":cli"))
kover(project(":relayBench"))
kover(project(":desktopApp"))
}
kover {
currentProject {
createVariant("coverage") {}
}
}
subprojects {
plugins.withId("org.jetbrains.kotlinx.kover") {
configure<kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension> {
currentProject {
createVariant("coverage") {
add("jvm", optional = true)
add("playDebug", optional = true)
}
}
}
}
}
// Shared app version for all subprojects — read from gradle/libs.versions.toml.
@@ -164,15 +120,6 @@ if (sonarEnabled) {
.filter { it.startsWith("sonar.") }
.forEach { System.setProperty(it, sonarProperties.getProperty(it)) }
// Import Kover's aggregated coverage (run `./gradlew koverXmlReportCoverage`
// first) unless the operator pointed the scanner somewhere else.
if (System.getProperty("sonar.coverage.jacoco.xmlReportPaths") == null) {
System.setProperty(
"sonar.coverage.jacoco.xmlReportPaths",
layout.buildDirectory.file("reports/kover/reportCoverage.xml").get().asFile.absolutePath,
)
}
// The scanner's sonarResolver task reads AGP's generated-res-values provider
// but doesn't depend on the task that produces it — wire it up in every
// module that has both (today only :amethyst enables resValues, but the
-1
View File
@@ -3,7 +3,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.jetbrainsKotlinJvm)
application
alias(libs.plugins.kotlinxKover)
}
kotlin {
-1
View File
@@ -25,7 +25,6 @@ plugins {
alias(libs.plugins.jetbrainsComposeCompiler)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.serialization)
alias(libs.plugins.kotlinxKover)
}
kotlin {
@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.commons.blurhash
import android.graphics.Bitmap
import androidx.core.graphics.scale
actual class PlatformImage(
val bitmap: Bitmap,
@@ -43,7 +44,7 @@ actual class PlatformImage(
actual fun scale(
width: Int,
height: Int,
): PlatformImage = PlatformImage(Bitmap.createScaledBitmap(bitmap, width, height, false))
): PlatformImage = PlatformImage(bitmap.scale(width, height, false))
actual companion object {
actual fun create(
@@ -21,6 +21,7 @@
package com.vitorpamplona.amethyst.commons.keystorage
import android.content.Context
import androidx.core.content.edit
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import kotlinx.coroutines.Dispatchers
@@ -86,7 +87,7 @@ actual class SecureKeyStorage private actual constructor() {
) {
withContext(Dispatchers.IO) {
try {
encryptedPrefs.edit().putString(KEY_PREFIX + npub, privKeyHex).apply()
encryptedPrefs.edit { putString(KEY_PREFIX + npub, privKeyHex) }
} catch (e: Exception) {
throw SecureStorageException("Failed to save private key", e)
}
@@ -108,7 +109,7 @@ actual class SecureKeyStorage private actual constructor() {
val key = KEY_PREFIX + npub
val existed = encryptedPrefs.contains(key)
if (existed) {
encryptedPrefs.edit().remove(key).apply()
encryptedPrefs.edit { remove(key) }
}
existed
} catch (e: Exception) {
@@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.commons.nip64Chess
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
actual class ChessDismissedGamesStorage private actual constructor() {
private var prefs: SharedPreferences? = null
@@ -48,6 +49,6 @@ actual class ChessDismissedGamesStorage private actual constructor() {
userPubkey: String,
ids: Set<String>,
) {
prefs?.edit()?.putStringSet(prefsKey(userPubkey), ids)?.apply()
prefs?.edit { putStringSet(prefsKey(userPubkey), ids) }
}
}
-1
View File
@@ -6,7 +6,6 @@ plugins {
alias(libs.plugins.jetbrainsKotlinJvm)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.jetbrainsComposeCompiler)
alias(libs.plugins.kotlinxKover)
}
// RPM rejects dashes in version strings — replace with tilde (~) which RPM uses
+12 -10
View File
@@ -134,6 +134,12 @@
"Hindi"
]
},
{
"user": "StellarStoic",
"languages": [
"Slovenian"
]
},
{
"user": "summoner001",
"languages": [
@@ -146,12 +152,6 @@
"Chinese Simplified"
]
},
{
"user": "StellarStoic",
"languages": [
"Slovenian"
]
},
{
"user": "anthony-robin",
"languages": [
@@ -178,6 +178,12 @@
"Spanish, United States"
]
},
{
"user": "davotoula",
"languages": [
"Czech"
]
},
{
"user": "greenart7c3",
"languages": []
@@ -242,10 +248,6 @@
"user": "adhrasreoshiathoi",
"languages": []
},
{
"user": "davotoula",
"languages": []
},
{
"user": "crackadoo",
"languages": []
-1
View File
@@ -5,7 +5,6 @@ plugins {
alias(libs.plugins.serialization)
application
`java-test-fixtures`
alias(libs.plugins.kotlinxKover)
}
application {
-2
View File
@@ -35,7 +35,6 @@ kmpTorResource = "409.5.0"
junit = "4.13.2"
kchesslib = "1.0.5"
kotlin = "2.4.0"
kover = "0.9.8"
kotlinxCollectionsImmutable = "0.5.0"
kotlinxCoroutinesCore = "1.11.0"
kotlinxSerialization = "1.11.0"
@@ -247,7 +246,6 @@ jetbrainsKotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
jetbrainsComposeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
serialization = { id = 'org.jetbrains.kotlin.plugin.serialization', version.ref = 'kotlin' }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlinxKover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
androidKotlinMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
vanniktech-mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" }
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" }
@@ -54,6 +54,8 @@ import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets
import androidx.core.graphics.scale
import androidx.core.net.toUri
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.webkit.JavaScriptReplyProxy
@@ -456,7 +458,7 @@ class NappletBrowserActivity : ComponentActivity() {
runCatching {
val scaled =
if (icon.width > ICON_MAX_PX || icon.height > ICON_MAX_PX) {
Bitmap.createScaledBitmap(icon, ICON_MAX_PX, ICON_MAX_PX, true)
icon.scale(ICON_MAX_PX, ICON_MAX_PX)
} else {
icon
}
@@ -597,7 +599,7 @@ class NappletBrowserActivity : ComponentActivity() {
// Key the persisted choice on the host actually displayed (which may differ from startUrl after
// in-page navigation), so the preference sticks to the right site.
val liveUrl = if (this::webView.isInitialized) webView.url ?: startUrl else startUrl
val host = runCatching { Uri.parse(liveUrl).host }.getOrNull()?.takeIf { it.isNotBlank() } ?: return
val host = runCatching { liveUrl.toUri().host }.getOrNull()?.takeIf { it.isNotBlank() } ?: return
val msg =
Message.obtain(null, NappletIpc.MSG_SET_WEB_TOR).apply {
data =
@@ -613,7 +615,7 @@ class NappletBrowserActivity : ComponentActivity() {
private var title: String = ""
private fun barTitle(): String = title.ifBlank { runCatching { Uri.parse(startUrl).host }.getOrNull() ?: getString(CommonsR.string.napplet_untitled) }
private fun barTitle(): String = title.ifBlank { runCatching { startUrl.toUri().host }.getOrNull() ?: getString(CommonsR.string.napplet_untitled) }
/**
* The top pull-down sheet: a small grabber at the top edge (out of the corner where a site shows its
@@ -644,7 +646,7 @@ class NappletBrowserActivity : ComponentActivity() {
*/
private fun openPermissions() {
val liveUrl = if (this::webView.isInitialized) webView.url ?: startUrl else startUrl
val uri = runCatching { Uri.parse(liveUrl) }.getOrNull() ?: return
val uri = runCatching { liveUrl.toUri() }.getOrNull() ?: return
val scheme = uri.scheme?.takeIf { it.isNotBlank() } ?: return
val host = uri.host?.takeIf { it.isNotBlank() } ?: return
val origin = "$scheme://$host" + if (uri.port > 0) ":${uri.port}" else ""
@@ -774,6 +776,6 @@ class NappletBrowserActivity : ComponentActivity() {
.putExtra(EXTRA_THEME, theme)
.putExtra(EXTRA_IS_FAVORITE, isFavorite)
// Distinct task identity per URL for documentLaunchMode=intoExisting.
.setData(Uri.parse(url))
.setData(url.toUri())
}
}
@@ -45,6 +45,7 @@ import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import androidx.core.graphics.createBitmap
import androidx.privacysandbox.ui.provider.toCoreLibInfo
import androidx.webkit.JavaScriptReplyProxy
import androidx.webkit.WebMessageCompat
@@ -206,7 +207,7 @@ class NappletBrowserService : Service() {
val outW = (boxW * zoom).toInt().coerceAtLeast(1)
val outH = (boxH * zoom).toInt().coerceAtLeast(1)
val t0 = SystemClock.elapsedRealtimeNanos()
val bitmap = Bitmap.createBitmap(outW, outH, Bitmap.Config.ARGB_8888)
val bitmap = createBitmap(outW, outH)
val canvas = Canvas(bitmap)
canvas.drawColor(tab.bgColor)
// Map the source rect (centered on cx,cy in view px) into the zoomed output bitmap.
@@ -45,6 +45,7 @@ import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import androidx.core.graphics.createBitmap
import androidx.privacysandbox.ui.provider.toCoreLibInfo
import androidx.webkit.JavaScriptReplyProxy
import androidx.webkit.ProxyConfig
@@ -238,7 +239,7 @@ class NappletHostService : Service() {
val outW = (boxW * zoom).toInt().coerceAtLeast(1)
val outH = (boxH * zoom).toInt().coerceAtLeast(1)
val t0 = SystemClock.elapsedRealtimeNanos()
val bitmap = Bitmap.createBitmap(outW, outH, Bitmap.Config.ARGB_8888)
val bitmap = createBitmap(outW, outH)
val canvas = Canvas(bitmap)
canvas.drawColor(tab.bgColor)
canvas.scale(zoom, zoom)
-1
View File
@@ -5,7 +5,6 @@ plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidKotlinMultiplatformLibrary)
alias(libs.plugins.serialization)
alias(libs.plugins.kotlinxKover)
}
kotlin {
-1
View File
@@ -9,7 +9,6 @@ plugins {
alias(libs.plugins.androidKotlinMultiplatformLibrary)
alias(libs.plugins.serialization)
alias(libs.plugins.vanniktech.mavenPublish)
alias(libs.plugins.kotlinxKover)
}
kotlin {
-1
View File
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidKotlinMultiplatformLibrary)
alias(libs.plugins.kotlinxKover)
}
kotlin {
-1
View File
@@ -3,7 +3,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
alias(libs.plugins.jetbrainsKotlinJvm)
application
alias(libs.plugins.kotlinxKover)
}
application {