Files
TREK/shared/src/i18n/pl/admin.ts
T
jubnl 91025683bb 3.2.1 (#1433)
* fix(plugins): prevent arbitrary api access

* fix(planner): disable drag & drop on mobile so the places list scrolls (#1432)

On touch devices the draggable rows hijack the scroll gesture, so dragging
to scroll started an HTML5 drag and popped up the file-import overlay instead
of scrolling. Gate the draggable rows and the sidebar file-drop handlers on
!isMobile across the places sidebar and the day plan (places, transports,
notes), and hide the grip handle — the arrow reorder buttons take over there.

* fix(inspector): make the remove-from-day button icon-only on mobile

* fix(collections): show the save picker above the mobile place detail

* fix(plugins): seal IPC parent/child for good

* test(inspector): match the icon-only remove-from-day button

* feat(sdk): switch plain ts for clack/prompts interactive session

* feat(plugins): force-refresh the registry from the rescan button

The registry is cached for 30 min server-side and GitHub serves it with a
5-min CDN cache, so a freshly published plugin could take up to ~35 min to
appear. The rescan/reload button now force-pulls the registry: it bypasses the
in-memory cache and appends a cache-buster + no-cache headers to beat the CDN,
and refreshes the browse grid immediately.

* feat(sdk): bump plugin version

* fix(stored settings): prevent local storage drop when update not successful

* feat(plugins): sideload plugins by uploading a .zip

Adds an admin "Upload plugin" button + drag-and-drop to the plugins panel for
installing a plugin archive directly — handy for testing a build before it goes
to the registry. It reuses the registry install pipeline (slip/bomb-safe
extract, strict manifest validation, native-binary scan) via a new
POST /admin/plugins/upload, and only skips the registry sha256/signature checks
that a sideload can't have.

Sideloaded plugins are flagged (source "local:upload", a "Sideloaded" badge, no
GitHub link, no auto-update) and always land INACTIVE — replacing a running or
active plugin stops it and clears the active flag first, so new code never runs
without a fresh activation + permission consent.

* fix(planner): keep the day-plan collapse state after fully closing the page

The expanded/collapsed days were stored in sessionStorage, which survives a
reload but is wiped when the tab or window is closed — so every fresh open
re-expanded all days, which is tedious to re-collapse on long (10+ day) trips.
Store it in localStorage instead so a collapsed layout sticks until it's
changed.

* fix(i18n): correct Vietnamese translation of 'Disabled' (#1438)

'Tàn tật' means physically handicapped/disabled-person, not the
off/disabled state of a toggle. Replace with 'Tắt' (off), matching
the existing 'admin.plugins.stateOff' translation.

Affects admin.notifications.none and admin.addons.disabled.

* add the code of conduct

* fix(plugins): let widgets follow the in-app dark-mode toggle

The plugin frame is sandboxed at an opaque origin (no parent DOM access) and we
only sent the context — including the theme — once, on trek:ready. So toggling
dark mode in TREK left already-mounted widgets on the old theme until a reload.
Watch the <html> `dark` class and re-post the context when it flips; plugins
already re-apply the theme on trek:context.

* fix(plugins): deliver widget context on load so the theme is right on first paint

* fix(plugins): give widget cards the native glassy look and auto-height

Widget plugins rendered in a plain card with a fixed 180px body, so they looked
foreign next to the glassy dashboard tools and taller widgets had their controls
clipped. Mirror the native `.tool` surface (glass background/border/blur, uppercase
title) and let the body grow to the height the widget reports over trek:resize.

* feat(plugins): add read/rwite costs

* feat(plugin): better readme/index.js

* feat(plugin): better readme/index.js

* feat(plugins): hand widgets TREK's theme tokens, formats and display identity

Extends trek:context with a non-secret `tokens` map (TREK's resolved CSS design
tokens for the current theme), `formats` (currency/date/units/timezone) and a
`user` display object (name/avatar/isAdmin — never the email, role only as a
boolean). Re-sent on every theme toggle. A widget can now apply the tokens and
match the host exactly, in both themes and under a custom appearance, instead of
hard-coding a palette that drifts — so plugins feel native, not bolted-on.

* feat(plugins): hand plugins the full palette and appearance state

The theme context only carried a ~19-token subset read off <html> and only
followed the dark-mode toggle. Widen it to the whole global (:root/.dark)
palette — surfaces, text, borders, the accent family, semantic + soft fills,
shadows, radii and fonts — so a plugin tracks the user's chosen accent scheme,
custom accent and high-contrast live, not just light/dark. Also send an
`appearance` block (scheme, density, reduced-motion, no-transparency) mirrored
from the attributes applyAppearance writes on <html>, and re-post the context
whenever any of those actually change (a small signature dedupes unrelated
mutations) so plugins restyle in step with the app.

* feat(plugins): ship a design kit so plugin UIs look native

A plugin's UI is a sandboxed, opaque-origin iframe that can't load TREK's
stylesheet — so authors had to re-derive the whole look by hand, and most
didn't. Ship it instead: a token-driven stylesheet (glass, hover, buttons,
inputs, chips, rows) that consumes the tokens the host already sends and swaps
light/dark, plus a small bootstrap that applies those tokens, mirrors the
appearance flags, auto-reports the frame height and exposes a `window.trek`
helper over the existing bridge. Both are plain strings meant to be inlined
(the CSP forbids external assets for an opaque frame); `injectTrekUi` expands a
`<!-- trek:ui -->` marker. No new capability — only a native look.

* feat(plugins): deliver the design kit — native scaffold + inline on dev/pack

A new page/widget scaffolds a native, glassy starter that talks over
window.trek. The source keeps a single `<!-- trek:ui -->` line; `dev` (when it
serves /ui) and `pack` (as the file enters the archive) expand it into the
inlined kit — so the file stays a one-line opt-in and a rebuild always ships
the current kit. Existing plugins opt in the same way, by dropping the marker.

* feat(plugins): faithful themed host preview in dev

`dev` served the plugin UI raw at /ui — top-level, with no host — so the theme,
context and bridge never fired and authors couldn't see the design kit render.
Add /preview: it embeds /ui in a sandboxed opaque-origin iframe (exactly TREK's
isolation) and plays the host — posts trek:context with a theme/accent/appearance
toggle, proxies trek:invoke to your /api routes as the dev user, and surfaces
resize/notify/navigate. /ui stays as the raw doc for debugging.

* docs(plugins): document the design kit, window.trek and the token contract

Rewrite the client section of the Plugin Development wiki kit-first: the
`<!-- trek:ui -->` marker, the component classes, the `window.trek` bridge, the
`/preview` host preview, the full `trek:context` payload (now the whole palette
plus an `appearance` block) and how to apply tokens by hand. Add a "Build a
native UI" section + the new exports to the SDK README.

* feat(budget): add 'Outstanding amount' card

* fix(translations): finish translating new keys

* feat(plugins): trip-page plugins — a plugin tab inside every trip

Adds a `trip-page` plugin type whose sandboxed iframe mounts as a tab in the
trip planner (Plan / Transports / … / <plugin>), scoped to the open trip, with
no dashboard nav entry. This is the most-asked planner-extension request from
discussion #1429 (a plugin that lives in the trip, e.g. SimMesg20's budget
planner). It reuses PluginFrame and the existing tab system — the frame already
receives the current tripId over trek:context — so there is no bridge or
security change: only the manifest type enum (server + SDK), the client feed
classification (pluginStore.tripPages), and one render branch in the planner.
The SDK scaffolds it with `create --type trip-page`.

* fix(apple wallet): support for .pkpasses

* feat(plugins): permission-gated write APIs for the planner (#1429)

Plugins can now WRITE core planner data, not just read it, through curated,
membership-checked methods — so downstream features can live in plugins instead
of long-lived core patches. Four new scopes: db:write:places (create/update/delete
places), db:write:days (days), db:write:itinerary (assign/unassign a place on a
day) and db:write:trips (update trip fields).

Each ctx method mirrors costs.create: it validates the input against the SAME
@trek/shared schema the web app uses, binds the acting user host-side (a job/onLoad
has none, so its writes are refused), checks trip access AND the app's edit
permission (place_edit / day_edit / trip_edit), delegates to the real services,
broadcasts the same events so open sessions update live, and records the write in
the tamper-evident capability audit. No new route, no sandbox or CSP change — the
isolation boundary is unchanged; a plugin can only change what its user could change
by hand. Consent UI + permission labels in all 22 locales, SDK types + mock host,
and the wikis are updated.

* docs(plugin): ensure wiki correctness

* feat(plugins): plugin metadata on core entities — db:meta (#1429)

Plugins can now attach their OWN namespaced key/value data to a trip, place or
day without forking the core schema (#1429, request 2). New `db:meta` scope +
`ctx.meta.get/set/list/delete`. Storage is one plugin_entity_metadata table
(migration 161) keyed (plugin_id, entity_type, entity_id, key) — a plugin only
ever sees its own rows. Every call is membership-checked: the entity must belong to
a trip the host-bound acting user can access. Quotas guard the shared volume (≤64KB
per value, ≤100 keys per entity); rows are purged on uninstall-with-delete-data and
recorded in the capability audit. SDK types + mock host, a consent chip + labels in
all 22 locales, and the wikis. No new route, no sandbox change.

* feat(plugins): place-detail plugin slot in the trip planner (#1429)

A widget plugin can declare `capabilities.widget.slot: 'place-detail'` to mount
its sandboxed frame inside the trip planner's place-detail panel, scoped to the
open place — the frame receives the `placeId` in trek:context alongside the tripId.
This is the UI half of the place-detail-providers ask (reviews/ratings/popular
times shown on a place). It reuses the existing widget mechanism: PluginFrame gains
an optional placeId, the feed/store learn the new slot, and PlaceInspector renders
the slot at the foot of its body in trip mode. Admin chip + label in all 22 locales,
wiki updated. No sandbox or permission change.

* fix(plugins): green the server tests + harden the new capability surface

The in-memory uninstall fixture was missing the new plugin_entity_metadata table,
so uninstall's DELETE threw "no such table" and failed the server test job. Add the
table to the fixture schema.

Self-review hardening of the write/metadata surface:
- trips.update now reproduces the web UI's per-field gate: is_archived needs
  trip_archive and cover_image needs trip_cover_upload, not just trip_edit — so a
  member who may only edit can't archive or re-cover a trip.
- Plugin metadata WRITES now also require the entity's edit permission
  (place_edit/day_edit/trip_edit), not just trip access, so a read-only member can't
  overwrite or delete metadata another user created. Reads stay access-gated.
- Cap the metadata key length (<=256 chars) alongside the value/count quotas — the
  key was attacker-controlled and uncapped, defeating the disk-DoS guard.

* test(plugins): cover the new write/metadata deps to hold the coverage gate

The new create-rpc-host write + metadata deps were untested, dropping the
src/nest branch coverage below the 80% gate. Add a seeded in-memory core db plus
mocked core services to exercise every dep end-to-end: places/days/itinerary
create/update/delete + not-found paths, trips.update with the archive/cover
per-field gates and the Validation/NotFound/unknown-error mapping, metadata CRUD
+ key/value/count caps + access checks, the costs deps, and users.getById
scoping. Plus rpc-host cases for meta writes on place/day and a no-acting-user
refusal. Tests only — no production code change.

* fix(costs): freeze FX on every cost + settlement write path (#1445)

Settled foreign-currency costs kept re-opening with a few-cent residual
when live rates drifted. The #1335 freeze only ran on the REST create/
update path, so two gaps remained:

- Foreign-currency items created via MCP create_budget_item or booking-
  import bypassed the freeze and stored exchange_rate = 1, so settlement
  re-converted them with live rates. Promote freezeForeignRate into the
  shared budgetService and call it from every write path.
- Settle-up transfers were stored currency-less and re-converted with
  live rates on each recompute. Add currency + exchange_rate to
  budget_settlements (migration), freeze the display-currency rate at
  settle time, and convert with it in calculateSettlement. Legacy rows
  (currency = NULL / rate = 1) keep live-rate behaviour until re-edited.

Also expose guarded cost update/delete to plugins: costs.update and
costs.delete under db:write:costs, gated exactly like costs.create
(addon + trip access + the acting user's budget_edit permission).
updateCost reuses BudgetService.update so a plugin write re-freezes the
FX rate too; both broadcast the same budget:updated / budget:deleted
events the REST controller emits. Wired through the host, the runtime
SDK context and the published trek-plugin-sdk (types + mock host).

* feat(plugins): provider hooks — placeDetailProvider, wired (#1429)

Turn "hooks" from a declared-but-dead surface into a real host→plugin capability.
Add an invoke.hook branch to the child + a supervisor hook registry
(providersOf) + PluginRuntimeService.invokeHook, reusing the existing invoke
transport and its timeout (a short 5s deadline so a slow provider can't delay a
response; a job/onLoad has no user, host-bound as ever). Also fixes a real bug: the
in-repo runtime SDK copy was missing the `hooks` field entirely and could not even
parse a plugin that declared one — synced it with the published SDK.

The first wired hook is placeDetailProvider: a plugin returns extra rows
({label,value?,url?}) for a place, and TREK renders them natively at the foot of the
place-detail panel. Consumer is a new, additive, fail-safe endpoint
GET /api/place-details/:placeId (membership-checked; any provider that errors or
times out is simply skipped — it never breaks the panel). New hook:place-detail-
provider scope + consent chip in all 22 locales. SDK types (both copies), a
controller test, and the wiki. photoProvider/calendarSource stay reserved but the
transport now exists for them. No sandbox or CSP change.

* fix(files): handle pkpass in booking uploads and files-tab open (#1447, #1448)

Both bugs were client-only; the server already allows .pkpass and serves it
as application/vnd.apple.pkpass.

#1448: the reservation/transport attachment inputs hard-coded an accept list
that omitted pkpass, so macOS grayed it out. Add .pkpass/.pkpasses (+ wallet
MIME types) to the accept attribute in both modals.

#1447: the files-tab open path routed every non-media/non-markdown file into
the in-app PDF preview object. Add isWalletPass() and route wallet passes
through the shared blob openFile helper (as bookings already do), which
downloads them so the OS hands them to Apple Wallet.

* feat(plugins): validation/warning contributions via warningProvider hook (#1429)

Second wired provider hook, reusing the invoke.hook infra from the last commit. A
plugin implements warningProvider.getWarnings(tripId, ctx) → {level, message,
dayId?, placeId?}[] to flag problems on a trip (overpacked day, place closed on its
planned date, missing booking, …). TREK surfaces them as a non-blocking overlay
banner at the top of the trip planner (the wrapper ignores pointer events so it
never covers the map/panels; only the pills are interactive).

Consumer is a new additive, fail-safe endpoint GET /api/trip-warnings/:tripId
(membership-checked; a provider that errors or times out contributes nothing and
never blocks the planner). New hook:trip-warning-provider scope + consent chip in
all 22 locales, SDK types (both copies), a controller test, and the wiki. This is
the validation half of the scheduling+validation block; feeding durations/travel
times back into core recalculation stays out (it would touch core planner
computation — deliberately deferred to keep the no-breaking-changes guarantee).

* fix(plugins): enforce the hook:* grant on provider dispatch (#1429 audit)

The adversarial audit of the #1429 additions found one real (medium) gap: the
hook:* permission was never enforced at runtime. providersOf() selected provider
plugins purely by the hooks their CODE declares (sup.hooks, reported by the child
as Object.keys(def.hooks)) and never intersected that with sup.granted — so a
plugin that merely implemented placeDetailProvider/warningProvider got wired in as
a provider even when the admin never consented to hook:place-detail-provider /
hook:trip-warning-provider. The downstream capability router still held (the hook's
ctx can only do what the plugin's OTHER grants allow), but a plugin could obtain an
auto-triggered, user-bound execution context on a passive UI browse without the
hook being consented — a consent-integrity gap that contradicts the documented
invariant.

Gate it host-side: a hookName→permission map, and providersOf now returns a plugin
only if it is active, implements the hook, AND holds the matching hook:* grant. An
unmapped hook resolves to nobody. invokeHook additionally re-checks membership in
providersOf (defense-in-depth against a direct caller). Unit test proves the
grant/implements/active intersection.

* docs(plugins): add the Plugin Cookbook + a trip-doctor example (#1429 eco)

Fosters plugin authoring by turning the new #1429 capabilities into copy-paste
recipes. New wiki page Plugin-Cookbook (read a trip, write to the itinerary, tag an
entity with metadata, contribute native place details, raise trip warnings,
broadcast, match the TREK look) linked in the sidebar, plus a complete runnable
example — trip-doctor — a hooks-only plugin that showcases warningProvider +
placeDetailProvider + ctx.meta with zero UI of its own. Manifest validates against
the SDK. Docs/example only; no product code.

* fix(collections): don't reset saved-place status to 'idea' on edit (#1437)

The update schema reused collectionStatusSchema, whose .default('idea')
survives .optional() — so a PATCH that omits status had 'idea' injected by
the validation pipe and written to the DB, clobbering 'want'/'visited'.
Strip the default on the update field with .removeDefault(), keeping the
.catch guard. Add a shared schema regression test and an e2e round-trip.

* docs(plugin): ensure plugin scopes are the same everywhere

* feat(plugins): read scopes for packing + files (#1429 eco)

Extend the read side of the capability model beyond trips/costs: db:read:packing
→ ctx.packing.list(tripId) and db:read:files → ctx.files.list(tripId). Both mirror
the existing trip reads exactly — the host membership-checks the trip against the
invocation's user (tripRead) before delegating to the same packingService/
fileService the REST paths use (so bags/assignees hydrate and trash is excluded),
and each is a separate scope (packing doesn't unlock files). ctx types in both SDK
copies + mock-host, consent labels + cap chips in all 22 locales, rpc-host +
create-rpc-host tests, and the wiki (perm table + cookbook recipe).

* feat(plugins): core event subscriptions (#1429 eco)

A plugin can react to core activity by declaring events: [{ on, handler }] + the
events:subscribe grant. websocket.broadcast announces every CORE trip event (name +
tripId ONLY, never the payload) through a tiny dependency-free relay
(plugin-event-sink); the runtime registers a sink in onModuleInit and the supervisor
fans each event out to subscribed, granted, active plugins via a fire-and-forget
invoke.event on a short timeout — so a slow subscriber can never block a core write.

Safety by construction: handlers run with NO user (like a job) so trip reads are
refused — they react to the fact, using the plugin's own ctx.db/ws/outbound; the
grant is enforced host-side (deliverEvent checks events:subscribe); plugin:* re-
broadcasts are never delivered back, so handlers can't loop; and only the event name
+ tripId cross the boundary. SDK types (both copies), consent label + cap chip in all
22 locales, supervisor gating + broadcast-tap tests, and the wiki + cookbook.

The relay lives in its own module (not websocket) so it doesn't drag `ws` into the
runtime and tests that mock ./websocket don't strip the sink.

* feat(plugin-sdk): typed ctx returns + native trek.ui DOM helpers (#1429 eco)

Two author-DX wins, SDK-only.

Typed reads/writes: ctx.trips.getById/getPlaces/getReservations, packing.list,
files.list, costs.*, places/days/itinerary writes and users.getById now return
proper entity types (Trip, Place, Day, Reservation, PackingItem, TripFile,
BudgetItem, Assignment, User) instead of unknown — real autocomplete for authors.
Only `id` is guaranteed and every shape keeps an index signature, so it mirrors the
raw DB row honestly (no column hidden, no false guarantees). mock-host matches.

Native UI helpers: window.trek now carries `trek.ui` — a tiny bundler-free DOM
builder (el/button/card/chip/input/mount) that emits the kit's trek-* classes, so a
widget builds themed UI with no CSS and no build step. Ships inlined via the same
<!-- trek:ui --> marker. Wiki updated.

* fix(plugins): scope packing.list to the acting user's #858 visibility (eco audit)

The final eco audit found one real (medium) gap: the db:read:packing delegate
called packingService.listItems(tripId) with NO userId, which takes the UNFILTERED
branch and returns every member's private (is_private=1) packing items — leaking
another member's personal/surprise-gift items to a plugin the normal UI/REST hides
them from. The handler had the host-bound acting user but dropped it when delegating.

Thread it through: tripRead now hands the membership-checked userId to the read
callback, packing.list forwards it to listPackingItems(tripId, userId), and the
service applies its three-tier #858 filter — a plugin now sees exactly what its user
sees. files.list is unaffected (no per-user file visibility). Tests assert the user
is passed. The other three audited surfaces (event subscriptions, trek.ui, and the
regression sweep of the capability boundary) were clean.

* security(plugins): prevent open redirect

* fix(plugins): resolve PR #1433 full-audit findings (code + tests)

The comprehensive PR audit confirmed 21 findings; this fixes the code/test ones I own:

- ctx.users.getById was DEAD: the runtime SDK omitted the _inv tag, so actingUser
  never bound and every call hit RESOURCE_FORBIDDEN. Add _inv (the test had codified
  the bug — corrected).
- Plugin place writes bypassed the REST STRING_LIMITS (a 100k-char name the web app
  rejects). Mirror the caps (name 200 / description 2000 / address 500 / notes 2000).
- packing.list / files.list were missing from the capability audit log while every
  other core read is audited — add them to isAuditable + auditResource.
- SDK lockstep: CalendarSource.getEvents drifted (published Date vs runtime string);
  the host->plugin boundary is JSON, so align both to string.
- Admin panel didn't know the new trip-page plugin type (unlocalised badge, missing
  filter) — add it to KNOWN_TYPES + the type filter + a 22-locale label.
- Tests for previously-uncovered paths: the child-side invoke.hook/invoke.event
  dispatch (real fork, hook + event + non-matching-subscription), and invokeHook's
  defense-in-depth grant re-check.

Julien's settlement-FX-refreeze finding is his budget code (flagged, not touched).

* docs(plugins): correct the wiki against the shipped capability surface (#1433 audit)

Fixes the 11 doc findings from the PR audit — every corrected claim was cross-checked
against the code:

- Plugin-Development: CSP connect-src is built from granted http:outbound:<host>, not
  egress[]; dropped the stale "costs.create is the first and only core mutation";
  documented costs.update/delete + ctx.packing/ctx.files; the manifest permission table
  gained the six missing scopes (db:write:places/days/itinerary/trips, db:meta,
  hook:trip-warning-provider); the widget slot table gained place-detail.
- Plugin-Cookbook: days.create no longer passes a title the schema drops;
  broadcastToUser uses the real (userId, event, data) signature; fixed the broken
  #the-trek-ui-design-kit anchor and noted window.trek.ui.
- Plugin-Permissions: added db:read:packing, db:read:files and events:subscribe;
  the provider hooks are implemented in `hooks: {...}` on the definition, not on ctx.

* fix(unsplash) allow api key usage

* fix(guests): scope guest display names per-trip, not globally (#1446)

A guest is a per-trip person, but their name lived in the globally UNIQUE
users.username, so uniqueGuestUsername() auto-renamed a second "Jake" (on any other
trip) to "Jake 2". Add a non-unique users.display_name: a guest now stores the human
name there and gets a uuid-based username that is never shown, and every member view
(members list, day-assignment participants, budget members/payers, packing
recipients/contributors/bags/assignees) COALESCEs display_name over username. Rename
updates display_name with no dedup. Real users are unchanged (display_name NULL →
COALESCE falls through to username). Migration adds the nullable column; existing
guests keep their current username via the COALESCE fallback.

This also unblocks ctx.users.getById (the audit's #4 fix), whose projection selects
display_name. Tests: two "Jake" guests on two trips both keep the name; the two
codified-the-old-behaviour guest tests corrected.

* fix(costs): don't re-freeze a settlement's FX rate on an unrelated edit (#1445)

The full audit found that updateSettlement called freezeForeignRate without the
"currency unchanged" guard the item path has, so any edit of a foreign-currency
settlement (e.g. correcting from/to) re-fetched the LIVE rate and overwrote the
frozen one — re-opening an already-balanced position with a small residual, the
exact drift #1445 was meant to prevent.

freezeForeignRate's unchanged-check was item-centric (it queried budget_items),
which a settlement (a different table) can't use. Give it an explicit
existingCurrency param; updateSettlement now reads the settlement's stored currency
and passes it, so an edit that doesn't change the currency keeps the frozen rate
(the service UPDATE already preserves exchange_rate when it's left unset). Tests
cover both: unchanged currency keeps the rate, a real currency change re-freezes.

* feat(plugins): add inter plugin dependency support and addon dependency support

* feat(plugins): add inter plugin dependency support and addon dependency support

* docs(plugins) inter dependencies

---------

Co-authored-by: Maurice <mauriceboe@icloud.com>
Co-authored-by: trongbinhnguyen <43725147+trongbinh15@users.noreply.github.com>
2026-07-06 00:27:42 +02:00

559 lines
38 KiB
TypeScript

import type { TranslationStrings } from '../types';
const admin: TranslationStrings = {
'admin.smtp.title': 'E-maile i powiadomienia',
'admin.smtp.hint': 'Konfiguracja SMTP dla powiadomień e-mail. Opcjonalnie: URL Webhooka dla Discorda, Slacka, itp.',
'admin.smtp.testButton': 'Wyślij testowego e-maila',
'admin.smtp.testSuccess': 'Testowy e-mail został wysłany pomyślnie',
'admin.smtp.testFailed': 'Nie udało się wysłać testowego e-maila',
'admin.title': 'Administracja',
'admin.subtitle': 'Zarządzanie użytkownikami i ustawienia systemowe',
'admin.tabs.users': 'Użytkownicy',
'admin.tabs.categories': 'Kategorie',
'admin.tabs.backup': 'Backupy',
'admin.tabs.notifications': 'Powiadomienia',
'admin.tabs.audit': 'Audit',
'admin.stats.users': 'Użytkownicy',
'admin.stats.trips': 'Podróże',
'admin.stats.places': 'Miejsca',
'admin.stats.photos': 'Zdjęcia',
'admin.stats.files': 'Pliki',
'admin.table.user': 'Użytkownik',
'admin.table.email': 'E-mail',
'admin.table.role': 'Rola',
'admin.table.created': 'Utworzono',
'admin.table.lastLogin': 'Ostatnie logowanie',
'admin.table.actions': 'Akcje',
'admin.you': '(Ty)',
'admin.editUser': 'Edytuj użytkownika',
'admin.newPassword': 'Nowe hasło',
'admin.newPasswordHint': 'Pozostaw puste, aby zachować obecne hasło',
'admin.deleteUser': 'Usunąć użytkownika "{name}"? Wszystkie jego podróże zostaną trwale usunięte.',
'admin.deleteUserTitle': 'Usuń użytkownika',
'admin.newPasswordPlaceholder': 'Podaj nowe hasło...',
'admin.toast.loadError': 'Nie udało się załadować danych administratora',
'admin.toast.userUpdated': 'Użytkownik został zaktualizowany',
'admin.toast.updateError': 'Nie udało się zaktualizować użytkownika',
'admin.toast.userDeleted': 'Użytkownik został usunięty',
'admin.toast.deleteError': 'Nie udało się usunąć użytkownika',
'admin.toast.cannotDeleteSelf': 'Nie można usunąć własnego konta',
'admin.toast.userCreated': 'Użytkownik został utworzony',
'admin.toast.createError': 'Nie udało się utworzyć użytkownika',
'admin.toast.fieldsRequired': 'Nazwa użytkownika, e-mail i hasło są wymagane',
'admin.createUser': 'Utwórz użytkownika',
'admin.invite.title': 'Linki zaproszeń',
'admin.invite.subtitle': 'Twórz jednorazowe linki do rejestracji',
'admin.invite.create': 'Utwórz link',
'admin.invite.createAndCopy': 'Utwórz i skopiuj',
'admin.invite.empty': 'Nie utworzono jeszcze żadnych linków zaproszeń',
'admin.invite.maxUses': 'Maksymalna liczba użyć',
'admin.invite.expiry': 'Wygasa po',
'admin.invite.uses': 'użycia',
'admin.invite.expiresAt': 'wygasa',
'admin.invite.createdBy': 'utworzone przez',
'admin.invite.active': 'Aktywny',
'admin.invite.expired': 'Wygasł',
'admin.invite.usedUp': 'Wykorzystany',
'admin.invite.copied': 'Link zaproszenia został skopiowany do schowka',
'admin.invite.copyLink': 'Skopiuj link',
'admin.invite.deleted': 'Link zaproszenia został usunięty',
'admin.invite.createError': 'Nie udało się utworzyć linku zaproszenia',
'admin.invite.deleteError': 'Nie udało się usunąć linku zaproszenia',
'admin.tabs.settings': 'Ustawienia',
'admin.allowRegistration': 'Zezwól na rejestrację',
'admin.allowRegistrationHint': 'Nowi użytkownicy mogą się rejestrować samodzielnie',
'admin.authMethods': 'Authentication Methods',
'admin.passwordLogin': 'Password Login',
'admin.passwordLoginHint': 'Allow users to sign in with email and password',
'admin.passwordRegistration': 'Password Registration',
'admin.passwordRegistrationHint': 'Allow new users to register with email and password',
'admin.oidcLogin': 'SSO Login',
'admin.oidcLoginHint': 'Allow users to sign in with SSO',
'admin.oidcRegistration': 'SSO Auto-Provisioning',
'admin.oidcRegistrationHint': 'Automatically create accounts for new SSO users',
'admin.envOverrideHint':
'Password login settings are controlled by the OIDC_ONLY environment variable and cannot be changed here.',
'admin.lockoutWarning': 'At least one login method must remain enabled',
'admin.requireMfa': 'Wymagaj uwierzytelniania dwuskładnikowego (2FA)',
'admin.requireMfaHint':
'Użytkownicy bez 2FA muszą ukończyć konfigurację w Ustawieniach zanim zaczną korzystać z aplikacji.',
'admin.apiKeys': 'Klucze API',
'admin.apiKeysHint':
'Opcjonalne. Umożliwiają pobieranie większej ilości danych o miejscach, takich jak zdjęcia i pogoda.',
'admin.mapsKey': 'Klucz Google Maps API',
'admin.mapsKeyHint': 'Wymagany do wyszukiwania miejsc. Uzyskaj go na console.cloud.google.com',
'admin.mapsKeyHintLong':
'Bez klucza API, OpenStreetMap jest wykorzystywany do wyszukiwania miejsc. Z kluczem API Google, zdjęcia, oceny i godziny otwarcia również mogą być pobierane. Uzyskaj go na console.cloud.google.com.',
'admin.recommended': 'Polecane',
'admin.weatherKey': 'Klucz OpenWeatherMap API',
'admin.weatherKeyHint': 'Do danych pogodowych. Uzyskaj go bezpłatnie na openweathermap.org',
'admin.unsplashKey': 'Klucz API Unsplash',
'admin.unsplashKeyHint': 'Do wyszukiwania obrazów. Bezpłatnie na unsplash.com/developers',
'admin.validateKey': 'Testuj',
'admin.keyValid': 'Połączono',
'admin.keyInvalid': 'Niepoprawny',
'admin.keySaved': 'Klucze API zostały zapisane',
'admin.oidcTitle': 'Logowanie jednokrotne (OIDC)',
'admin.oidcSubtitle':
'Zezwól na logowanie za pomocą zewnętrznych dostawców, takich jak Google, Apple, Authentik lub Keycloak.',
'admin.oidcDisplayName': 'Wyświetlana nazwa',
'admin.oidcIssuer': 'URL wystawcy',
'admin.oidcIssuerHint': 'Adres URL wystawcy OpenID Connect dostawcy, np. https://accounts.google.com',
'admin.oidcSaved': 'Konfiguracja OIDC została zapisana',
'admin.oidcOnlyMode': 'Wyłącz uwierzytelnianie hasłem',
'admin.oidcOnlyModeHint':
'Po włączeniu dozwolone jest tylko logowanie jednokrotne. Logowanie i rejestracja za pomocą hasła są zablokowane.',
'admin.fileTypes': 'Dozwolone typy plików',
'admin.fileTypesHint': 'Ustaw, które typy plików mogą być przesyłane przez użytkowników.',
'admin.fileTypesFormat':
'Rozszerzenia oddzielone przecinkami (np. jpg,png,pdf,doc). Użyj * aby zezwolić na wszystkie typy.',
'admin.fileTypesSaved': 'Ustawienia typów plików zostały zapisane',
'admin.placesPhotos.title': 'Zdjęcia miejsc',
'admin.placesPhotos.subtitle':
'Pobiera zdjęcia z Google Places API. Wyłącz, aby zaoszczędzić limit API. Zdjęcia z Wikimedia nie są objęte.',
'admin.placesAutocomplete.title': 'Autouzupełnianie miejsc',
'admin.placesAutocomplete.subtitle':
'Używa Google Places API do sugestii wyszukiwania. Wyłącz, aby zaoszczędzić limit API.',
'admin.placesDetails.title': 'Szczegóły miejsca',
'admin.placesDetails.subtitle':
'Pobiera szczegółowe informacje o miejscu (godziny, ocena, strona) z Google Places API. Wyłącz, aby zaoszczędzić limit API.',
'admin.bagTracking.title': 'Kontrola bagażu',
'admin.bagTracking.subtitle': 'Włącz wagę i przypisywanie do toreb dla przedmiotów do pakowania',
'admin.collab.chat.title': 'Czat',
'admin.collab.chat.subtitle': 'Wiadomości w czasie rzeczywistym',
'admin.collab.notes.title': 'Notatki',
'admin.collab.notes.subtitle': 'Wspólne notatki i dokumenty',
'admin.collab.polls.title': 'Ankiety',
'admin.collab.polls.subtitle': 'Ankiety grupowe i głosowania',
'admin.collab.whatsnext.title': 'Co dalej',
'admin.collab.whatsnext.subtitle': 'Sugestie aktywności i następne kroki',
'admin.tabs.config': 'Personalizacja',
'admin.tabs.defaults': 'Domyślne ustawienia',
'admin.defaultSettings.title': 'Domyślne ustawienia użytkownika',
'admin.defaultSettings.description':
'Ustaw domyślne wartości dla całej instancji. Użytkownicy, którzy nie zmienili ustawienia, zobaczą te wartości. Ich własne zmiany zawsze mają pierwszeństwo.',
'admin.defaultSettings.saved': 'Domyślne zapisane',
'admin.defaultSettings.reset': 'Przywróć wbudowaną wartość domyślną',
'admin.defaultSettings.resetToBuiltIn': 'przywróć',
'admin.tabs.templates': 'Szablony pakowania',
'admin.packingTemplates.title': 'Szablony pakowania',
'admin.packingTemplates.subtitle': 'Twórz szablony list pakowania do wielokrotnego użycia dla swoich podróży',
'admin.packingTemplates.create': 'Nowy szablon',
'admin.packingTemplates.namePlaceholder': 'Nazwa szablonu (np. Wakacje na plaży)',
'admin.packingTemplates.empty': 'Nie utworzono jeszcze żadnych szablonów',
'admin.packingTemplates.items': 'przedmiotów',
'admin.packingTemplates.categories': 'kategorie',
'admin.packingTemplates.itemName': 'Nazwa przedmiotu',
'admin.packingTemplates.itemCategory': 'Kategoria',
'admin.packingTemplates.categoryName': 'Nazwa kategorii (np. Ubrania)',
'admin.packingTemplates.addCategory': 'Dodaj kategorię',
'admin.packingTemplates.created': 'Szablon został utworzony',
'admin.packingTemplates.deleted': 'Szablon został usunięty',
'admin.packingTemplates.loadError': 'Nie udało się załadować szablonów',
'admin.packingTemplates.createError': 'Nie udało się utworzyć szablonu',
'admin.packingTemplates.deleteError': 'Nie udało się usunąć szablonu',
'admin.packingTemplates.saveError': 'Nie udało się zapisać szablonu',
'admin.tabs.addons': 'Dodatki',
'admin.tabs.plugins': 'Wtyczki',
'admin.plugins.rescan': 'Skanuj ponownie',
'admin.plugins.rescanned': 'Folder wtyczek został ponownie przeskanowany',
'admin.plugins.upload': 'Prześlij wtyczkę',
'admin.plugins.dropToUpload': 'Upuść plik .zip wtyczki, aby zainstalować',
'admin.plugins.uploaded': 'Wtyczka “{name}” przesłana — aktywuj ją, aby uruchomić',
'admin.plugins.sideloaded': 'Załadowano ręcznie',
'admin.plugins.sideloadedHint': 'Przesłano ręcznie — nie z rejestru, niepodpisane i niesprawdzone',
'admin.plugins.browse': 'Przeglądaj wtyczki',
'admin.plugins.installed': 'Zainstalowane',
'admin.plugins.install': 'Zainstaluj',
'admin.plugins.registryEmpty': 'W rejestrze nie ma jeszcze dostępnych wtyczek.',
'admin.plugins.actionError': 'Akcja nie powiodła się',
'admin.plugins.activate': 'Aktywuj',
'admin.plugins.activated': 'Wtyczka została aktywowana',
'admin.plugins.deactivate': 'Dezaktywuj',
'admin.plugins.deactivated': 'Wtyczka została dezaktywowana',
'admin.plugins.viewErrors': 'Pokaż dziennik błędów',
'admin.plugins.errorLog': 'Dziennik błędów',
'admin.plugins.noErrors': 'Brak zarejestrowanych błędów.',
'admin.plugins.uninstalled': 'Wtyczka została odinstalowana',
'admin.plugins.uninstallTitle': 'Odinstalować wtyczkę?',
'admin.plugins.uninstallBody':
'Spowoduje to zatrzymanie wtyczki, usunięcie jej kodu i wszystkich jej danych. Tej operacji nie można cofnąć.',
'admin.plugins.status.starting': 'Uruchamianie…',
'admin.plugins.type.widget': 'Widget',
'admin.plugins.type.page': 'Strona',
'admin.plugins.type.integration': 'Integracja',
'admin.plugins.type.trip-page': 'Strona podróży',
'admin.plugins.reviewed': 'Zweryfikowana',
'admin.plugins.unreviewed': 'Niezweryfikowana',
'admin.plugins.updated': 'Wtyczka została zaktualizowana',
'admin.plugins.updateTo': 'Update → v{version}',
'admin.plugins.enabledToggle': 'Włącz wtyczkę',
'plugins.notFound': 'Nie znaleziono wtyczki',
'admin.plugins.title': 'Wtyczki',
'admin.plugins.subtitle': 'Instaluj wtyczki innych autorów i zarządzaj nimi na swojej instancji.',
'admin.plugins.disabledTitle': 'Wtyczki są wyłączone',
'admin.plugins.disabledBody':
'Środowisko uruchomieniowe wtyczek jest wyłączone (TREK_PLUGINS_ENABLED). Żadna wtyczka nie może działać, dopóki administrator nie włączy tej opcji w konfiguracji serwera.',
'admin.plugins.empty': 'Nie zainstalowano jeszcze żadnych wtyczek.',
'admin.plugins.loadError': 'Nie udało się załadować wtyczek.',
'admin.plugins.scaffoldNote':
'Instalacja i aktywacja wtyczek pojawią się w późniejszej aktualizacji. Ten panel obecnie jedynie wyświetla zainstalowane wtyczki.',
'admin.plugins.status.active': 'Aktywna',
'admin.plugins.status.inactive': 'Nieaktywna',
'admin.plugins.status.disabled': 'Wyłączona',
'admin.plugins.status.error': 'Błąd',
'admin.plugins.status.incompatible': 'Niekompatybilna',
'admin.plugins.details': 'Szczegóły',
'admin.plugins.detailError': 'Nie udało się załadować szczegółów wtyczki.',
'admin.plugins.permissionsTitle': 'Uprawnienia',
'admin.plugins.noPermissions': 'Ta wtyczka nie wymaga żadnych specjalnych uprawnień.',
'admin.plugins.egressNote': 'Może łączyć się z: {hosts}',
'admin.plugins.setupTitle': 'Konfiguracja',
'admin.plugins.noSetup': 'Działa od razu — nie wymaga konfiguracji.',
'admin.plugins.scope.instance': 'Dla całej instancji',
'admin.plugins.scope.user': 'Na użytkownika',
'admin.plugins.fieldRequired': 'Wymagane',
'admin.plugins.sourceRepo': 'Repozytorium źródłowe',
'admin.plugins.homepage': 'Strona główna',
'admin.plugins.requiresTrek': 'Wymaga TREK {version}+',
'admin.plugins.reviewedOn': 'Zweryfikowano {date}',
'admin.plugins.perm.db:own': 'Przechowywanie własnych danych w izolowanej bazie danych',
'admin.plugins.perm.db:read:trips': 'Odczyt podróży, do których działający użytkownik ma dostęp',
'admin.plugins.perm.db:read:users':
'Odczyt podstawowych informacji profilowych (nazwa, awatar — nigdy dane logowania)',
'admin.plugins.perm.db:read:costs': 'Odczyt wydatków (pozycji budżetu), do których działający użytkownik ma dostęp',
'admin.plugins.perm.db:read:packing':
'Odczyt list rzeczy do spakowania w podróżach, do których działający użytkownik ma dostęp',
'admin.plugins.perm.db:read:files': 'Odczyt plików w podróżach, do których działający użytkownik ma dostęp',
'admin.plugins.perm.db:write:costs':
'Tworzenie wydatków (pozycji budżetu) w podróżach, które działający użytkownik może edytować',
'admin.plugins.perm.db:write:places':
'Dodawanie, edycja i usuwanie miejsc w podróżach, które działający użytkownik może edytować',
'admin.plugins.perm.db:write:days':
'Dodawanie, edycja i usuwanie dni w podróżach, które działający użytkownik może edytować',
'admin.plugins.perm.db:write:itinerary':
'Przypisywanie i usuwanie miejsc do dni w podróżach, które działający użytkownik może edytować',
'admin.plugins.perm.db:write:trips':
'Edycja szczegółów podróży (tytuł, daty, waluta…) w podróżach, które działający użytkownik może edytować',
'admin.plugins.perm.db:meta':
'Dołączanie własnych prywatnych danych do podróży, miejsc i dni, do których działający użytkownik ma dostęp',
'admin.plugins.perm.ws:broadcast:trip': 'Wysyłanie aktualizacji w czasie rzeczywistym do członków podróży',
'admin.plugins.perm.ws:broadcast:user': 'Wysyłanie aktualizacji w czasie rzeczywistym do poszczególnych użytkowników',
'admin.plugins.perm.hook:photo-provider': 'Dostarczanie zdjęć do sekcji Zdjęcia',
'admin.plugins.perm.hook:calendar-source': 'Dostarczanie wydarzeń do kalendarza',
'admin.plugins.perm.hook:place-detail-provider':
'Dodawanie dodatkowych szczegółów (recenzji, ocen, linków) do miejsca',
'admin.plugins.perm.hook:trip-warning-provider':
'Zgłaszanie ostrzeżeń walidacyjnych dla podróży (widocznych w planerze)',
'admin.plugins.perm.events:subscribe':
'Reagowanie na podstawowe zdarzenia aktywności (tylko nazwa zdarzenia i podróż, nigdy treść)',
'admin.plugins.perm.http:outbound': 'Wykonywanie wychodzących zapytań do zadeklarowanych hostów',
'admin.plugins.updateConsentTitle': 'Ta aktualizacja wymaga nowych uprawnień',
'admin.plugins.updateConsentBody':
'{name} v{version} prosi o uprawnienia, których jeszcze nie przyznałeś. Nowa wersja jest zainstalowana, ale pozostaje wyłączona, dopóki jej nie zatwierdzisz.',
'admin.plugins.updateNewPermissions': 'Nowo wymagane uprawnienia',
'admin.plugins.updateNewEgress': 'Nowe połączenia wychodzące',
'admin.plugins.updateApprove': 'Zatwierdź i włącz',
'admin.plugins.updateLater': 'Na razie pozostaw wyłączoną',
'admin.plugins.updateKeptOff':
'Aktualizacja zainstalowana — pozostaje wyłączona, dopóki nie zatwierdzisz nowych uprawnień',
'admin.plugins.reviewedMeaning':
'„Zweryfikowana” oznacza, że opiekun TREK przeskanował tę wtyczkę pod kątem złośliwego oprogramowania w każdej wersji — nie pod kątem jakości ani tego, czy działa. To nie jest gwarancja, że wtyczka jest nieszkodliwa.',
'admin.plugins.security.title': 'Jak wtyczki są izolowane — i jakie są tego granice',
'admin.plugins.security.isolationTitle': 'Każda wtyczka działa w izolacji',
'admin.plugins.security.isolationBody':
'Wtyczka działa jako własny, odizolowany proces, który może odczytywać wyłącznie swoje własne pliki. Nie może odczytać Twojej bazy danych, sekretu logowania ani klucza szyfrującego, nie może uruchamiać innych programów ani nigdzie zapisywać plików. Jej interfejs działa w zamkniętej ramce przeglądarki, która nie może odczytać Twojego pliku cookie sesji ani ingerować w otaczającą ją stronę TREK.',
'admin.plugins.security.permsTitle': 'Co oznaczają uprawnienia',
'admin.plugins.security.permsBody':
'Uprawnienia pokazywane przed instalacją to twarda granica, którą TREK egzekwuje w trakcie działania wtyczki — dosłownie nie może ona zrobić niczego, czego nie ma na liście. Mówią one jednak, co wtyczka może robić, a nie co faktycznie robi. Wtyczka, która może odczytywać Twoje podróże i łączyć się z serwerem, może wysłać Twoje podróże na ten serwer, dlatego czytaj uprawnienia i hosty wychodzące, a nie tylko opis.',
'admin.plugins.security.limitsTitle': 'Czego nie możemy obiecać',
'admin.plugins.security.limitsBody':
'Izolacja to silna granica programowa, ale nie absolutna. Wtyczka działa dokładnie z tymi uprawnieniami, które zatwierdzisz, więc w ich ramach może zachowywać się inaczej, niż sugeruje jej opis, i może wysyłać dane, do których ma zgodny z uprawnieniami dostęp, do zadeklarowanych przez siebie hostów. TREK nie odczytuje ani nie ocenia tego, co faktycznie robi kod wtyczki.',
'admin.plugins.security.worstTitle': 'Najgorszy scenariusz',
'admin.plugins.security.worstBody':
'Wroga wtyczka, którą włączysz, może nadużyć danych i połączeń, które jej przyznałeś — na przykład ujawnić podróże, które może odczytywać. Nie może wykraść haseł, sfałszować logowania administratora, uruchamiać poleceń na Twoim serwerze ani sięgać po dane, których jej nie przyznałeś. Szkody pozostają w granicach tego, co zatwierdziłeś, a wyłączenie wtyczki je zatrzymuje.',
'admin.plugins.security.reviewedTitle': 'Co oznacza „Zweryfikowana”',
'admin.plugins.security.reviewedBody':
'Zweryfikowana wtyczka została ręcznie przeskanowana pod kątem złośliwego oprogramowania przez opiekuna TREK w każdej wersji — sprawdzona pod kątem wrogiego kodu, a nie tego, czy działa dobrze. To nie jest obietnica, że wtyczka jest nieszkodliwa.',
'admin.plugins.security.trustTitle': 'Podsumowanie',
'admin.plugins.security.trustBody':
'Instalacja wtyczki jest jak instalacja dowolnej aplikacji innych firm: dodawaj tylko kod od autorów, którym ufasz, a w razie wątpliwości najpierw samodzielnie go sprawdź. TREK nie ponosi żadnej odpowiedzialności za wtyczki innych firm.',
'admin.plugins.runtimeOn': 'Środowisko włączone',
'admin.plugins.tabDiscover': 'Odkrywaj',
'admin.plugins.searchPlaceholder': 'Szukaj wtyczek…',
'admin.plugins.filterType': 'Typ',
'admin.plugins.filterStatus': 'Status',
'admin.plugins.sortBy': 'Sortuj',
'admin.plugins.allTypes': 'Wszystkie typy',
'admin.plugins.allStatuses': 'Wszystkie',
'admin.plugins.stateOff': 'Wył.',
'admin.plugins.filterUpdate': 'Dostępna aktualizacja',
'admin.plugins.sortName': 'Nazwa',
'admin.plugins.sortRecent': 'Ostatnio zaktualizowane',
'admin.plugins.sortUpdates': 'Najpierw aktualizacje',
'admin.plugins.updatesAvailable': 'Dostępne aktualizacje dla Twoich wtyczek: {count}.',
'admin.plugins.updateAll': 'Zaktualizuj wszystkie',
'admin.plugins.noMatchInstalled': 'Żadna zainstalowana wtyczka nie pasuje do wyszukiwania.',
'admin.plugins.noMatchRegistry': 'Żadna wtyczka w rejestrze nie pasuje do wyszukiwania.',
'admin.plugins.restart': 'Uruchom ponownie',
'admin.plugins.restarted': 'Wtyczka została uruchomiona ponownie',
'admin.plugins.cap.readsTrips': 'Odczytuje Twoje podróże',
'admin.plugins.cap.readsUsers': 'Odczytuje podstawowe profile',
'admin.plugins.cap.readsCosts': 'Odczytuje Twoje wydatki',
'admin.plugins.cap.readsPacking': 'Odczytuje listy pakowania',
'admin.plugins.cap.readsFiles': 'Odczytuje pliki podróży',
'admin.plugins.cap.writesCosts': 'Dodaje wydatki',
'admin.plugins.cap.writesPlaces': 'Edytuje miejsca',
'admin.plugins.cap.writesDays': 'Edytuje dni',
'admin.plugins.cap.writesItinerary': 'Edytuje plan podróży',
'admin.plugins.cap.writesTrips': 'Edytuje podróże',
'admin.plugins.cap.metadata': 'Dodaje metadane',
'admin.plugins.cap.widget': 'Widget na pulpicie',
'admin.plugins.cap.heroWidget': 'Widget karty pokładowej',
'admin.plugins.cap.placeSlot': 'Szczegóły miejsca',
'admin.plugins.cap.realtime': 'Aktualizacje na żywo',
'admin.plugins.cap.photos': 'Dostarcza zdjęcia',
'admin.plugins.cap.calendar': 'Dostarcza wydarzenia kalendarza',
'admin.plugins.cap.placeDetails': 'Wzbogaca miejsca',
'admin.plugins.cap.warnings': 'Zgłasza problemy',
'admin.plugins.cap.events': 'Reaguje na aktywność',
'admin.plugins.cap.requiresAddon': 'Wymaga {addon}',
'admin.plugins.cap.dependsOn': 'Wymaga {id} {version}',
'admin.plugins.dep.addonDisabledToast': 'Najpierw włącz wymagane dodatki: {addons}',
'admin.plugins.dep.autoEnabled': 'Najpierw włączono wymagane wtyczki: {plugins}',
'admin.plugins.dep.downloaded': 'Pobrano {id}',
'admin.plugins.dep.resolveTitle': 'Brakujące zależności',
'admin.plugins.dep.resolveBody': '„{name}” wymaga zainstalowania tych wtyczek, zanim będzie można ją włączyć.',
'admin.plugins.dep.requires': 'Wymaga {version}',
'admin.plugins.dep.mismatch': 'Wymaga {wanted} — zainstalowano {installed}',
'admin.plugins.dep.download': 'Pobierz',
'admin.plugins.dep.update': 'Aktualizuj',
'admin.plugins.dep.resolveHint': 'Pobiera najnowszą zgodną wersję wraz z jej zależnościami.',
'admin.plugins.accessTitle': 'Do czego ma dostęp',
'admin.plugins.connectsTitle': 'Łączy się z',
'admin.plugins.detailsTitle': 'Szczegóły',
'admin.plugins.noAccess': 'Nie wymaga specjalnego dostępu.',
'admin.plugins.metaVersion': 'Wersja',
'admin.plugins.metaSize': 'Rozmiar',
'admin.plugins.metaRequires': 'Wymaga',
'admin.plugins.metaReviewed': 'Zweryfikowano',
'admin.addons.title': 'Dodatki',
'admin.addons.subtitle': 'Włączaj lub wyłączaj funkcje, aby dostosować swoje doświadczenie w TREK.',
'admin.addons.catalog.packing.name': 'Listy',
'admin.addons.catalog.packing.description': 'Listy pakowania i zadania do wykonania dla Twoich podróży',
'admin.addons.catalog.budget.name': 'Budżet',
'admin.addons.catalog.budget.description': 'Śledź wydatki i planuj budżet podróży',
'admin.addons.catalog.documents.name': 'Dokumenty',
'admin.addons.catalog.documents.description': 'Przechowuj i zarządzaj dokumentami podróżnymi',
'admin.addons.catalog.vacay.name': 'Urlopy',
'admin.addons.catalog.vacay.description': 'Osobisty planer urlopu z widokiem kalendarza',
'admin.addons.catalog.atlas.name': 'Atlas',
'admin.addons.catalog.atlas.description': 'Mapa świata z odwiedzonymi krajami i statystykami podróży',
'admin.addons.catalog.collab.name': 'Współpraca',
'admin.addons.catalog.collab.description': 'Notatki w czasie rzeczywistym, ankiety i czat do planowania podróży',
'admin.addons.catalog.memories.name': 'Zdjęcia (Immich)',
'admin.addons.catalog.memories.description': 'Udostępniaj zdjęcia z podróży za pośrednictwem swojej instancji Immich',
'admin.addons.catalog.mcp.name': 'MCP',
'admin.addons.catalog.mcp.description': 'Model Context Protocol dla integracji asystenta AI',
'admin.addons.subtitleBefore': 'Włączaj lub wyłączaj funkcje, aby dostosować swoje doświadczenie w ',
'admin.addons.subtitleAfter': '.',
'admin.addons.enabled': 'Włączone',
'admin.addons.disabled': 'Wyłączone',
'admin.addons.type.trip': 'Podróż',
'admin.addons.type.global': 'Globalne',
'admin.addons.type.integration': 'Integracja',
'admin.addons.tripHint': 'Dostępne jako zakładka w każdej podróży',
'admin.addons.globalHint': 'Dostępne jako osobna sekcja w menu głównym',
'admin.addons.integrationHint': 'Usługi backendowe i integracje API bez dedykowanej strony',
'admin.addons.toast.updated': 'Dodatek został zaktualizowany',
'admin.addons.toast.error': 'Nie udało się zaktualizować dodatku',
'admin.addons.noAddons': 'Brak dostępnych dodatków',
'admin.weather.title': 'Dane pogodowe',
'admin.weather.badge': 'Od 24 marca 2026',
'admin.weather.description':
'TREK korzysta z Open-Meteo jako źródła danych pogodowych. Open-Meteo to darmowy, otwartoźródłowy serwis pogodowy — klucz API nie jest wymagany.',
'admin.weather.forecast': '16-dniowa prognoza',
'admin.weather.forecastDesc': 'Wcześniej 5 dni (OpenWeatherMap)',
'admin.weather.climate': 'Historyczne dane klimatyczne',
'admin.weather.climateDesc': 'Średnie z ostatnich 85 lat dla dni poza 16-dniową prognozą',
'admin.weather.requests': '10,000 zapytań / dzień',
'admin.weather.requestsDesc': 'Bezpłatnie, bez klucza API',
'admin.weather.locationHint':
'Pogoda jest określana na podstawie pierwszego miejsca z przypisanymi współrzędnymi w danym dniu. Jeśli do dnia nie przypisano żadnego miejsca, jako punkt odniesienia używane jest dowolne miejsce z listy.',
'admin.tabs.mcpTokens': 'Dostęp MCP',
'admin.mcpTokens.title': 'Dostęp MCP',
'admin.mcpTokens.subtitle': 'Zarządzaj sesjami OAuth i tokenami API dla wszystkich użytkowników',
'admin.mcpTokens.sectionTitle': 'Tokeny API',
'admin.mcpTokens.owner': 'Właściciel',
'admin.mcpTokens.tokenName': 'Nazwa tokenu',
'admin.mcpTokens.created': 'Utworzono',
'admin.mcpTokens.lastUsed': 'Ostatnio użyto',
'admin.mcpTokens.never': 'Nigdy',
'admin.mcpTokens.empty': 'Nie utworzono jeszcze żadnych tokenów MCP',
'admin.mcpTokens.deleteTitle': 'Usuń token',
'admin.mcpTokens.deleteMessage':
'Spowoduje to natychmiastowe unieważnienie tokenu. Użytkownik straci dostęp MCP przez ten token.',
'admin.mcpTokens.deleteSuccess': 'Token został usunięty',
'admin.mcpTokens.deleteError': 'Nie udało się usunąć tokenu',
'admin.mcpTokens.loadError': 'Nie udało się załadować tokenów',
'admin.oauthSessions.sectionTitle': 'Sesje OAuth',
'admin.oauthSessions.clientName': 'Klient',
'admin.oauthSessions.owner': 'Właściciel',
'admin.oauthSessions.scopes': 'Uprawnienia',
'admin.oauthSessions.created': 'Utworzono',
'admin.oauthSessions.empty': 'Brak aktywnych sesji OAuth',
'admin.oauthSessions.revokeTitle': 'Unieważnij sesję',
'admin.oauthSessions.revokeMessage': 'Ta sesja OAuth zostanie natychmiast unieważniona. Klient straci dostęp do MCP.',
'admin.oauthSessions.revokeSuccess': 'Sesja unieważniona',
'admin.oauthSessions.revokeError': 'Nie udało się unieważnić sesji',
'admin.oauthSessions.loadError': 'Nie udało się załadować sesji OAuth',
'admin.tabs.github': 'GitHub',
'admin.audit.subtitle':
'Zdarzenia związane z bezpieczeństwem i administracją (kopie zapasowe, użytkownicy, MFA, ustawienia).',
'admin.audit.empty': 'Brak zapisów w historii aktywności.',
'admin.audit.refresh': 'Odśwież',
'admin.audit.loadMore': 'Załaduj więcej',
'admin.audit.showing': '{count} załadowanych · {total} łącznie',
'admin.audit.col.time': 'Czas',
'admin.audit.col.user': 'Użytkownik',
'admin.audit.col.action': 'Akcja',
'admin.audit.col.resource': 'Zasób',
'admin.audit.col.ip': 'IP',
'admin.audit.col.details': 'Szczegóły',
'admin.github.title': 'Historia wydań',
'admin.github.subtitle': 'Najnowsze aktualizacje z {repo}',
'admin.github.latest': 'Najnowsze',
'admin.github.prerelease': 'Wersja testowa',
'admin.github.showDetails': 'Pokaż szczegóły',
'admin.github.hideDetails': 'Ukryj szczegóły',
'admin.github.loadMore': 'Załaduj więcej',
'admin.github.loading': 'Ładowanie...',
'admin.github.error': 'Nie udało się załadować wydań',
'admin.github.by': 'przez',
'admin.github.support': 'Pomóż mi rozwijać TREK',
'admin.update.available': 'Dostępna aktualizacja',
'admin.update.text': 'Dostępna jest wersja TREK {version}. Używasz {current}.',
'admin.update.button': 'Zobacz na GitHubie',
'admin.update.install': 'Zainstaluj aktualizację',
'admin.update.confirmTitle': 'Zainstalować aktualizację?',
'admin.update.confirmText':
'TREK zostanie zaktualizowany z {current} do {version}. Serwer zostanie automatycznie zrestartowany po zakończeniu.',
'admin.update.dataInfo':
'Wszystkie twoje dane (podróże, użytkownicy, klucze API, przesłane pliki, urlopy, Atlas, budżety) zostaną zachowane.',
'admin.update.warning': 'Aplikacja będzie niedostępna przez krótki czas podczas restartu.',
'admin.update.confirm': 'Zaktualizuj',
'admin.update.installing': 'Aktualizowanie...',
'admin.update.success': 'Aktualizacja zakończona! Serwer restartuje się...',
'admin.update.failed': 'Aktualizacja nie powiodła się',
'admin.update.backupHint': 'Zalecamy utworzenie kopii zapasowej przed aktualizacją.',
'admin.update.backupLink': 'Zrób kopię zapasową',
'admin.update.howTo': 'Jak zaktualizować',
'admin.update.dockerText':
'Twoja instancja TREK działa w Dockerze. Aby zaktualizować do {version}, uruchom następujące polecenia na swoim serwerze:',
'admin.update.nonDockerText':
'Ta instancja TREK nie działa w Dockerze. Aby zaktualizować do {version}, uruchom ponownie metodę instalacji lub aktualizacji, której użyłeś — na przykład w Proxmox Community Scripts uruchom aktualizację z konsoli LXC:',
'admin.update.wikiLink': 'Otwórz przewodnik aktualizacji',
'admin.update.reloadHint': 'Proszę odświeżyć stronę za kilka sekund.',
'admin.notifications.title': 'Powiadomienia',
'admin.notifications.hint': 'Wybierz jeden kanał powiadomień.',
'admin.notifications.none': 'Wyłączone',
'admin.notifications.email': 'E-mail (SMTP)',
'admin.notifications.webhook': 'Webhook',
'admin.notifications.save': 'Zapisz ustawienia powiadomień',
'admin.notifications.saved': 'Ustawienia powiadomień zapisane',
'admin.notifications.testWebhook': 'Wyślij testowy webhook',
'admin.notifications.testWebhookSuccess': 'Testowy webhook wysłany pomyślnie',
'admin.notifications.testWebhookFailed': 'Testowy webhook nie powiódł się',
'admin.notifications.emailPanel.title': 'Email (SMTP)',
'admin.notifications.webhookPanel.title': 'Webhook',
'admin.notifications.inappPanel.title': 'In-App',
'admin.notifications.inappPanel.hint':
'Powiadomienia w aplikacji są zawsze aktywne i nie można ich globalnie wyłączyć.',
'admin.notifications.adminWebhookPanel.title': 'Webhook admina',
'admin.notifications.adminWebhookPanel.hint':
'Ten webhook służy wyłącznie do powiadomień admina (np. alertów o nowych wersjach). Jest niezależny od webhooków użytkowników i wysyła automatycznie, gdy URL jest skonfigurowany.',
'admin.notifications.adminWebhookPanel.saved': 'URL webhooka admina zapisany',
'admin.notifications.adminWebhookPanel.testSuccess': 'Testowy webhook wysłany pomyślnie',
'admin.notifications.adminWebhookPanel.testFailed': 'Wysyłanie testowego webhooka nie powiodło się',
'admin.notifications.adminWebhookPanel.alwaysOnHint':
'Webhook admina wysyła automatycznie, gdy URL jest skonfigurowany',
'admin.notifications.ntfy': 'Ntfy',
'admin.ntfy.hint':
'Pozwala użytkownikom skonfigurować własne tematy ntfy dla powiadomień push. Ustaw domyślny serwer poniżej, aby wstępnie wypełnić ustawienia użytkownika.',
'admin.notifications.testNtfy': 'Wyślij testowe Ntfy',
'admin.notifications.testNtfySuccess': 'Testowe Ntfy wysłane pomyślnie',
'admin.notifications.testNtfyFailed': 'Wysyłanie testowego Ntfy nie powiodło się',
'admin.notifications.adminNtfyPanel.title': 'Admin Ntfy',
'admin.notifications.adminNtfyPanel.hint':
'Ten temat Ntfy jest używany wyłącznie do powiadomień admina (np. alertów o wersjach). Jest niezależny od tematów użytkowników i zawsze wysyła po skonfigurowaniu.',
'admin.notifications.adminNtfyPanel.serverLabel': 'URL serwera Ntfy',
'admin.notifications.adminNtfyPanel.serverHint':
'Używany również jako domyślny serwer dla powiadomień ntfy użytkowników. Pozostaw puste, aby użyć ntfy.sh. Użytkownicy mogą to nadpisać w swoich ustawieniach.',
'admin.notifications.adminNtfyPanel.serverPlaceholder': 'https://ntfy.sh',
'admin.notifications.adminNtfyPanel.topicLabel': 'Temat admina',
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
'admin.notifications.adminNtfyPanel.tokenLabel': 'Token dostępu (opcjonalne)',
'admin.notifications.adminNtfyPanel.tokenCleared': 'Token dostępu admina wyczyszczony',
'admin.notifications.adminNtfyPanel.saved': 'Ustawienia admin Ntfy zapisane',
'admin.notifications.adminNtfyPanel.test': 'Wyślij testowe Ntfy',
'admin.notifications.adminNtfyPanel.testSuccess': 'Testowe Ntfy wysłane pomyślnie',
'admin.notifications.adminNtfyPanel.testFailed': 'Wysyłanie testowego Ntfy nie powiodło się',
'admin.notifications.adminNtfyPanel.alwaysOnHint': 'Admin Ntfy zawsze wysyła po skonfigurowaniu tematu',
'admin.notifications.adminNotificationsHint':
'Skonfiguruj, które kanały dostarczają powiadomienia admina (np. alerty o wersjach). Webhook wysyła automatycznie, gdy ustawiony jest URL webhooka admina.',
'admin.notifications.tripReminders.title': 'Przypomnienia o podróżach',
'admin.notifications.tripReminders.hint':
'Wysyła powiadomienie z przypomnieniem przed rozpoczęciem podróży (wymaga ustawienia dni przypomnienia dla podróży).',
'admin.notifications.tripReminders.enabled': 'Przypomnienia o podróżach włączone',
'admin.notifications.tripReminders.disabled': 'Przypomnienia o podróżach wyłączone',
'admin.webhook.hint':
'Pozwól użytkownikom konfigurować własne adresy URL webhooka dla powiadomień (Discord, Slack itp.).',
'admin.tabs.permissions': 'Uprawnienia',
'admin.addons.catalog.journey.name': 'Dziennik podróży',
'admin.addons.catalog.journey.description':
'Śledzenie podróży i dziennik z zameldowaniami, zdjęciami i codziennymi historiami',
'admin.addons.catalog.collections.name': 'Kolekcje',
'admin.addons.catalog.collections.description':
'Osobista biblioteka miejsc — zapisuj miejsca z podróży na nazwanych listach, kopiuj je do dowolnej podróży i udostępniaj innym',
'admin.passkey.title': 'Logowanie kluczem dostępu',
'admin.passkey.cardHint': 'Pozwól użytkownikom logować się kluczami dostępu (WebAuthn). Domyślnie wyłączone.',
'admin.passkey.login': 'Włącz logowanie kluczem dostępu',
'admin.passkey.loginHint':
'Pokaż opcję „Zaloguj się kluczem dostępu” i pozwól użytkownikom rejestrować klucze dostępu w swoich ustawieniach.',
'admin.passkey.notConfigured':
'Dla tego wdrożenia nie ustalono jeszcze żadnej domeny WebAuthn. Ustaw APP_URL lub Relying Party ID poniżej — do tego czasu klucze dostępu pozostaną ukryte.',
'admin.passkey.rpId': 'Relying Party ID (domena)',
'admin.passkey.rpIdHint':
'Sama domena, do której przypisane są klucze dostępu, np. trek.example.org. Pozostaw puste, aby wyprowadzić ją z APP_URL. Późniejsza zmiana unieważnia istniejące klucze dostępu.',
'admin.passkey.origins': 'Dozwolone origins',
'admin.passkey.originsHint':
'Pełne origins oddzielone przecinkami, np. https://trek.example.org. Pozostaw puste, aby użyć APP_URL.',
'admin.passkey.reset': 'Zresetuj klucze dostępu',
'admin.passkey.resetHint':
'Usuń wszystkie klucze dostępu tego użytkownika (np. po utracie urządzenia). Nadal będzie mógł logować się hasłem.',
'admin.passkey.resetConfirm': 'Usunąć wszystkie klucze dostępu dla {name}?',
'admin.passkey.resetDone': 'Usunięto {count} kluczy dostępu',
'admin.defaultSettings.mapProvider': 'Silnik map',
'admin.defaultSettings.mapProviderHint':
'Domyślna mapa dla wszystkich na tej instancji. Każdy użytkownik może ją zmienić we własnych ustawieniach.',
'admin.defaultSettings.providerLeaflet': 'Standardowa (bezpłatna)',
'admin.defaultSettings.providerMapbox': 'Mapbox (3D)',
'admin.defaultSettings.providerMapLibre': 'MapLibre (OpenFreeMap)',
'admin.defaultSettings.mapboxToken': 'Współdzielony token Mapbox',
'admin.defaultSettings.mapboxTokenHint':
'Używany dla każdego użytkownika, który nie wprowadził własnego tokena — dzięki temu cała instancja korzysta z Mapbox bez udostępniania klucza każdemu z osobna. Przechowywany w postaci zaszyfrowanej.',
'admin.defaultSettings.mapboxStyle': 'Styl mapy',
'admin.defaultSettings.mapboxStylePlaceholder': 'Wybierz styl…',
'admin.defaultSettings.mapbox3d': 'Budynki i teren 3D',
'admin.defaultSettings.mapboxQuality': 'Tryb wysokiej jakości',
'admin.group.users': 'Users',
'admin.group.config': 'Configuration',
'admin.group.integration': 'Integrations',
'admin.group.maintenance': 'Maintenance',
'admin.invite.tripLabel': 'Dodaj do podróży (opcjonalnie)',
'admin.invite.tripNone': 'Brak podróży',
'admin.invite.tripHint': 'Nowy użytkownik zostanie automatycznie dodany do tej podróży po rejestracji przez link.',
'admin.invite.boundTo': 'dodaje do {trip}',
};
export default admin;