hermes-agent/locales/af.yaml
Siddharth Balyan 7ba5df0d52
feat(billing): /credits command — balance + portal top-up handoff (#44776)
* feat(billing): /usage → portal top-up browser handoff

Add the terminal side of the billing slice (phase 2a): start a top-up by
throwing the user to the portal billing page with the top-up modal open. The
terminal does not confirm, poll, or track payment — checkout completes in the
browser and the next /usage shows the new balance.

- nous_account.py: parse organisation.slug/name from /api/oauth/account into
  NousPortalAccountInfo; add nous_portal_topup_url() building the org-pinned
  {base}/orgs/{slug}/billing?topup=open with a null-slug fallback to the legacy
  {base}/billing?topup=open (never /orgs/None/...).
- portal_cli.py: 'hermes portal topup' — fresh account fetch, identity line
  (Topping up as <email> / org <name>), browser open with printed-URL fallback,
  no-wait closing copy. No polling/confirmation (deferred to 2b).
- account_usage.py: the shared /usage credits block now links the org-pinned
  top-up URL (auto-opens the modal) + points to the command.

Depends on NAS #409 (organisation.slug/name + ?topup=open). Do not merge until
that is live on the target env; until then /api/oauth/account returns
organisation: { id } only and the URL falls back to legacy.

* feat(billing): /credits command for balance + top-up handoff

Replace the standalone `hermes portal topup` subcommand with an in-session
/credits slash command — a focused money surface (balance in, top-up out) that
works in the CLI, TUI, and every messaging platform from one registry entry.

- commands.py: register /credits (Info category). Slack is at its 50-slash cap,
  so /credits is routed via /hermes credits on Slack only (new
  _SLACK_VIA_HERMES_ONLY set) to avoid clamping a canonical command off the
  native list and breaking Telegram parity; native everywhere else.
- account_usage.py: build_credits_view() — one portal fetch → balance lines +
  identity line + org-pinned top-up URL + depleted flag, consumed by all
  surfaces. Reuses the same snapshot/URL builder as /usage so numbers match.
- cli.py: _show_credits() — balance block + identity line + 3-button panel
  (Open top-up / Copy link / Cancel) via the existing prompt_toolkit modal.
  ASK, never auto-launch; headless falls back to printing the URL.
- gateway/slash_commands.py: _handle_credits_command() — renders the block +
  tappable top-up URL + no-wait copy; works on button and plain-text platforms.
- /usage credits line now points to /credits.
- Retire `hermes portal topup` (portal_cli.py back to baseline); the engine
  (slug/name parse + nous_portal_topup_url) stays as the shared core.

No polling, no payment confirmation (billing phase 2a). Depends on NAS #409.

* fix(credits): /credits works in the TUI slash-worker (non-interactive)

In the TUI, /credits runs in the slash-worker subprocess where there is no
live prompt_toolkit app and stdin is the JSON-RPC pipe. _show_credits called
the 3-button modal unconditionally, which fell back to reading stdin →
exception → slash.exec rejected → the command produced no output (only the
pre-existing 'Credit access paused' banner showed).

- _show_credits: when self._app is None (TUI worker / piped / non-interactive),
  render the text variant — balance block + tappable top-up URL + no-wait line,
  same affordance as the messaging surfaces — and skip the modal entirely. The
  3-button panel still renders in the interactive CLI.
- Depleted banner copy: 'run /usage for balance' → 'run /credits to top up'
  now that /credits is the dedicated money surface (+ tests).
- Regression tests: _show_credits with self._app=None renders text and never
  invokes the modal; logged-out path.

* feat(tui): credits.view RPC for the /credits tappable top-up button

Add a credits.view JSON-RPC method returning the structured CreditsView
(logged_in, balance_lines, identity_line, topup_url, depleted) so the TUI can
render a clickable <Link> top-up button instead of plain text. Account-
independent (portal fetch gated on a logged-in Nous account), fail-open to
{logged_in: false} on any hiccup. Mirrors session.usage's credits-block pattern.

Frontend (TUI-local /credits command + Ink component) lands separately.

* feat(tui): /credits command with keyboard-driven top-up confirm

TUI-local /credits: fetches the structured balance via the credits.view RPC,
prints the balance + identity + top-up URL, then arms the EXISTING confirm
overlay (Enter = open top-up in browser via openExternalUrl, Esc = cancel).
Reuses ConfirmReq — no new overlay component/state/input handler. Headless
(openExternalUrl returns false) falls back to printing the URL.

- gatewayTypes.ts: CreditsViewResponse.
- commands/credits.ts: the command (mirrors /status's rpc+guarded pattern).
- registry.ts: register creditsCommands.
- test: balance+overlay armed, headless fallback, no-url, logged-out (4 cases).

Matches the CLI /credits 'Enter to open' affordance. Phase 2a: no polling.
2026-06-12 08:51:10 +00:00

374 lines
26 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Hermes statiese boodskap-katalogus -- Afrikaans
# See locales/en.yaml for the source of truth; keep keys in sync.
approval:
dangerous_header: "⚠️ GEVAARLIKE OPDRAG: {description}"
choose_long: " [o]eenmalig | [s]sessie | [a]altyd | [d]weier"
choose_short: " [o]eenmalig | [s]sessie | [d]weier"
prompt_long: " Keuse [o/s/a/D]: "
prompt_short: " Keuse [o/s/D]: "
timeout: " ⏱ Tyd verstreke - opdrag word geweier"
allowed_once: " ✓ Eenmalig toegelaat"
allowed_session: " ✓ Vir hierdie sessie toegelaat"
allowed_always: " ✓ By permanente toelaatlys gevoeg"
denied: " ✗ Geweier"
cancelled: " ✗ Gekanselleer"
blocklist_message: "Hierdie opdrag is op die onvoorwaardelike blokkeerlys en kan nie goedgekeur word nie."
gateway:
approval_expired: "⚠️ Goedkeuring het verval (die agent wag nie meer nie). Vra die agent om weer te probeer."
draining: "⏳ Wag vir {count} aktiewe agent(e) voor herbegin..."
goal_cleared: "✓ Doelwit verwyder."
no_active_goal: "Geen aktiewe doelwit nie."
config_read_failed: "⚠️ Kon nie config.yaml lees nie: {error}"
config_save_failed: "⚠️ Kon nie konfigurasie stoor nie: {error}"
model:
error_prefix: "Fout: {error}"
switched: "Model verander na `{model}`"
provider_label: "Verskaffer: {provider}"
context_label: "Konteks: {tokens} tokens"
max_output_label: "Maks. uitvoer: {tokens} tokens"
cost_label: "Koste: {cost}"
capabilities_label: "Vermoëns: {capabilities}"
prompt_caching_enabled: "Prompt-kasing: geaktiveer"
warning_prefix: "Waarskuwing: {warning}"
saved_global: "Gestoor in config.yaml (`--global`)"
session_only_hint: "_(slegs sessie — voeg `--global` by om permanent te stoor)_"
current_label: "Huidig: `{model}` op {provider}"
current_tag: " (huidig)"
more_models_suffix: " (+{count} meer)"
usage_switch_model: "`/model <name>` — verander model"
usage_switch_provider: "`/model <name> --provider <slug>` — verander verskaffer"
usage_persist: "`/model <name> --global` — stoor permanent"
agents:
header: "🤖 **Aktiewe Agente & Take**"
active_agents: "**Aktiewe agente:** {count}"
this_chat: " · hierdie geselsie"
more: "... en nog {count}"
running_processes: "**Lopende agtergrondprosesse:** {count}"
async_jobs: "**Asinchrone werke van die gateway:** {count}"
none: "Geen aktiewe agente of lopende take nie."
state_starting: "begin"
state_running: "loop"
approve:
no_pending: "Geen hangende opdrag om goed te keur nie."
once_singular: "✅ Opdrag goedgekeur. Die agent gaan voort..."
once_plural: "✅ Opdragte goedgekeur ({count} opdragte). Die agent gaan voort..."
session_singular: "✅ Opdrag goedgekeur (patroon goedgekeur vir hierdie sessie). Die agent gaan voort..."
session_plural: "✅ Opdragte goedgekeur (patroon goedgekeur vir hierdie sessie) ({count} opdragte). Die agent gaan voort..."
always_singular: "✅ Opdrag goedgekeur (patroon permanent goedgekeur). Die agent gaan voort..."
always_plural: "✅ Opdragte goedgekeur (patroon permanent goedgekeur) ({count} opdragte). Die agent gaan voort..."
background:
usage: "Gebruik: /background <prompt>\nVoorbeeld: /background Som vandag se top HN-stories op\n\nVoer die prompt in 'n aparte sessie uit. Jy kan aanhou gesels — die resultaat verskyn hier wanneer dit klaar is."
started: "🔄 Agtergrondtaak begin: \"{preview}\"\nTaak-ID: {task_id}\nJy kan aanhou gesels — resultate verskyn hier wanneer dit klaar is."
branch:
db_unavailable: "Sessie-databasis is nie beskikbaar nie."
no_conversation: "Geen gesprek om te vertak nie — stuur eers 'n boodskap."
create_failed: "Kon nie tak skep nie: {error}"
switch_failed: "Tak is geskep, maar oorskakeling het misluk."
branched_one: "⑂ Vertak na **{title}** ({count} boodskap gekopieer)\nOorspronklik: `{parent}`\nTak: `{new}`\nGebruik `/resume` om terug te gaan na die oorspronklike."
branched_many: "⑂ Vertak na **{title}** ({count} boodskappe gekopieer)\nOorspronklik: `{parent}`\nTak: `{new}`\nGebruik `/resume` om terug te gaan na die oorspronklike."
commands:
usage: "Gebruik: `/commands [page]`"
skill_header: "⚡ **Vaardigheidsopdragte**:"
default_desc: "Vaardigheidsopdrag"
none: "Geen opdragte beskikbaar nie."
header: "📚 **Opdragte** ({total} altesaam, bladsy {page}/{total_pages})"
nav_prev: "`/commands {page}` ← vorige"
nav_next: "volgende → `/commands {page}`"
out_of_range: "_(Versoekte bladsy {requested} was buite reikwydte; bladsy {page} word vertoon.)_"
compress:
not_enough: "Nie genoeg gesprek om saam te pers nie (ten minste 4 boodskappe nodig)."
no_provider: "Geen verskaffer opgestel nie -- kan nie saampers nie."
nothing_to_do: "Niks om saam te pers nie (die transkripsie is steeds heeltemal beskermde konteks)."
focus_line: "Fokus: \"{topic}\""
summary_failed: "⚠️ Opsomming kon nie gegenereer word nie ({error}). {count} historiese boodskap(pe) is verwyder en met 'n plekhouer vervang; vroeëre konteks kan nie meer herstel word nie. Oorweeg om jou auxiliary.compression-modelopstelling na te gaan."
aborted: "⚠️ Kompressie gestaak ({error}). Geen boodskappe is laat val nie — die gesprek is onveranderd. Voer /compress uit om weer te probeer, /reset vir 'n skoon sessie, of kyk na jou auxiliary.compression-modelkonfigurasie."
aux_failed: " Opgestelde saamperseringsmodel `{model}` het misluk ({error}). Herstel met jou hoofmodel — konteks is intakt — maar jy mag dalk `auxiliary.compression.model` in config.yaml wil nagaan."
failed: "Saampersing het misluk: {error}"
debug:
upload_failed: "✗ Kon nie ontfoutverslag oplaai nie: {error}"
header: "**Ontfoutverslag opgelaai:**"
auto_delete: "⏱ Plakke sal outomaties oor 6 uur uitgevee word."
full_logs_hint: "Vir volledige loglae, gebruik `hermes debug share` vanaf die CLI."
share_hint: "Deel hierdie skakels met die Hermes-span vir ondersteuning."
deny:
stale: "❌ Opdrag geweier (goedkeuring was verouderd)."
no_pending: "Geen hangende opdrag om te weier nie."
denied_singular: "❌ Opdrag geweier."
denied_plural: "❌ Opdragte geweier ({count} opdragte)."
fast:
not_supported: "⚡ /fast is slegs beskikbaar vir OpenAI-modelle wat Priority Processing ondersteun."
status: "⚡ Priority Processing\n\nHuidige modus: `{mode}`\n\n_Gebruik:_ `/fast <normal|fast|status>`"
unknown_arg: "⚠️ Onbekende argument: `{arg}`\n\n**Geldige opsies:** normal, fast, status"
saved: "⚡ ✓ Priority Processing: **{label}** (gestoor in konfigurasie)\n_(neem effek by die volgende boodskap)_"
session_only: "⚡ ✓ Priority Processing: **{label}** (slegs hierdie sessie)"
label_fast: "FAST"
label_normal: "NORMAL"
status_fast: "fast"
status_normal: "normal"
footer:
status: "📎 Looptyd-voetstuk: **{state}**\nVelde: `{fields}`\nPlatform: `{platform}`"
usage: "Gebruik: `/footer [on|off|status]`"
saved: "📎 Looptyd-voetstuk: **{state}**{example}\n_(globaal gestoor — neem effek by die volgende boodskap)_"
example_line: "\nVoorbeeld: `{preview}`"
state_on: "AAN"
state_off: "AF"
goal:
unavailable: "Doelwitte is nie beskikbaar in hierdie sessie nie."
no_goal_set: "Geen doelwit gestel nie."
paused: "⏸ Doelwit gepouse: {goal}"
no_resume: "Geen doelwit om voort te sit nie."
resumed: "▶ Doelwit hervat: {goal}\nStuur enige boodskap om voort te gaan, of wag — ek sal die volgende stap met die volgende beurt neem."
invalid: "Ongeldige doelwit: {error}"
set: "⊙ Doelwit gestel ({budget}-beurt-begroting): {goal}\nEk sal aanhou werk totdat die doelwit klaar is, jy dit pouseer/verwyder, of die begroting opgebruik is.\nBeheer: /goal status · /goal pause · /goal resume · /goal clear"
help:
header: "📖 **Hermes-opdragte**\n"
skill_header: "\n⚡ **Vaardigheidsopdragte** ({count} aktief):"
more_use_commands: "\n... en nog {count}. Gebruik `/commands` vir die volledige bladsy-lys."
insights:
invalid_days: "Ongeldige --days waarde: {value}"
error: "Fout met genereer van insigte: {error}"
kanban:
error_prefix: "⚠ kanban-fout: {error}"
subscribed_suffix: "(ingeteken — jy sal in kennis gestel word wanneer {task_id} voltooi of vasval)"
truncated_suffix: "… (afgekap; gebruik `hermes kanban …` in jou terminale vir volle uitvoer)"
no_output: "(geen uitvoer)"
personality:
none_configured: "Geen persoonlikhede opgestel in `{path}/config.yaml` nie"
header: "🎭 **Beskikbare Persoonlikhede**\n"
none_option: "• `none` — (geen persoonlikheidslaag)"
item: "• `{name}` — {preview}"
usage: "\nGebruik: `/personality <name>`"
save_failed: "⚠️ Kon nie persoonlikheidsverandering stoor nie: {error}"
cleared: "🎭 Persoonlikheid verwyder — basis-agentgedrag word gebruik.\n_(neem effek by die volgende boodskap)_"
set_to: "🎭 Persoonlikheid gestel op **{name}**\n_(neem effek by die volgende boodskap)_"
unknown: "Onbekende persoonlikheid: `{name}`\n\nBeskikbaar: {available}"
profile:
header: "👤 **Profiel:** `{profile}`"
home: "📂 **Tuiste:** `{home}`"
reasoning:
level_default: "medium (verstek)"
level_disabled: "none (gedeaktiveer)"
scope_session: "sessie-oorskryf"
scope_global: "globale konfigurasie"
status: "🧠 **Redenering-instellings**\n\n**Inspanning:** `{level}`\n**Bereik:** {scope}\n**Vertoon:** {display}\n\n_Gebruik:_ `/reasoning <none|minimal|low|medium|high|xhigh|reset|show|hide> [--global]`"
display_on: "aan ✓"
display_off: "af"
display_set_on: "🧠 ✓ Redenering-vertoon: **AAN**\nDie model se denke sal voor elke antwoord op **{platform}** vertoon word."
display_set_off: "🧠 ✓ Redenering-vertoon: **AF** vir **{platform}**"
reset_global_unsupported: "⚠️ `/reasoning reset --global` word nie ondersteun nie. Gebruik `/reasoning <level> --global` om die globale verstek te verander."
reset_done: "🧠 ✓ Sessie-redenering-oorskryf verwyder; val terug op globale konfigurasie."
unknown_arg: "⚠️ Onbekende argument: `{arg}`\n\n**Geldige vlakke:** none, minimal, low, medium, high, xhigh\n**Vertoon:** show, hide\n**Permanent:** voeg `--global` by om verby hierdie sessie te stoor"
set_global: "🧠 ✓ Redenering-inspanning gestel op `{effort}` (gestoor in konfigurasie)\n_(neem effek by die volgende boodskap)_"
set_global_save_failed: "🧠 ✓ Redenering-inspanning gestel op `{effort}` (slegs sessie — konfigurasie-stoor het misluk)\n_(neem effek by die volgende boodskap)_"
set_session: "🧠 ✓ Redenering-inspanning gestel op `{effort}` (slegs sessie — voeg `--global` by om permanent te stoor)\n_(neem effek by die volgende boodskap)_"
reload_mcp:
cancelled: "🟡 /reload-mcp gekanselleer. MCP-gereedskap onveranderd."
always_followup: " Toekomstige `/reload-mcp`-oproepe sal sonder bevestiging loop. Heraktiveer via `approvals.mcp_reload_confirm: true` in config.yaml."
confirm_prompt: "⚠️ **Bevestig /reload-mcp**\n\nOm MCP-bedieners te herlaai, herbou die gereedskapsstel vir hierdie sessie en **maak die verskaffer se prompt-kasie ongeldig** — die volgende boodskap sal alle invoertokens herstuur. Op modelle met lang konteks of hoë redenering kan dit duur wees.\n\nKies:\n• **Eenmaal Goedkeur** — herlaai nou\n• **Altyd Goedkeur** — herlaai nou en stop hierdie prompt permanent\n• **Kanselleer** — laat MCP-gereedskap onveranderd\n\n_Teks-alternatief: antwoord `/approve`, `/always`, of `/cancel`._"
header: "🔄 **MCP-bedieners herlaai**\n"
reconnected: "♻️ Herverbind: {names}"
added: " Bygevoeg: {names}"
removed: " Verwyder: {names}"
none_connected: "Geen MCP-bedieners verbind nie."
tools_available: "\n🔧 {tools} gereedskap beskikbaar van {servers} bediener(s)"
failed: "❌ MCP-herlaai het misluk: {error}"
reload_skills:
header: "🔄 **Vaardighede herlaai**\n"
no_new: "Geen nuwe vaardighede opgespoor nie."
total: "\n📚 {count} vaardigheid(e) beskikbaar"
added_header: " **Bygevoegde Vaardighede:**"
removed_header: " **Verwyderde Vaardighede:**"
item_with_desc: " - {name}: {desc}"
item_no_desc: " - {name}"
failed: "❌ Vaardigheids-herlaai het misluk: {error}"
reset:
header_default: "✨ Sessie herstel! Begin van voor."
header_new: "✨ Nuwe sessie begin!"
header_titled: "✨ Nuwe sessie begin: {title}"
title_rejected: "\n⚠ Titel verwerp: {error}"
title_error_untitled: "\n⚠ {error} — sessie sonder titel begin."
title_empty_untitled: "\n⚠ Titel is leeg na opruiming — sessie sonder titel begin."
tip: "\n✦ Wenk: {tip}"
restart:
in_progress: "⏳ Gateway-herbegin reeds aan die gang..."
restarting: "♻ Herbegin van gateway. As jy nie binne 60 sekondes in kennis gestel word nie, herbegin vanaf die konsole met `hermes gateway restart`."
resume:
db_unavailable: "Sessie-databasis is nie beskikbaar nie."
parse_error: "⚠️ Could not parse `/resume` arguments: {error}.
Use quotes around titles with spaces, for example: `/resume \"Project A Plan\"`."
matrix_no_named_sessions: "No named sessions found for this Matrix room.
Use `/title My Session` to name the current room session, `/resume --all` to list all Matrix sessions, or `/resume --cross-room <session name>` to explicitly cross room boundaries."
matrix_blocked_no_origin: "⚠️ Matrix /resume blocked: this named session has no recorded room origin, so Hermes will not resume it inside the current room by default. Use `/resume --cross-room {name}` if you intentionally want to cross room boundaries."
matrix_blocked_other_room: "⚠️ Matrix /resume blocked: that session belongs to a different Matrix room ({room}). Use `/resume --cross-room {name}` if you intentionally want to resume it here."
matrix_cross_room_success: "⚠️ Cross-room resume: resumed **{title}** inside Matrix room **{room}**.
Future messages in this room will use that transcript until `/reset` or another `/resume`.{msg_part}"
no_named_sessions: "Geen benoemde sessies gevind nie.\nGebruik `/title My Sessie` om jou huidige sessie 'n naam te gee, en dan `/resume My Sessie` om later daarheen terug te keer."
list_header: "📋 **Benoemde Sessies**\n"
list_item: "• **{title}**{preview_part}"
list_item_numbered: "{index}. **{title}**{preview_part}"
list_preview_suffix: " — _{preview}_"
list_footer: "\nGebruik: `/resume <session name>`"
list_footer_numbered: "\nGebruik: `/resume <sessienaam>` of `/resume <nommer>` (bv. `/resume 1` vir die mees onlangse)"
list_failed: "Kon nie sessies lys nie: {error}"
out_of_range: "Hervat-indeks {index} is buite bereik.\nGebruik `/resume` sonder argumente om beskikbare sessies te sien."
not_found: "Geen sessie gevind wat by '**{name}**' pas nie.\nGebruik `/resume` sonder argumente om beskikbare sessies te sien."
already_on: "📌 Reeds op sessie **{name}**."
switch_failed: "Kon nie sessie verander nie."
resumed_one: "↻ Sessie **{title}** hervat ({count} boodskap). Gesprek herstel."
resumed_many: "↻ Sessie **{title}** hervat ({count} boodskappe). Gesprek herstel."
resumed_no_count: "↻ Sessie **{title}** hervat. Gesprek herstel."
retry:
no_previous: "Geen vorige boodskap om te herhaal nie."
rollback:
not_enabled: "Kontrolepunte is nie geaktiveer nie.\nAktiveer in config.yaml:\n```\ncheckpoints:\n enabled: true\n```"
none_found: "Geen kontrolepunte vir {cwd} gevind nie"
invalid_number: "Ongeldige kontrolepunt-nommer. Gebruik 1-{max}."
restored: "✅ Herstel na kontrolepunt {hash}: {reason}\n'n Voor-terugrol-momentopname is outomaties gestoor."
restore_failed: "❌ {error}"
set_home:
save_failed: "Kon nie tuiste-kanaal stoor nie: {error}"
success: "✅ Tuiste-kanaal gestel op **{name}** (ID: {chat_id}).\nKron-take en kruisplatform-boodskappe sal hier afgelewer word."
status:
header: "📊 **Hermes Gateway Status**"
matrix_scope_header: "**Matrix scope:**"
matrix_scope_room: " room: {room}"
matrix_scope_room_id: " room_id: {room_id}"
matrix_scope_thread: " thread_id: {thread_id}"
matrix_scope_mode: " session_scope: {scope}"
matrix_scope_key: " session_key: {session_key}"
session_id: "**Sessie-ID:** `{session_id}`"
title: "**Titel:** {title}"
created: "**Geskep:** {timestamp}"
last_activity: "**Laaste aktiwiteit:** {timestamp}"
tokens: "**Kumulatiewe API-tokens (elke oproep weer gestuur):** {tokens}"
agent_running: "**Agent loop:** {state}"
state_yes: "Ja ⚡"
state_no: "Nee"
queued: "**Opgehoopte opvolge:** {count}"
platforms: "**Verbinde Platforms:** {platforms}"
stop:
stopped_pending: "⚡ Gestop. Die agent het nog nie begin nie — jy kan met hierdie sessie voortgaan."
stopped: "⚡ Gestop. Jy kan met hierdie sessie voortgaan."
no_active: "Geen aktiewe taak om te stop nie."
title:
db_unavailable: "Sessie-databasis is nie beskikbaar nie."
warn_prefix: "⚠️ {error}"
empty_after_clean: "⚠️ Titel is leeg na opruiming. Gebruik asseblief drukbare karakters."
set_to: "✏️ Sessie-titel gestel: **{title}**"
not_found: "Sessie nie in databasis gevind nie."
current_with_title: "📌 Sessie: `{session_id}`\nTitel: **{title}**"
current_no_title: "📌 Sessie: `{session_id}`\nGeen titel gestel nie. Gebruik: `/title My Sessie Naam`"
topic:
not_telegram_dm: "Die /topic-opdrag is slegs beskikbaar in Telegram-privaatgesprekke."
no_session_db: "Sessie-databasis is nie beskikbaar nie."
unauthorized: "Jy het nie toestemming om /topic op hierdie bot te gebruik nie."
restore_needs_topic: "Om 'n sessie te herstel, skep of open eers 'n Telegram-onderwerp en stuur dan /topic <session-id> binne daardie onderwerp. Om 'n nuwe onderwerp te skep, open All Messages en stuur enige boodskap daar."
topics_disabled: "Telegram-onderwerpe is nog nie vir hierdie bot geaktiveer nie.\n\nHoe om dit te aktiveer:\n1. Open @BotFather.\n2. Kies jou bot.\n3. Open Bot Settings → Threads Settings.\n4. Skakel Threaded Mode aan en maak seker gebruikers mag nuwe drade skep.\n\nStuur dan weer /topic."
topics_user_disallowed: "Telegram-onderwerpe is geaktiveer, maar gebruikers mag nie onderwerpe skep nie.\n\nOpen @BotFather → kies jou bot → Bot Settings → Threads Settings, en skakel dan 'Disallow users to create new threads' af.\n\nStuur dan weer /topic."
enable_failed: "Kon nie Telegram-onderwerpmodus aktiveer nie: {error}"
bound_status: "Hierdie onderwerp is gekoppel aan:\nSessie: {label}\nID: {session_id}\n\nGebruik /new om hierdie onderwerp met 'n vars sessie te vervang.\nVir parallelle werk, open All Messages en stuur 'n boodskap daar om 'n ander onderwerp te skep."
thread_ready: "Telegram multi-sessie-onderwerpe is geaktiveer.\n\nHierdie onderwerp sal as 'n onafhanklike Hermes-sessie gebruik word. Gebruik /new om hierdie onderwerp se huidige sessie te vervang. Vir parallelle werk, open All Messages en stuur 'n boodskap daar om 'n ander onderwerp te skep."
untitled_session: "Sessie sonder titel"
undo:
nothing: "Niks om ongedaan te maak nie."
removed: "↩️ {turns} beurt(e) ongedaan gemaak ({count} boodskap(pe)).\nGerugsteun na: \"{preview}\"\nKopieer/wysig die teks hierbo en stuur dit om van hier af weer te vra."
invalid_count: "Ongeldige getal \"{arg}\" — gebruik /undo of /undo N."
update:
platform_not_messaging: "✗ /update is slegs beskikbaar vanaf boodskapplatforms. Voer `hermes update` vanaf die terminale uit."
not_git_repo: "✗ Nie 'n git-bewaarplek nie — kan nie opdateer nie."
hermes_cmd_not_found: "✗ Kon nie die `hermes`-opdrag vind nie. Hermes loop, maar die opdateeropdrag kon nie die uitvoerbare lêer op PATH of via die huidige Python-vertolker vind nie. Probeer `hermes update` met die hand in jou terminale uitvoer."
start_failed: "✗ Kon nie opdatering begin nie: {error}"
starting: "⚕ Begin Hermes-opdatering… Ek sal vordering hier stroom."
usage:
rate_limits: "⏱️ **Tariefperke:** {state}"
header_session: "📊 **Sessie-tokengebruik**"
label_model: "Model: `{model}`"
label_input_tokens: "Invoertokens: {count}"
label_cache_read: "Kasie-leestokens: {count}"
label_cache_write: "Kasie-skryftokens: {count}"
label_output_tokens: "Uitvoertokens: {count}"
label_total: "Totaal: {count}"
label_api_calls: "API-oproepe: {count}"
label_cost: "Koste: {prefix}${amount}"
label_cost_included: "Koste: ingesluit"
label_context: "Konteks: {used} / {total} ({pct}%)"
label_compressions: "Saamperserings: {count}"
header_session_info: "📊 **Sessie-inligting**"
label_messages: "Boodskappe: {count}"
label_estimated_context: "Geskatte konteks: ~{count} tokens"
detailed_after_first: "_(Gedetailleerde gebruik beskikbaar na die eerste agent-antwoord)_"
no_data: "Geen gebruiksdata beskikbaar vir hierdie sessie nie."
credits:
not_logged_in: "Nie by Nous Portal aangemeld nie. Meld aan om jou kredietsaldo te sien en op te laai."
verbose:
not_enabled: "Die `/verbose`-opdrag is nie vir boodskapplatforms geaktiveer nie.\n\nAktiveer dit in `config.yaml`:\n```yaml\ndisplay:\n tool_progress_command: true\n```"
mode_off: "⚙️ Gereedskap-vordering: **AF** — geen gereedskap-aktiwiteit word vertoon nie."
mode_new: "⚙️ Gereedskap-vordering: **NUUT** — vertoon wanneer gereedskap verander (voorskoulengte: `display.tool_preview_length`, verstek 40)."
mode_all: "⚙️ Gereedskap-vordering: **ALMAL** — elke gereedskaps-oproep vertoon (voorskoulengte: `display.tool_preview_length`, verstek 40)."
mode_verbose: "⚙️ Gereedskap-vordering: **OMSLAGTIG** — elke gereedskaps-oproep met volle argumente."
saved_suffix: "_(gestoor vir **{platform}** — neem effek by die volgende boodskap)_"
save_failed: "_(kon nie in konfigurasie stoor nie: {error})_"
voice:
enabled_voice_only: "Stemmodus geaktiveer.\nEk sal met stem antwoord wanneer jy stemboodskappe stuur.\nGebruik /voice tts om stemantwoorde vir alle boodskappe te kry."
disabled_text: "Stemmodus gedeaktiveer. Slegs teks-antwoorde."
tts_enabled: "Outo-TTS geaktiveer.\nAlle antwoorde sal 'n stemboodskap insluit."
status_mode: "Stemmodus: {label}"
status_channel: "Stemkanaal: #{channel}"
status_participants: "Deelnemers: {count}"
status_member: " - {name}{status}"
speaking: " (praat)"
enabled_short: "Stemmodus geaktiveer."
disabled_short: "Stemmodus gedeaktiveer."
label_off: "Af (slegs teks)"
label_voice_only: "Aan (stemantwoord op stemboodskappe)"
label_all: "TTS (stemantwoord op alle boodskappe)"
help: "{toggle}\n\n**Hoe /voice werk**\n• `/voice on` — stemantwoord wanneer jy 'n stemboodskap stuur\n• `/voice tts` — stemantwoord op *elke* boodskap\n• `/voice off` — terug na slegs-teks antwoorde\n• `/voice status` — wys die huidige modus\n• `/voice` (geen argument) — wissel vinnig tussen aan en af{channels}"
help_channels: "\n\n**Lewendige stemkanale (Discord)**\n• Sluit eers by 'n stemkanaal aan, dan `/voice channel` — ek sluit aan, luister en praat my antwoorde\n• `/voice leave` — ontkoppel van die stemkanaal"
yolo:
disabled: "⚠️ YOLO-modus **AF** vir hierdie sessie — gevaarlike opdragte sal goedkeuring vereis."
enabled: "⚡ YOLO-modus **AAN** vir hierdie sessie — alle opdragte word outomaties goedgekeur. Gebruik versigtig."
shared:
session_db_unavailable: "Sessie-databasis is nie beskikbaar nie."
session_db_unavailable_prefix: "Sessie-databasis is nie beskikbaar"
session_not_found: "Sessie nie in databasis gevind nie."
warn_passthrough: "⚠️ {error}"