Sfoglia il codice sorgente

i18n: Polish (issue #3303)

- New locale pl.ts (Polski), registered in the lazy loader, the
  supported list and the language picker.
- Polish has three plural forms and the app only _one/_other, so
  counts use label forms that read right for any number, and the
  words the code puts after a number use "szt.".
- Parity: PL_COGNATES lists the values that stay as in English
  (brands, acronyms, placeholders, loanwords), each checked.
- README: 16 languages.
maziggy 1 giorno fa
parent
commit
b3d01d45aa

+ 1 - 0
CHANGELOG.md

@@ -5,6 +5,7 @@ All notable changes to Bambuddy will be documented in this file.
 ## [1.3.1b1] - Unreleased
 
 ### Added
+- **Polish (#3303, requested by @lukg20)** — The interface is available in Polish (Polski), chosen in **Settings > General > Language**. Counts are written in forms that read correctly for any number, since the interface can't tell Polish's three plural forms apart.
 - **Each archive opens with all its prints** — An archive is one file, but everything about its prints sat on one card: its latest print's outcome, one video, one note. A click on a card (or its name in the list) now opens the archive over the list, at `/archives/<id>` so a link to it works; Escape or a click outside it closes it:
   - **The file:** thumbnail (larger on hover), what it was sliced for (printer, nozzle, bed type), its project, how often it was printed (good and failed) and the slicer's estimate for the whole file, the archive's note, and **Print** (a sliced file; a source file offers **Slice** only), **Slice**, **Edit** and a menu with **3D preview**, **Download**, **All photos** and **Delete**. A **File** section below lists layer height, nozzle, bed type, layers, size, when it was archived, its MakerWorld source and tags.
   - **Plates:** each plate of a multi-plate file with its objects, estimate, filaments, how often it printed good and failed and how far its last print ran from the estimate, its prints' finish photos and newest timelapse video, with **Print this plate** and **Show its prints**.

+ 2 - 2
README.md

@@ -242,7 +242,7 @@ Optional but recommended — drop the [`slicer-api/` Compose stack](slicer-api/R
 - **Per-filament humidity threshold** — Set a different humidity trigger per filament type (e.g. Nylon at 20%, PLA at 60%, ASA at 30%) instead of one global value. Mixed-material AMS units use the most-restrictive threshold across the loaded spools so a single PLA + Nylon unit triggers at Nylon's level. Drives both the auto-drying scheduler and the hourly humidity alarm so the two can never disagree on whether a unit is "too humid"
 - Dual external spool support for H2D (Ext-L / Ext-R)
 - **Filament Track Switch inlet binding** — Shows which AMS feeds which FTS inlet, and K-profiles follow the inlet
-- **HMS error monitoring with one-click actions** — Live HMS error log with history and the same Resume / Stop / Continue / Retry / Check Assistant / Don't Remind Me action buttons BambuStudio shows. Click and the matching MQTT command goes back to the printer — no more walking to the device just to dismiss a paused-print dialog. Catalog covers every Bambu model (X1 / P1 / A1 / H2 series); buttons are translated in all 15 supported languages
+- **HMS error monitoring with one-click actions** — Live HMS error log with history and the same Resume / Stop / Continue / Retry / Check Assistant / Don't Remind Me action buttons BambuStudio shows. Click and the matching MQTT command goes back to the printer — no more walking to the device just to dismiss a paused-print dialog. Catalog covers every Bambu model (X1 / P1 / A1 / H2 series); buttons are translated in all 16 supported languages
 - **Heater history charts** — Bambuddy logs nozzle, bed, and chamber readings every minute and surfaces them via a tiny chart icon on each heater tile in the printer card. Click for a per-heater modal with current / average / min / max stats, target overlay, and a 6h / 24h / 48h / 7d time range — works on read-only chamber sensors (X1C / P2S) too. AMS humidity and temperature get the same treatment (already shipped).
 - Print success rates & trends
 - Filament usage tracking
@@ -438,7 +438,7 @@ Optional but recommended — drop the [`slicer-api/` Compose stack](slicer-api/R
 </tr>
 </table>
 
-**Plus:** Configurable slicer (Bambu Studio / OrcaSlicer) • Customizable themes (style, background, accent) • Mobile responsive • Keyboard shortcuts • 15 languages (EN/DE/ES/FR/IT/JA/KO/NL/PT-BR/RU/SV/TR/UK/ZH-CN/ZH-TW) • Auto updates • Database backup/restore • System info dashboard
+**Plus:** Configurable slicer (Bambu Studio / OrcaSlicer) • Customizable themes (style, background, accent) • Mobile responsive • Keyboard shortcuts • 16 languages (EN/DE/ES/FR/IT/JA/KO/NL/PL/PT-BR/RU/SV/TR/UK/ZH-CN/ZH-TW) • Auto updates • Database backup/restore • System info dashboard
 
 ---
 

+ 33 - 0
frontend/scripts/check-i18n-parity.mjs

@@ -485,6 +485,38 @@ const NL_COGNATES = [
   'Warm', '{{weight}}g', 'Workflow',
 ];
 
+// Polish cognates — brand names, acronyms, format strings and the technical
+// words Polish UIs use verbatim. Checked against pl.ts entry by entry.
+const PL_COGNATES = [
+  'MakerWorld: {{designer}}',
+  '{{printer}}: {{error}}',
+  'Bambu Cloud', 'Orca Cloud',
+  'Sport (124%)', 'Ludicrous (166%)',
+  'email',
+  '{{name}} — {{stage}} ({{percent}}%) — {{elapsed}}',
+  'EC984C,#6CD4BC,A66EB9,D87694',
+  '({{count}}/8)',
+  '(25%, 50%, 75%)',
+
+  // Loanwords, brands, Bambu's own plate/finish names, acronyms, placeholders:
+  'Filament', 'MakerWorld', 'System', 'Status', 'Model', 'Offline', 'Problem', 'Firmware',
+  '{{filament}} @ {{temp}}°C', 'L', '{{ams}} · Slot {{slot}}', 'GCODE', '{{weight}}g',
+  '{{name}} - Timelapse', 'SJF', 'G-code', 'Timelapse', 'SpoolBuddy', 'LDAP', 'SSO / OIDC', 'Online', 'NFC',
+  'Spoolman', 'Auto', 'Slicer', 'Hex', 'ISO (YYYY-MM-DD)', 'Bambu Studio', 'OrcaSlicer',
+  'http://192.168.1.61:1984/api/frame.jpeg?src=printer', 'Home Assistant', 'Port', 'OK', 'Client ID',
+  'Client Secret', 'Filament {{n}}', '{{shown}} / {{total}}', '000000', 'XXXXXXXX', 'user@example.com',
+  'Branding', 'Pressure Advance', 'Region', 'README', 'https://printables.com/model/...', 'URL',
+  'https://makerworld.com/...', 'Filament {{index}} ({{type}})', 'Cool Plate', 'Cool Plate SuperTack',
+  'Engineering Plate', 'Smooth PEI Plate / High Temp Plate', 'Textured PEI Plate', '(Spoolman)', 'Slot',
+  'Jade White, Fire Red...', 'Galaxy', 'Gradient', 'AMS', '?', 'K', 'https://github.com/username/repo-name',
+  'https://gitea.example.com/username/repo-name', 'https://forgejo.example.com/username/repo-name',
+  'https://gitlab.com/username/repo-name', 'GitHub', 'GitLab', 'Gitea', 'Forgejo', 'Commit', '0.020',
+  'Proxy', 'SHA-256', '{{count}} filament', 'ON, true, 1', 'Live Activities (iOS)', 'Notify!',
+  'CallMeBot/WhatsApp', 'ntfy', 'Pushover', 'Telegram', 'Discord', 'Webhook', 'Bark', 'Gotify', 'Start',
+  'Test', 'Hex: #{{hex}}', 'BamBuddy', '-', 'Tag', 'Host', 'Manyfold', 'http://192.168.1.10:3214',
+  'Skirt / brim', 'Folder', 'SKU', 'Trend', 'ROP', 'SS', '{{count}} alert', 'CSV',
+];
+
 const IDENTICAL_TO_EN_ALLOWED = {
   de: new Set(DE_COGNATES),
   fr: new Set(FR_COGNATES),
@@ -500,6 +532,7 @@ const IDENTICAL_TO_EN_ALLOWED = {
   ru: new Set(RU_COGNATES),
   uk: new Set(UK_COGNATES),
   nl: new Set(NL_COGNATES),
+  pl: new Set(PL_COGNATES),
 };
 
 // Pure comparison logic, exported so tests can verify each failure mode

+ 3 - 1
frontend/src/i18n/index.ts

@@ -14,6 +14,7 @@ const LOCALE_LOADERS: Record<string, () => Promise<{ default: ResourceLanguage }
   ja: () => import('./locales/ja'),
   it: () => import('./locales/it'),
   nl: () => import('./locales/nl'),
+  pl: () => import('./locales/pl'),
   ko: () => import('./locales/ko'),
   'pt-BR': () => import('./locales/pt-BR'),
   'zh-CN': () => import('./locales/zh-CN'),
@@ -48,7 +49,7 @@ export const localeBackend: BackendModule = {
   },
 };
 
-const SUPPORTED_LNGS = ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'nl', 'pt-BR', 'ru', 'sv', 'tr', 'uk', 'zh-CN', 'zh-TW'];
+const SUPPORTED_LNGS = ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'nl', 'pl', 'pt-BR', 'ru', 'sv', 'tr', 'uk', 'zh-CN', 'zh-TW'];
 const APPLIANCE_CONSUMED_KEY = 'bambuddy_appliance_locale_consumed';
 
 /** Settles once the language in use has loaded (or failed to). */
@@ -127,6 +128,7 @@ export const availableLanguages = [
   { code: 'it', name: 'Italian', nativeName: 'Italiano' },
   { code: 'ko', name: 'Korean', nativeName: '한국어' },
   { code: 'nl', name: 'Dutch', nativeName: 'Nederlands' },
+  { code: 'pl', name: 'Polish', nativeName: 'Polski' },
   { code: 'pt-BR', name: 'Portuguese (Brazil)', nativeName: 'Português (Brasil)' },
   { code: 'zh-CN', name: 'Chinese (Simplified)', nativeName: '简体中文' },
   { code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '繁體中文' },

+ 8586 - 0
frontend/src/i18n/locales/pl.ts

@@ -0,0 +1,8586 @@
+export default {
+  // Navigation
+  nav: {
+    printers: 'Drukarki',
+    archives: 'Archiwa',
+    queue: 'Kolejka druku',
+    stats: 'Statystyki',
+    profiles: 'Profile',
+    maintenance: 'Konserwacja',
+    projects: 'Projekty',
+    finance: 'Finanse',
+    inventory: 'Filament',
+    files: 'Menedżer plików',
+    makerworld: 'MakerWorld',
+    modelSources: 'Źródła modeli',
+    notifications: 'Powiadomienia',
+    settings: 'Ustawienia',
+    system: 'System',
+    collapseSidebar: 'Zwiń pasek boczny',
+    expandSidebar: 'Rozwiń pasek boczny',
+    update: 'Aktualizacja',
+    updateAvailable: 'Dostępna aktualizacja: v{{version}}',
+    updateAvailableBanner: 'Dostępna jest wersja {{version}}!',
+    viewUpdate: 'Pokaż aktualizację',
+    viewOnGithub: 'Zobacz na GitHub',
+    keyboardShortcuts: 'Skróty klawiszowe (?)',
+    switchToLight: 'Przełącz na tryb jasny',
+    switchToDark: 'Przełącz na tryb ciemny',
+    switchToSystem: 'Przełącz na tryb systemowy',
+    smartSwitches: 'Inteligentne przełączniki',
+    logout: 'Wyloguj',
+    installApp: 'Zainstaluj aplikację',
+    installAppSuccess: 'Bambuddy został zainstalowany',
+  },
+
+  // Common
+  announcements: {
+    title: 'Ogłoszenia',
+    unread: 'Nieprzeczytane ogłoszenia: {{count}}',
+    empty: 'Brak ogłoszeń.',
+    earlier: 'Wcześniejsze ({{count}})',
+    new: 'Nowe',
+    readMore: 'Czytaj więcej',
+    readMoreCount: 'Czytaj więcej (+{{count}})',
+    gotIt: 'Rozumiem',
+    source: 'Od opiekunów Bambuddy, pobrane z GitHub. Możesz je wyłączyć w Ustawieniach.',
+    level: {
+      info: 'Informacja',
+      important: 'Ważne',
+      critical: 'Krytyczne',
+    },
+  },
+  common: {
+    secretKept: 'Zapisano. Pozostaw bez zmian, aby zachować, lub wpisz nową wartość.',
+    secretReenter: 'Adres się zmienił: wpisz go ponownie. Nic nie zostanie zapisane, dopóki tego nie zrobisz.',
+    plusNMore: '+{{count}} więcej',
+    save: 'Zapisz',
+    saving: 'Zapisywanie...',
+    cancel: 'Anuluj',
+    delete: 'Usuń',
+    edit: 'Edytuj',
+    add: 'Dodaj',
+    close: 'Zamknij',
+    confirm: 'Potwierdź',
+    loading: 'Ładowanie...',
+    error: 'Błąd',
+    errorLoading: 'Błąd ładowania danych',
+    retry: 'Ponów',
+    success: 'Sukces',
+    warning: 'Ostrzeżenie',
+    enabled: 'Włączone',
+    disabled: 'Wyłączone',
+    yes: 'Tak',
+    no: 'Nie',
+    on: 'Wł.',
+    off: 'Wył.',
+    all: 'Wszystkie',
+    none: 'Brak',
+    search: 'Szukaj',
+    filter: 'Filtruj',
+    sort: 'Sortuj',
+    refresh: 'Odśwież',
+    download: 'Pobierz',
+    upload: 'Prześlij',
+    uploading: 'Przesyłanie...',
+    uploadFailed: 'Przesyłanie nie powiodło się',
+    actions: 'Akcje',
+    status: 'Status',
+    name: 'Nazwa',
+    user: 'Użytkownik',
+    description: 'Opis',
+    date: 'Data',
+    time: 'Czas',
+    hours: 'godz.',
+    minutes: 'min',
+    seconds: 'sek.',
+    days: 'dni',
+    enable: 'Włącz',
+    disable: 'Wyłącz',
+    permissions: 'Uprawnienia',
+    noPrinters: 'Brak skonfigurowanych drukarek',
+    noData: 'Brak danych',
+    linkNotFound: 'Nie znaleziono linku',
+    required: 'Wymagane',
+    optional: 'Opcjonalne',
+    dismiss: 'Odrzuć',
+    apply: 'Zastosuj',
+    reset: 'Resetuj',
+    export: 'Eksportuj',
+    import: 'Importuj',
+    clear: 'Wyczyść',
+    selectAll: 'Zaznacz wszystko',
+    deselectAll: 'Odznacz wszystko',
+    noChange: '— Bez zmian —',
+    unchanged: 'Bez zmian',
+    unassigned: 'Nieprzypisane',
+    unknown: 'Nieznane',
+    unknownError: 'Nieznany błąd',
+    today: 'Dzisiaj',
+    tomorrow: 'Jutro',
+    asap: 'Jak najszybciej',
+    overdue: 'Po terminie',
+    now: 'Teraz',
+    collapse: 'Zwiń',
+    expand: 'Rozwiń',
+    previous: 'Poprzedni',
+    next: 'Następny',
+    viewArchive: 'Pokaż archiwum',
+    viewInFileManager: 'Pokaż w menedżerze plików',
+    addedBy: 'Dodane przez {{username}}',
+    prints: 'wydruki',
+    more: '+{{count}} więcej',
+    ascending: 'Rosnąco',
+    descending: 'Malejąco',
+    back: 'Wstecz',
+    copy: 'Kopiuj',
+    copied: 'Skopiowano!',
+    printer: 'Drukarka',
+    remove: 'Usuń',
+    type: 'Typ',
+    print: 'Drukuj',
+    rename: 'Zmień nazwę',
+    move: 'Przenieś',
+    create: 'Utwórz',
+    duplicate: 'Duplikuj',
+    left: 'Lewy',
+    right: 'Prawy',
+    run: 'Uruchom',
+    running: 'Uruchamianie...',
+  },
+
+  finance: {
+    allTypes: 'Wszystkie typy',
+    allCostCenters: 'Wszystkie centra kosztów',
+    title: 'Finanse',
+    subtitle: 'Portfel, transakcje osobiste i centra kosztów',
+    noAccess: 'Nie masz uprawnień do wyświetlania danych finansowych.',
+    personalView: 'Widok osobisty',
+    adminView: 'Widok administratora',
+    createCostCenter: 'Utwórz centrum kosztów',
+    adjustWallet: 'Koryguj portfel',
+    addManualPrint: 'Dodaj wydruk ręcznie',
+    manageMembers: 'Zarządzaj członkami centrum kosztów',
+    currentBalance: 'Saldo osobiste',
+    transactions: 'Transakcje',
+    personalTransactions: 'Transakcje osobiste',
+    costCenters: 'Centra kosztów',
+    availableForPrinting: 'Dostępne do przypisania wydruków',
+    costCenterName: 'Nazwa',
+    budgetType: 'Typ budżetu',
+    monthlyBudget: 'Budżet miesięczny',
+    totalBudget: 'Budżet całkowity',
+    noBudget: "Brak budżetu",
+    create: 'Utwórz',
+    selectUser: 'Wybierz użytkownika',
+    transactionType: 'Typ',
+    amount: 'Kwota',
+    noCostCenter: 'Brak centrum kosztów',
+    descriptionOptional: 'Opis (opcjonalnie)',
+    applyAdjustment: 'Zastosuj korektę',
+    memberCanPrint: 'Członek może drukować',
+    addMember: 'Dodaj członka',
+    canPrint: 'Może drukować',
+    noMembers: 'Brak przypisanych członków.',
+    editCostCenter: 'Edytuj centrum kosztów',
+    myCostCenters: 'Moje centra kosztów',
+    costCentersHint: 'Sprawdzaj limity budżetu i kontroluj koszty',
+    noCostCenters: 'Nie znaleziono centrów kosztów.',
+    owner: 'Właściciel',
+    balance: 'Saldo konta',
+    unlimited: 'Bez limitu',
+    budgetPolicyHint: 'Salda kont śledzą koszty. Drukowanie jest ograniczone wyłącznie budżetem wybranego centrum kosztów; bez budżetu drukowanie jest nieograniczone.',
+    budget: 'Budżet',
+    shared: 'Współdzielone',
+    cannotEditPrivateCostCenter: 'Prywatnych centrów kosztów nie można tu edytować',
+    recentTransactions: 'Ostatnie transakcje',
+    transactionsHint: 'Filtruj według typu i centrum kosztów',
+    first: 'Pierwsza',
+    prev: 'Poprzednia',
+    next: 'Następna',
+    last: 'Ostatnia',
+    pageNumberOf: 'Strona {{page}} z {{total}}',
+    noTransactions: 'Brak transakcji.',
+    noTransactionsForFilter: 'Żadna transakcja nie pasuje do wybranych filtrów.',
+    costCenter: 'Centrum kosztów',
+    balanceAfter: 'Saldo po',
+    userWithId: 'Użytkownik #{{id}}',
+    deletedUser: 'Usunięty użytkownik',
+    noUser: 'Brak użytkownika',
+    partial: 'Częściowy',
+    editTransaction: 'Edytuj transakcję',
+    selectCostCenter: 'Wybierz centrum kosztów...',
+    costCenterRequired: 'Wybierz centrum kosztów',
+    amountExample: 'np. 4.00',
+    manualAdjustmentExample: 'np. Korekta ręczna',
+    userRequired: 'Wybierz użytkownika',
+    amountInvalid: 'Kwota musi być prawidłową liczbą',
+    createdCostCenter: 'Utworzono centrum kosztów',
+    createCostCenterFailed: 'Nie udało się utworzyć centrum kosztów',
+    transactionDeleted: 'Usunięto transakcję',
+    deleteTransactionFailed: 'Nie udało się usunąć transakcji',
+    transactionEdited: 'Zaktualizowano transakcję i przeliczono księgę',
+    editTransactionFailed: 'Nie udało się edytować transakcji',
+    manualPrintCreated: 'Dodano opłatę za wydruk ręczny i przeliczono księgę',
+    manualPrintFailed: 'Nie udało się utworzyć wydruku ręcznego',
+    memberSaved: 'Zapisano członka',
+    memberSaveFailed: 'Nie udało się zapisać członka',
+    memberRemoved: 'Usunięto członka',
+    memberRemoveFailed: 'Nie udało się usunąć członka',
+    costCenterNameRequired: 'Nazwa centrum kosztów jest wymagana',
+    costCenterUpdated: 'Zaktualizowano centrum kosztów',
+    costCenterUpdateFailed: 'Nie udało się zaktualizować centrum kosztów',
+    confirmDeleteCostCenter: 'Usunąć centrum kosztów "{{name}}"?',
+    costCenterDeleted: 'Usunięto centrum kosztów',
+    costCenterDeleteFailed: 'Nie udało się usunąć centrum kosztów',
+    deleteTransactionConfirm: 'Usunąć tę transakcję? Salda zostaną przeliczone automatycznie.',
+    deposit: 'Wpłata',
+    withdraw: 'Wypłata',
+    printCharge: 'Opłata za wydruk',
+    deleteTransaction: 'Usuń transakcję',
+  },
+
+  // Printers page
+  printers: {
+    // Printer Locations page (#2962). Counts are written as "label: N" so
+    // they read correctly in every language without plural forms.
+    locations: {
+      title: 'Lokalizacje drukarek',
+      backToPrinters: 'Wróć do drukarek',
+      subtitle: '{{grouped}} w lokalizacji, {{ungrouped}} bez lokalizacji',
+      search: 'Szukaj lokalizacji...',
+      showEmpty: 'Pokaż puste',
+      hideEmpty: 'Ukryj puste',
+      select: 'Zaznacz',
+      done: 'Gotowe',
+      sortNameAsc: 'Nazwa A→Z',
+      sortNameDesc: 'Nazwa Z→A',
+      sortCountAsc: 'Najmniej drukarek',
+      sortCountDesc: 'Najwięcej drukarek',
+      create: 'Nowa lokalizacja',
+      createTitle: 'Utwórz lokalizację',
+      editTitle: 'Edytuj lokalizację',
+      namePlaceholder: 'Nazwa lokalizacji',
+      icon: 'Ikona',
+      color: 'Kolor',
+      noColor: 'Brak koloru',
+      none: 'Brak lokalizacji drukarek',
+      noResults: 'Żadna lokalizacja nie pasuje do wyszukiwania',
+      printerCount: 'Drukarki: {{count}}',
+      noPrinters: 'Brak drukarek w tej lokalizacji',
+      selectPrinter: 'Zaznacz drukarkę',
+      move: 'Przenieś do innej lokalizacji',
+      moveButton: 'Przenieś',
+      removeFromLocation: 'Usuń z lokalizacji',
+      ungroupedPrinters: 'Drukarki bez lokalizacji: {{count}}',
+      selected: 'Zaznaczone: {{count}}',
+      deleteSelected: 'Usuń zaznaczone',
+      moveTitle: 'Przenieś drukarkę',
+      moveTitleMany: 'Przenieś drukarki ({{count}})',
+      targetPlaceholder: 'Wybierz lokalizację...',
+      noLocation: 'Brak lokalizacji',
+      deleteTitle: 'Usuń lokalizację',
+      deleteTitleMany: 'Usuń lokalizacje ({{count}})',
+      deleteMessage: 'Usunąć {{names}}? Drukarki pozostawione bez lokalizacji: {{count}}.',
+      created: 'Utworzono lokalizację',
+      saved: 'Zaktualizowano lokalizację',
+      deleted: 'Usunięte lokalizacje: {{count}}',
+      moved: 'Przeniesione drukarki: {{count}}',
+      failed: 'Nie udało się zapisać zmiany: {{error}}',
+    },
+    title: 'Drukarki',
+    addPrinter: 'Dodaj drukarkę',
+    addPreflight: {
+      checking: 'Sprawdzanie połączenia...',
+      warning: 'Część testów połączenia nie powiodła się. Ta drukarka może być widoczna jako offline. Przejrzyj poniższe testy, popraw, co możesz, lub mimo to zapisz.',
+      back: 'Wstecz',
+      saveAnyway: 'Zapisz mimo to',
+    },
+    editPrinter: 'Edytuj drukarkę',
+    deletePrinter: 'Usuń drukarkę',
+    printerName: 'Nazwa drukarki',
+    serialNumber: 'Numer seryjny',
+    ipAddress: 'Adres IP / nazwa hosta',
+    accessCode: 'Kod dostępu',
+    model: 'Model',
+    nozzleCount: 'Liczba dysz',
+    autoArchive: 'Automatyczne archiwizowanie',
+    status: {
+      available: 'Dostępna',
+      idle: 'Bezczynna',
+      printing: 'Drukuje',
+      paused: 'Wstrzymano',
+      offline: 'Offline',
+      problem: 'Problem',
+      error: 'Błąd',
+      finished: 'Zakończono',
+      unknown: 'Nieznany',
+    },
+    temperatures: {
+      nozzle: 'Dysza',
+      bed: 'Stół',
+      chamber: 'Komora',
+    },
+    heaterHistory: {
+      title: 'Historia grzałek',
+      openLabel: 'Pokaż historię grzałek',
+      nozzle: 'Dysza',
+      nozzle2: 'Dysza 2',
+      bed: 'Stół',
+      chamber: 'Komora',
+      error: 'Nie udało się wczytać historii',
+      empty: 'Brak zarejestrowanych danych',
+    },
+    progress: 'Ukończono {{percent}}%',
+    timeRemaining: 'Pozostało {{time}}',
+    deleteConfirm: 'Czy na pewno chcesz usunąć "{{name}}"?',
+    maintenanceOk: 'Konserwacja OK',
+    maintenanceWarning: '{{count}} ostrzeżenie',
+    maintenanceWarning_plural: 'Ostrzeżenia: {{count}}',
+    maintenanceDue: 'Do wykonania: {{count}}',
+    maintenanceDue_plural: 'Do wykonania: {{count}}',
+    // Sort options
+    sort: {
+      name: 'Nazwa',
+      status: 'Status',
+      model: 'Model',
+      location: 'Lokalizacja',
+      eta: 'Przewidywany koniec',
+      ascending: 'Sortuj rosnąco',
+      descending: 'Sortuj malejąco',
+    },
+    // Card size
+    cardSize: {
+      small: 'Małe karty',
+      medium: 'Średnie karty',
+      large: 'Duże karty',
+      extraLarge: 'Bardzo duże karty',
+    },
+    pageView: {
+      openCamWallPage: 'Otwórz ścianę kamer jako stronę',
+      cards: 'Karty',
+      camWall: 'Ściana kamer',
+    },
+    camWall: {
+      page: {
+        tokenRejected:
+          'Ten link do ściany kamer jest już nieważny. Token mógł wygasnąć lub zostać unieważniony.',
+        loadFailed: 'Nie udało się wczytać drukarek.',
+      },
+      tileSize: {
+        small: 'Małe kafelki',
+        medium: 'Średnie kafelki',
+        large: 'Duże kafelki',
+        extraLarge: 'Bardzo duże kafelki',
+      },
+      noPrinters: 'Brak drukarek do wyświetlenia',
+      noSignal: 'Brak sygnału',
+      live: 'Na żywo',
+      snap: 'Zdjęcie',
+      off: 'Wył.',
+      summary: 'Na żywo: {{live}}, zdjęcia: {{snap}}, razem: {{total}}',
+      layer: 'Warstwa {{cur}}/{{total}}',
+      timeLeft: 'Pozostało {{time}}',
+      statusMode: {
+        off: 'Wył.',
+        compact: 'Kompaktowy',
+        full: 'Pełny',
+      },
+      settings: {
+        title: 'Ustawienia ściany kamer',
+        maxLive: 'Maks. strumieni na żywo',
+        maxLiveHint: 'Ile kafelków jednocześnie przesyła obraz na żywo. Pozostałe odświeżają się jako zdjęcia.',
+        snapshotInterval: 'Interwał zdjęć (sekundy)',
+        snapshotIntervalHint: 'Jak często kafelki bez obrazu na żywo pobierają nowe zdjęcie.',
+        statusOverlay: 'Nakładka stanu',
+        statusOverlayHint: 'Kompaktowa: tylko znacznik stanu. Pełna: + postęp, warstwa, pozostały czas.',
+      },
+    },
+    // Controls
+    hideOffline: 'Ukryj offline',
+    nextAvailable: 'Następna dostępna',
+    powerOn: 'Włącz zasilanie',
+    offlinePrintersWithPlugs: 'Drukarki offline z inteligentnymi gniazdkami',
+    noPrintersConfigured: 'Nie skonfigurowano jeszcze drukarek',
+    search: 'Szukaj drukarek...',
+    noSearchResults: 'Żadna drukarka nie pasuje do wyszukiwania lub filtrów',
+    filter: {
+      allStatuses: 'Wszystkie stany',
+      allLocations: 'Wszystkie lokalizacje',
+    },
+    toolbar: {
+      filters: 'Filtry',
+      view: 'Widok',
+      actions: 'Akcje',
+    },
+    // Printer card
+    readyToPrint: 'Gotowa do druku',
+    external: 'Zewnętrzna',
+    ext: 'Zewn.',
+    extL: 'Zewn.-L',
+    extR: 'Zewn.-P',
+    deleteArchives: 'Usuń archiwa wydruków',
+    noLabel: 'Brak etykiety',
+    printPreview: 'Podgląd wydruku',
+    width: 'Szerokość',
+    height: 'Wysokość',
+    noObjectsFound: 'Nie znaleziono obiektów',
+    objectsLoadedOnPrintStart: 'Obiekty są wczytywane po rozpoczęciu wydruku',
+    willBeSkipped: 'Zostanie pominięty',
+    name: 'Nazwa',
+    serialCannotBeChanged: 'Numeru seryjnego nie można zmienić',
+    locationHelp: 'Służy do grupowania drukarek i filtrowania zadań w kolejce',
+    // WiFi signal strength
+    wifiSignal: {
+      veryWeak: 'Bardzo słaby',
+      weak: 'Słaby',
+      fair: 'Średni',
+      good: 'Dobry',
+      excellent: 'Doskonały',
+    },
+    // Maintenance
+    maintenanceUpToDate: 'Cała konserwacja aktualna - kliknij, aby zobaczyć',
+    // Maintenance Mode (#1476) — operator-flipped "out of service" state.
+    // Distinct from the scheduled-maintenance dashboard above; this one
+    // wraps the backend is_active flag and stops MQTT + queue dispatch.
+    maintenance: {
+      title: 'W konserwacji',
+      subtitle: 'Ta drukarka jest wstrzymana — nie jest połączona, nie przyjmuje zadań z kolejki i nie wysyła powiadomień.',
+      pillLabel: 'Konserwacja',
+      exitButton: 'Zakończ konserwację',
+      menuEnter: 'Włącz tryb konserwacji',
+      menuExit: 'Wyłącz tryb konserwacji',
+      toastEntered: '{{name}} jest teraz w trybie konserwacji',
+      toastExited: '{{name}} jest znowu online',
+      confirmMidPrintTitle: 'Włączyć tryb konserwacji w trakcie wydruku?',
+      confirmMidPrintMessage: '{{name}} obecnie drukuje. Włączenie trybu konserwacji rozłączy MQTT i zatrzyma śledzenie postępu oraz powiadomienia o zakończeniu tego zadania. Kontynuować?',
+      editFieldLabel: 'Tryb konserwacji',
+      editFieldHelp: 'Po włączeniu ta drukarka jest wyłączona z MQTT, kolejki i powiadomień — przydatne przy naprawie, równoległych instalacjach Bambuddy lub czasowym zawieszeniu.',
+    },
+    // Chamber light
+    chamberLightOn: 'Włącz oświetlenie komory',
+    chamberLightOff: 'Wyłącz oświetlenie komory',
+    // Files
+    files: 'Pliki',
+    browseFiles: 'Przeglądaj pliki drukarki',
+    // Smart plug
+    autoOffAfterPrint: 'Automatyczne wyłączenie po wydruku',
+    autoOffExecuted: 'Wykonano automatyczne wyłączenie - włącz drukarkę, aby zresetować',
+    // HMS errors
+    hmsErrors: 'Błędy HMS',
+    viewHmsErrors: 'Pokaż błędy HMS ({{count}})',
+    // Actions
+    resume: 'Wznów',
+    pause: 'Wstrzymaj',
+    stop: 'Zatrzymaj',
+    camera: 'Kamera',
+    skipObject: 'Pomiń obiekt',
+    reconnect: 'Połącz ponownie',
+    forceRefresh: 'Wymuś odświeżenie',
+    forceRefreshSuccess: 'Zażądano odświeżenia',
+    mqttDebug: 'Debugowanie MQTT',
+    printerInformation: 'Informacje o drukarce',
+    copyToClipboard: 'Kopiuj',
+    copied: 'Skopiowano!',
+    state: 'Stan',
+    wifiSignalLabel: 'Sygnał WiFi',
+    developerMode: 'Tryb dewelopera',
+    enabled: 'Włączony',
+    disabled: 'Wyłączony',
+    addedOn: 'Dodano',
+    sdCard: 'Karta SD',
+    inserted: 'Włożona',
+    notInserted: 'Niewłożona',
+    totalPrintHours: 'Godziny druku',
+    activeNozzle: 'Aktywna dysza: {{nozzle}}',
+    amsSwitchInletTooltip: 'Filament Track Switch IN-{{inlet}} ({{side}}) — zasila obie dysze',
+    nozzleRack: 'Magazyn dysz',
+    nozzleDocked: 'Zadokowana',
+    nozzleMounted: 'Zamontowana',
+    nozzleActive: 'Aktywna',
+    nozzleIdle: 'Bezczynna',
+    nozzleDiameter: 'Średnica',
+    nozzleType: 'Typ',
+    nozzleStatus: 'Status',
+    nozzleFilament: 'Filament',
+    nozzleWear: 'Zużycie',
+    nozzleMaxTemp: 'Maks. temp.',
+    nozzleSerial: 'Nr seryjny',
+    nozzleHardenedSteel: 'Stal hartowana',
+    nozzleStainlessSteel: 'Stal nierdzewna',
+    nozzleTungstenCarbide: 'Węglik wolframu',
+    nozzleFlow: 'Przepływ',
+    nozzleHighFlow: 'Wysoki przepływ',
+    nozzleStandardFlow: 'Standardowy',
+    // Firmware
+    firmwareUpdate: 'Aktualizacja firmware',
+    firmwareInstructions: 'Na ekranie dotykowym drukarki przejdź do',
+    firmwareNav: 'Przejdź do',
+    settings: 'Ustawienia',
+    firmware: 'Firmware',
+    // Discovery
+    discoverPrinters: 'Wykryj drukarki',
+    searching: 'Wyszukiwanie...',
+    manualEntry: 'Wpis ręczny',
+    addFromCloud: 'Dodaj z chmury',
+    // Toast messages
+    toast: {
+      printerDeleted: 'Usunięto drukarkę',
+      missingSpoolAssignment: 'Rozpoczęto wydruk na {{printer}}. Brak przypisania szpuli dla: {{slots}}',
+      killSwitchTriggered: 'Wyłącznik rozliczeń zatrzymał nieautoryzowany wydruk na {{printer}}: {{filename}}',
+      billingChargeFailed: 'Rozliczenie {{filename}} na {{printer}} nie powiodło się. Rezerwacja budżetu została zachowana; sprawdź logi serwera.',
+      assignmentVerified: 'Załadowano filament do slotu {{slot}} ({{printer}})',
+      assignmentVerifiedNoKprofile: 'Slot {{slot}} na {{printer}} załadowany, ale kalibracja przepływu (profil K) nie została zastosowana',
+      assignmentNotConfirmed: 'Nie udało się potwierdzić przypisania slotu {{slot}} na {{printer}} — sprawdź slot AMS',
+      printerAdded: 'Dodano drukarkę',
+      printerUpdated: 'Zaktualizowano drukarkę',
+      failedToDelete: 'Nie udało się usunąć drukarki',
+      failedToAdd: 'Nie udało się dodać drukarki',
+      connectionFailedNotAdded: 'Nie udało się połączyć z drukarką. Sprawdź adres IP, numer seryjny i kod dostępu oraz upewnij się, że tryb LAN-only jest włączony. Drukarka nie została dodana.',
+      failedToUpdate: 'Nie udało się zaktualizować drukarki',
+      commandSent: 'Wysłano polecenie',
+      failedToSendCommand: 'Nie udało się wysłać polecenia',
+      turnedOn: 'Włączono {{name}}',
+      failedToPowerOn: 'Nie udało się włączyć {{name}}',
+      scriptTriggered: 'Uruchomiono skrypt',
+      printStopped: 'Zatrzymano wydruk',
+      printPaused: 'Wstrzymano wydruk',
+      printResumed: 'Wznowiono wydruk',
+      referenceDeleted: 'Usunięto odniesienie',
+      detectionAreaSaved: 'Zapisano obszar wykrywania',
+      failedToRunScript: 'Nie udało się uruchomić skryptu',
+      failedToStopPrint: 'Nie udało się zatrzymać wydruku',
+      failedToPausePrint: 'Nie udało się wstrzymać wydruku',
+      failedToResumePrint: 'Nie udało się wznowić wydruku',
+      failedToControlChamberLight: 'Nie udało się sterować oświetleniem komory',
+      failedToSetSpeed: 'Nie udało się ustawić prędkości druku',
+      failedToUpdateSetting: 'Nie udało się zaktualizować ustawienia',
+      failedToSkipObjects: 'Nie udało się pominąć obiektów',
+      failedToRereadRfid: 'Nie udało się ponownie odczytać RFID',
+      failedToCheckPlate: 'Nie udało się sprawdzić płyty',
+      failedToUpdateLabel: 'Nie udało się zaktualizować etykiety',
+      failedToDeleteReference: 'Nie udało się usunąć odniesienia',
+      failedToSaveDetectionArea: 'Nie udało się zapisać obszaru wykrywania',
+      plateCheckEnabled: 'Włączono sprawdzanie płyty',
+      plateCheckDisabled: 'Wyłączono sprawdzanie płyty',
+      calibrationSaved: 'Zapisano kalibrację!',
+      calibrationFailed: 'Kalibracja nie powiodła się',
+      rfidRereadInitiated: 'Rozpoczęto ponowny odczyt RFID',
+      loadInitiated: 'Ładowanie filamentu…',
+      unloadInitiated: 'Wyładowywanie filamentu…',
+      failedToLoad: 'Nie udało się załadować filamentu',
+      failedToUnload: 'Nie udało się wyładować filamentu',
+    },
+    // Connection status
+    connection: {
+      connected: 'Połączono',
+      offline: 'Offline',
+    },
+    plateStatus: {
+      markCleared: 'Oznacz płytę jako wyczyszczoną',
+      cleared: 'Płyta wolna',
+      notCleared: 'Płyta niewyczyszczona',
+      inUse: 'Płyta w użyciu',
+    },
+    // Queue info
+    queue: {
+      inQueue: '{{count}} wydruk w kolejce',
+      inQueue_plural: 'Wydruki w kolejce: {{count}}',
+    },
+    // Controls section
+    controls: 'Sterowanie',
+    // RFID
+    rfid: {
+      reread: 'Odczytaj RFID ponownie',
+    },
+    // AMS load/unload (#891)
+    ams: {
+      load: 'Załaduj',
+      unload: 'Wyładuj',
+      feedTitle: 'Do której dyszy załadować {{slot}}?',
+      feedPrompt: 'Filament Track Switch może skierować ten slot do dowolnego hotendu. Wybierz, który zasilić.',
+      feedLeft: 'Lewa dysza',
+      feedRight: 'Prawa dysza',
+      feedAlreadyLoaded: 'Już załadowano',
+      switchNotReady: 'Filament Track Switch nie jest jeszcze skonfigurowany. Przypisz każdy AMS do wejścia na drukarce i spróbuj ponownie.',
+    },
+    bedJog: {
+      limitWarning: 'Limity ruchu nie są egzekwowane podczas ręcznych ruchów — błąd firmware Bambu ignoruje programowe krańcówki dla poleceń zdalnych. Poruszaj ostrożnie, aby uniknąć kolizji.',
+      title: 'Sterowanie ruchem',
+      bed: 'Stół',
+      step: 'Krok (mm)',
+      up: 'Przesuń płytę w górę',
+      down: 'Przesuń płytę w dół',
+      toolheadUp: 'Przesuń głowicę w górę',
+      toolheadDown: 'Przesuń głowicę w dół',
+      disabledWhilePrinting: 'Niedostępne podczas drukowania',
+      notHomedTitle: 'Drukarka nie jest zbazowana',
+      notHomedMessage: 'Drukarka nie była bazowana od ostatniego wydruku. Najpierw uruchom automatyczne bazowanie, aby bezpiecznie ustalić pozycję (parkuje głowicę, potem bazuje X, Y i Z), lub mimo to wykonaj ruch — programowe krańcówki zostaną pominięte.',
+      homeZ: 'Automatyczne bazowanie',
+      moveAnyway: 'Przesuń mimo to',
+      homingStarted: 'Automatyczne bazowanie drukarki…',
+    },
+    // Permissions
+    permission: {
+      noAdd: 'Nie masz uprawnień do dodawania drukarek',
+      noEdit: 'Nie masz uprawnień do edytowania drukarek',
+      noDelete: 'Nie masz uprawnień do usuwania drukarek',
+      noControl: 'Nie masz uprawnień do sterowania drukarkami',
+      noFiles: 'Nie masz uprawnień dostępu do plików drukarki',
+      noAmsRfid: 'Nie masz uprawnień do ponownego odczytu RFID w AMS',
+      noSmartPlugControl: 'Nie masz uprawnień do sterowania inteligentnymi gniazdkami',
+      noCamera: 'Nie masz uprawnień do podglądu kamer',
+    },
+    // Add/Edit modal
+    modal: {
+      addTitle: 'Dodaj drukarkę',
+      editTitle: 'Edytuj drukarkę',
+      myPrinter: 'Moja drukarka',
+      selectModel: 'Wybierz model...',
+      locationGroup: 'Lokalizacja / grupa (opcjonalnie)',
+      locationPlaceholder: 'np. Warsztat, Biuro, Piwnica',
+      autoArchiveLabel: 'Automatycznie archiwizuj ukończone wydruki',
+      wearCostLabel: 'Koszt zużycia na godzinę druku ({{currency}})',
+      wearCostHelp: 'Ile godzina drukowania kosztuje tę drukarkę w zużyciu i częściach. Od teraz jest doliczany do kosztu każdego wydruku; wcześniejsze wydruki nie są zmieniane. Pozostaw puste, aby wyłączyć.',
+      fromPrinterSettings: 'Z ustawień drukarki',
+      modelOptional: 'Model (opcjonalnie)',
+      saveChanges: 'Zapisz zmiany',
+    },
+    // Skip objects
+    skipObjects: {
+      tooltip: 'Pomiń obiekty',
+      onlyWhilePrinting: 'Pomiń obiekty (tylko podczas drukowania)',
+      requiresMultiple: 'Pomiń obiekty (wymaga co najmniej 2 obiektów)',
+      title: 'Pomiń obiekty',
+      matchIdsInfo: 'Dopasuj ID do wyświetlacza drukarki',
+      printerShowsIds: 'Ekran drukarki pokazuje ID obiektów na płycie roboczej',
+      skipSelected: 'Pomiń zaznaczone',
+      skipping: 'Pomijanie...',
+      noObjectsSelected: 'Nie zaznaczono obiektów',
+      selectObjectsToSkip: 'Zaznacz obiekty, które chcesz pominąć w bieżącym wydruku',
+      skipped: 'pominięty',
+      objectsSkipped: 'Pominięto obiekty',
+      activeCount: 'Aktywne: {{count}}',
+      waitForLayer: 'Poczekaj na warstwę 2+, aby pomijać obiekty (obecnie warstwa {{layer}})',
+      skip: 'Pomiń',
+      confirmTitle: 'Pominąć obiekt?',
+      confirmMessage: 'Czy na pewno chcesz pominąć "{{name}}"? Tej operacji nie można cofnąć.',
+      confirmAllMessage: 'Zaznaczono wszystkie pozostałe obiekty. Spowoduje to zatrzymanie zadania druku. Kontynuować?',
+      confirmMultipleMessage: 'Pominąć zaznaczone obiekty ({{count}})? Tej operacji nie można cofnąć.',
+    },
+    // Confirm modals
+    confirm: {
+      deleteTitle: 'Usuń drukarkę',
+      deleteMessage: 'Czy na pewno chcesz usunąć "{{name}}"? Spowoduje to usunięcie wszystkich ustawień połączenia. Przypisani do niej dostawcy powiadomień i inteligentne gniazdka oraz wysyłające do niej wirtualne drukarki również zostaną usunięte.',
+      deleteArchivesNote: 'Cała historia wydruków tej drukarki zostanie trwale usunięta.',
+      keepArchivesNote: 'Historia wydruków zostanie zachowana, ale nie będzie już powiązana z tą drukarką.',
+      stopTitle: 'Zatrzymaj wydruk',
+      stopMessage: 'Czy na pewno chcesz zatrzymać bieżący wydruk na "{{name}}"? Spowoduje to anulowanie zadania druku.',
+      stopButton: 'Zatrzymaj wydruk',
+      pauseTitle: 'Wstrzymaj wydruk',
+      pauseMessage: 'Czy na pewno chcesz wstrzymać bieżący wydruk na "{{name}}"?',
+      pauseButton: 'Wstrzymaj wydruk',
+      resumeTitle: 'Wznów wydruk',
+      resumeMessage: 'Czy na pewno chcesz wznowić wydruk na "{{name}}"?',
+      resumeButton: 'Wznów wydruk',
+      powerOnTitle: 'Włącz zasilanie drukarki',
+      powerOnMessage: 'Czy na pewno chcesz WŁĄCZYĆ zasilanie "{{name}}"?',
+      powerOnButton: 'Włącz zasilanie',
+      powerOffTitle: 'Wyłącz zasilanie drukarki',
+      powerOffMessage: 'Czy na pewno chcesz WYŁĄCZYĆ zasilanie "{{name}}"?',
+      powerOffWarning: 'UWAGA: "{{name}}" obecnie drukuje! Czy na pewno chcesz WYŁĄCZYĆ zasilanie? Przerwie to wydruk i może uszkodzić drukarkę.',
+      powerOffButton: 'Wyłącz zasilanie',
+      haToggleTitle: 'Przełącz "{{name}}"',
+      haToggleMessage: 'Przełączyć encję Home Assistant {{entity}}? Jeśli jest obecnie włączona, może to odciąć zasilanie.',
+      haToggleWarning: 'UWAGA: "{{name}}" obecnie drukuje! Przełączenie {{entity}} może odciąć zasilanie i przerwać wydruk. Kontynuować?',
+      haToggleButton: 'Przełącz',
+    },
+    // Bulk actions
+    bulk: {
+      select: 'Zaznacz',
+      selectAll: 'Zaznacz wszystkie',
+      selectByLocation: 'Zaznacz według lokalizacji',
+      selected: 'Zaznaczone: {{count}}',
+      actions: {
+        stop: 'Zatrzymaj',
+        pause: 'Wstrzymaj',
+        resume: 'Wznów',
+        clearPlate: 'Wyczyść stół',
+        clearHMS: 'Wyczyść powiadomienia',
+      },
+      confirm: {
+        stopTitle: 'Zatrzymaj wydruki ({{count}})',
+        stopMessage: 'Spowoduje to anulowanie aktywnych wydruków na drukarkach (liczba: {{count}}). Tej operacji nie można cofnąć.',
+        stopButton: 'Zatrzymaj wszystkie',
+        pauseTitle: 'Wstrzymaj wydruki ({{count}})',
+        pauseMessage: 'Spowoduje to wstrzymanie aktywnych wydruków na drukarkach (liczba: {{count}}).',
+        pauseButton: 'Wstrzymaj wszystkie',
+        clearPlateTitle: 'Wyczyść stoły ({{count}})',
+        clearPlateMessage: 'Spowoduje to oznaczenie stołu jako wyczyszczonego na drukarkach (liczba: {{count}}) i może uruchomić zadania z kolejki.',
+        clearPlateButton: 'Wyczyść wszystkie',
+      },
+      success: '{{action}} — ukończono na drukarkach (liczba: {{count}})',
+      partial: 'Udane: {{succeeded}}, nieudane: {{failed}}',
+      noneApplicable: 'Żadna z zaznaczonych drukarek nie jest w odpowiednim stanie dla tej akcji',
+      selectByState: 'Zaznacz według stanu',
+    },
+    // Discovery
+    discovery: {
+      title: 'Wykryj drukarki',
+      searching: 'Wyszukiwanie...',
+      scanning: 'Skanowanie...',
+      scanProgress: 'Skanowanie... {{scanned}}/{{total}}',
+      foundPrinters: 'Znalezione drukarki: {{count}}',
+      noPrintersFound: 'Nie znaleziono drukarek',
+      noPrintersFoundSubnet: 'Nie znaleziono drukarek w podanej podsieci.',
+      noPrintersFoundNetwork: 'Nie znaleziono drukarek w sieci.',
+      allConfigured: 'Wszystkie wykryte drukarki są już skonfigurowane.',
+      alreadyAdded: 'Już dodana',
+      select: 'Wybierz',
+      manualEntry: 'Wpis ręczny',
+      addFromCloud: 'Dodaj z chmury',
+      subnetToScan: 'Podsieć do skanowania',
+      dockerNote: 'Wykryto Docker. Wpisz podsieć drukarki w notacji CIDR. Wymaga network_mode: host w docker-compose.yml.',
+      scanSubnet: 'Skanuj podsieć w poszukiwaniu drukarek',
+      discoverNetwork: 'Wykryj drukarki w sieci',
+      scanningSubnet: 'Skanowanie podsieci w poszukiwaniu drukarek Bambu...',
+      scanningNetwork: 'Skanowanie sieci...',
+      serialRequired: 'Wymagany numer seryjny',
+      unknown: 'Nieznana',
+      failedToStart: 'Nie udało się uruchomić wykrywania',
+      customSubnetOption: 'Własna podsieć...',
+      customSubnetLabel: 'Własna podsieć (CIDR)',
+      customSubnetNote: 'Użyj własnej podsieci, jeśli drukarka jest w innej sieci niż ten serwer. Porty FTP (990) i MQTT (8883) muszą być osiągalne przez granicę routingu.',
+    },
+    // AMS Drying
+    drying: {
+      start: 'Rozpocznij suszenie',
+      stop: 'Zatrzymaj suszenie',
+      temperature: 'Temperatura',
+      duration: 'Czas trwania',
+      hours: 'godz.',
+      timeRemaining: 'Pozostało {{time}}',
+      active: 'Suszenie',
+      notRunning: 'Suszenie nie trwa',
+      notRunningHint: 'Drukarka ma ustawiony timer suszenia, ale odliczanie się zatrzymało, a AMS nie zgłasza fazy suszenia. Cykl nigdy się nie rozpoczął lub został wstrzymany, np. przez limit mocy lub bieżący wydruk.',
+      targetSummary: '{{filament}} @ {{temp}}°C',
+      notSupported: 'Suszenie nieobsługiwane',
+      powerRequired: 'Podłącz zasilacz AMS, aby włączyć suszenie',
+      cannotDryNow: 'AMS nie może teraz rozpocząć suszenia',
+      startingDrying: 'Rozpoczynanie suszenia...',
+      toastCommandSent: 'Wysłano polecenie suszenia',
+      toastStopped: 'Wysłano polecenie zatrzymania',
+      toastNotStarted: 'Drukarka przyjęła polecenie, ale AMS nie rozpoczął suszenia. Sprawdź, czy zasilacz AMS jest podłączony i czy drukarka jest bezczynna.',
+      screenOnly: 'Suszeniem AMS na tej drukarce można sterować tylko z ekranu drukarki (ograniczenie Bambu)',
+      stoppingDrying: 'Zatrzymywanie suszenia...',
+      rotateTray: 'Obracaj szpulę podczas suszenia',
+      rotateUnavailableReason: 'Niedostępne — slot w tym AMS jest załadowany do głowicy. Szpula jest zablokowana przez rurkę podającą i nie może się obracać. Najpierw wycofaj filament.',
+      startMode: 'Czas rozpoczęcia',
+      modeNow: 'Teraz',
+      modeDelay: 'Po opóźnieniu',
+      modeAtTime: 'O godzinie',
+      // Verb (button label), not the noun.
+      schedule: 'Zaplanuj',
+      scheduledFor: 'Suszenie zaplanowane na {{time}}',
+      scheduledAsap: 'Suszenie zaplanowane (oczekiwanie na drukarkę)',
+      cancelScheduled: 'Anuluj zaplanowane suszenie',
+      scheduleFailed: 'Nie udało się zaplanować suszenia',
+      retractFilament: 'Wycofaj filament z wyjścia AMS, aby rozpocząć suszenie',
+      waitingAmsNotFound: 'Oczekiwanie na wykrycie AMS',
+      waitingOffline: 'Oczekiwanie, aż drukarka będzie online',
+      waitingPrinterBusy: 'Oczekiwanie, aż drukarka będzie wolna',
+      waitingAlreadyDrying: 'Oczekiwanie na zakończenie bieżącego cyklu suszenia',
+      waitingInterrupted: 'Przerwano, wznowi się, gdy drukarka będzie wolna',
+      scheduleFailedReason: 'Zaplanowane suszenie nie powiodło się: {{reason}}',
+      scheduleFailedUnknown: 'Nieznany błąd',
+      scheduleFailedDidNotStart: 'Drukarka przyjęła polecenie, ale AMS nie rozpoczął suszenia',
+      dismissFailed: 'Odrzuć',
+    },
+    // AMS Filament Backup status badge (printer-wide auto-switch to another spool)
+    amsBackup: {
+      titleOn: 'Zapas filamentu AMS jest WŁĄCZONY. Kliknij, aby wyłączyć.',
+      titleOff: 'Zapas filamentu AMS jest WYŁĄCZONY. Kliknij, aby włączyć.',
+      titleUnknown: 'Stan zapasu filamentu AMS jest niedostępny na tej drukarce.',
+      toastEnabled: 'Włączono zapas filamentu AMS',
+      toastDisabled: 'Wyłączono zapas filamentu AMS',
+      modalTitle: 'Zapas filamentu AMS',
+      modalHelp: 'Gdy w aktywnym slocie skończy się filament, drukarka przechodzi kolejno przez pasujące sloty z tym samym profilem i kolorem w tej kolejności.',
+      modalNoSlots: 'Nie załadowano filamentu.',
+      modalNoPairs: 'Brak par zapasowych — żadne dwa sloty nie mają tego samego profilu filamentu i koloru.',
+      extruderRightShort: 'P',
+      extruderLeftShort: 'L',
+      stateOn: 'Włączony',
+      stateOff: 'Wyłączony',
+      stateUnknown: 'Nieobsługiwany na tej drukarce',
+    },
+    activeJobSlot: {
+      title: 'Ten slot to filament {{n}} w aktywnym wydruku',
+      ariaLabel: 'Slot aktywnego wydruku {{n}}',
+    },
+    expectedSlot: {
+      title: 'Drukarka czeka na filament w tym slocie',
+      ariaLabel: 'Oczekiwany slot filamentu {{n}}',
+      label: '{{ams}} · Slot {{slot}}',
+      external: 'Szpula zewnętrzna',
+    },
+    // Filaments section
+    filaments: 'Filamenty',
+    externalSpool: {
+      hide: 'Ukryj szpulę zewnętrzną',
+      show: 'Pokaż szpulę zewnętrzną',
+    },
+    // Camera
+    openCameraOverlay: 'Otwórz nakładkę kamery',
+    openCameraWindow: 'Otwórz kamerę w nowym oknie',
+    // Firmware
+    firmwareUpdateAvailable: 'Dostępna aktualizacja firmware: {{current}} → {{latest}}',
+    firmwareUpToDate: 'Firmware {{version}} — aktualny',
+    firmwareUpdateButton: 'Aktualizuj',
+    // Plate detection
+    plateDetection: {
+      noPermission: 'Nie masz uprawnień do aktualizowania drukarek',
+      enabledClick: 'Sprawdzanie płyty włączone - kliknij, aby wyłączyć',
+      disabledClick: 'Sprawdzanie płyty wyłączone - kliknij, aby włączyć',
+      manageCalibration: 'Zarządzaj kalibracją wykrywania płyty',
+      calibrationRequired: 'Wymagana kalibracja',
+      calibrationInstructions: 'Upewnij się, że płyta robocza jest <strong>całkowicie pusta</strong>, a następnie kliknij Kalibruj.',
+      calibrationDescription: 'Kalibracja wykonuje zdjęcie referencyjne pustej płyty. Kolejne sprawdzenia porównują obraz z tym odniesieniem, aby wykryć obiekty.',
+      calibrationTip: '<strong>Wskazówka:</strong> Możesz zapisać do 5 kalibracji dla różnych płyt. System automatycznie używa najlepszego dopasowania podczas sprawdzania.',
+      plateEmpty: 'Płyta wygląda na pustą',
+      objectsDetected: 'Wykryto obiekty na płycie',
+      couldNotRun: 'Nie udało się sprawdzić płyty na {{printer}} ({{reason}}). Wydruk jest kontynuowany.',
+      couldNotRunTitle: 'Nie udało się sprawdzić płyty',
+      unavailableReasons: {
+        no_camera_frame: 'brak obrazu z kamery',
+        decode_failed: 'nie udało się odczytać obrazu z kamery',
+        analysis_error: 'analiza obrazu nie powiodła się',
+        opencv_missing: 'analiza obrazu nie jest zainstalowana',
+        not_calibrated: 'brak kalibracji pustej płyty',
+        error: 'nieoczekiwany błąd',
+      },
+      confidence: 'Pewność',
+      difference: 'Różnica',
+      analysisPreview: 'Podgląd analizy:',
+      analysisLegend: 'Zielona ramka = obszar wykrywania, czerwona nakładka = różnice względem kalibracji',
+      savedReferences: 'Zapisane odniesienia ({{count}}/{{max}})',
+      deleteReference: 'Usuń odniesienie',
+      labelPlaceholder: 'Etykieta...',
+      clickToEdit: '{{label}} - kliknij, aby edytować',
+      clickToAddLabel: 'Kliknij, aby dodać etykietę',
+    },
+    // Speed
+    speed: {
+      title: 'Prędkość druku',
+      silent: 'Cichy (50%)',
+      standard: 'Standardowy (100%)',
+      sport: 'Sport (124%)',
+      ludicrous: 'Szalony (166%)',
+    },
+    airduct: {
+      title: 'Tryb kanału powietrza',
+      cooling: 'Chłodzenie',
+      heating: 'Grzanie',
+    },
+    noSdCard: 'Brak SD',
+    door: {
+      open: 'Otwarte',
+      closed: 'Zamknięte',
+    },
+    // Fans
+    fans: {
+      partCooling: 'Wentylator chłodzenia modelu',
+      auxiliary: 'Wentylator pomocniczy',
+      leftAuxiliary: 'Lewy wentylator pomocniczy',
+      rightAuxiliary: 'Prawy wentylator pomocniczy',
+      exhaust: 'Wyciąg',
+      chamber: 'Wentylator komory',
+    },
+    // HMS errors
+    clickToViewHmsErrors: 'Kliknij, aby zobaczyć błędy HMS',
+    aiDetection: {
+      safe: 'Bezpieczny',
+      warning: 'Ostrzeżenie',
+      failure: 'Awaria',
+      idle: 'Bezczynny',
+      error: 'Nie sprawdza',
+      unknown: 'Uruchamianie',
+      tooltipError: 'Wykrywanie błędów AI nie sprawdza tego wydruku: {{reason}} - kliknij, aby zobaczyć szczegóły',
+      tooltipUnknown: 'Wykrywanie błędów AI: oczekiwanie na pierwszy wynik - kliknij, aby zobaczyć szczegóły',
+      errorHint: 'Ten wydruk nie jest sprawdzany. Wykrywanie wznowi się automatycznie po usunięciu poniższego problemu.',
+      tooltip: 'Wykrywanie błędów AI: {{status}} (wynik {{score}}) - kliknij, aby zobaczyć szczegóły',
+      tooltipIdle: 'Wykrywanie błędów AI włączone - monitorowanie rozpocznie się przy następnym wydruku - kliknij, aby zobaczyć szczegóły',
+      modalTitle: 'Wykrywanie błędów AI - {{name}}',
+      currentStatus: 'Status',
+      score: 'Wynik',
+      framesAnalyzed: 'Przeanalizowane klatki',
+      idleHint: 'Żaden wydruk nie jest teraz monitorowany. Monitorowanie rozpocznie się automatycznie przy następnym wydruku.',
+      lastError: 'Ostatni błąd',
+      openSettings: 'Otwórz ustawienia',
+    },
+    estimatedCompletion: 'Szacowany czas zakończenia',
+    pauseIn: '{{time}} do pauzy · {{eta}}',
+    pauseAtLayer: 'Pauza na warstwie {{layer}}',
+    nextPauseAtLayer: 'Następna pauza dodana w slicerze, na warstwie {{layer}}',
+    plateNumber: 'Płyta {{number}}',
+    slotOptions: 'Opcje slotu',
+    // AMS hover popup
+    amsPopup: {
+      friendlyName: 'Nazwa AMS',
+      friendlyNamePlaceholder: 'np. przyjazna nazwa AMS',
+      serialNumber: 'Numer seryjny',
+      firmwareVersion: 'Firmware',
+      save: 'Zapisz',
+      clear: 'Wyczyść',
+      noEditPermission: 'Nie masz uprawnień do zmiany nazw jednostek AMS',
+    },
+    // Firmware modal
+    firmwareModal: {
+      title: 'Aktualizacja firmware',
+      titleUpToDate: 'Informacje o firmware',
+      currentVersion: 'Bieżąca:',
+      latestVersion: 'Najnowsza:',
+      releaseNotes: 'Informacje o wydaniu',
+      checkingPrereqs: 'Sprawdzanie wymagań...',
+      sdCardReady: 'Karta SD gotowa. Kliknij poniżej, aby przesłać firmware.',
+      uploadedSuccess: 'Firmware przesłano na kartę SD!',
+      applyInstructions: 'Aby zastosować aktualizację na drukarce:',
+      step1: 'Na ekranie dotykowym drukarki przejdź do <strong>Settings</strong>',
+      step2: 'Przejdź do <strong>Firmware</strong>',
+      step3: 'Wybierz <strong>Update from SD card</strong>',
+      step4: 'Aktualizacja potrwa 10-20 minut',
+      done: 'Gotowe',
+      starting: 'Uruchamianie...',
+      uploadFirmware: 'Prześlij firmware',
+      printerBusy: 'Drukarka jest zajęta. Firmware można przesłać tylko wtedy, gdy jest bezczynna.',
+      uploadFailed: 'Nie udało się rozpocząć przesyłania: {{error}}',
+      uploadedToast: 'Firmware przesłano! Uruchom aktualizację z ekranu drukarki.',
+      availableVersions: 'Dostępne wersje',
+      usable: 'Możliwa do użycia',
+      unavailable: 'Niedostępna',
+      installed: 'Zainstalowana',
+      newerBadge: 'nowsza',
+      olderBadge: 'starsza',
+      currentBadge: 'bieżąca',
+    },
+    accessCodePlaceholder: 'Pozostaw puste, aby zachować bieżący',
+    // ROI editor
+    roi: {
+      title: 'Obszar wykrywania (ROI)',
+      xStart: 'Początek X',
+      yStart: 'Początek Y',
+      width: 'Szerokość',
+      height: 'Wysokość',
+      instruction: 'Dostosuj obszar wykrywania tak, aby obejmował płytę roboczą. Zielona ramka w podglądzie pokazuje bieżący obszar.',
+    },
+    developerModeWarning: 'Tryb Developer LAN nie jest włączony na: {{names}}. Niektóre funkcje mogą nie działać.',
+    howToEnable: 'Jak włączyć',
+    incompatibleFile: 'Ten plik został pocięty dla {{slicedFor}}, a ta drukarka to {{printerModel}}',
+    dropNotPrintable: 'Drukować można tylko pocięte pliki (.gcode, .gcode.3mf lub pocięty .3mf)',
+    dropNotSliced: 'Ten plik nie zawiera pociętego G-code. Najpierw go potnij, a potem wydrukuj.',
+    dropToPrint: 'Upuść, aby wydrukować',
+    dropToQueue: 'Upuść, aby dodać do kolejki',
+  },
+
+  // Archives page
+  archives: {
+    media: {
+      title: 'Filmy z wydruku',
+      download: 'Pobierz filmy z wydruku',
+      searching: 'Sprawdzanie filmów na drukarce…',
+      searchFailed: 'Nie udało się sprawdzić filmów na drukarce.',
+      none: 'Nie znaleziono timelapse ani fragmentów nagrań z kamery IP dla tego wydruku.',
+      attachedTimelapse: 'Dołączony timelapse',
+      printerFiles: 'Pliki nadal na drukarce',
+      downloadSelected: 'Pobierz zaznaczone',
+      printerMissing: 'Drukarka nie jest już skonfigurowana',
+      timelapseUnavailable: 'Nie udało się odczytać katalogu timelapse',
+      ipcamUnavailable: 'Nie udało się odczytać katalogu kamery IP',
+    },
+    title: 'Archiwa wydruków',
+    no3mfBanner: {
+      title: 'Niektórych ostatnich wydruków nie udało się zarchiwizować z miniaturami',
+      body: 'Slicer nie zostawił pliku .gcode.3mf na karcie SD drukarki, więc Bambuddy nie mógł pobrać miniatury ani metadanych slicera. Zwykle dzieje się tak, gdy w slicerze wyłączona jest opcja "Store sent files on external storage" (karta Device w Bambu Studio / OrcaSlicer).',
+      docsLink: 'Zobacz krok 4 instalacji',
+      dismissLabel: 'Zamknij to powiadomienie',
+      docsLinkInternalStorage: 'Dlaczego tak się dzieje',
+      titleInternalStorage: 'Niektóre ostatnie wydruki zostały w pamięci wewnętrznej drukarki',
+      bodyInternalStorage: 'Bambu Studio zapisał pocięty plik w pamięci wewnętrznej drukarki zamiast na karcie, więc Bambuddy nie miał czego odczytać przez FTP. W seriach H2, P2S i X2D przycisk Print zawsze tak robi — wybór daje tylko Send, a i tam domyślnie ustawione jest Cache. Te wydruki są nadal archiwizowane z nazwą i czasem, tylko bez miniatury i metadanych slicera. Aby uzyskać pełne archiwa, uruchom wydruk z Bambuddy albo tnij w OrcaSlicer — lub w Bambu Studio użyj Send z wybraną opcją External i uruchom wydruk później. Wszystkie te sposoby wymagają karty lub pendrive\'a w drukarce.',
+      titleNoExternalStorage: 'Niektórych ostatnich wydruków nie udało się zarchiwizować — brak nośnika w drukarce',
+      bodyNoExternalStorage: 'Drukarka zgłasza brak karty lub pendrive\'a w gnieździe, więc pocięty plik nie miał gdzie trafić, a Bambuddy nie miał czego odczytać. Włóż nośnik, a następny wydruk zostanie zarchiwizowany w całości.',
+      titleInternalHistory: 'Niektóre ostatnie wydruki uruchomiono z pliku, który był już na drukarce',
+      bodyInternalHistory: 'Te wydruki uruchomiono z własnej biblioteki drukarki — ponowny wydruk z jej ekranu, start z Handy lub plik wysłany wcześniej i wydrukowany później. Bambuddy odczytuje pliki wydruku przez FTP, który udostępnia tylko kartę lub pendrive, a drukarka trzyma tę bibliotekę w obszarze niedostępnym dla FTP, więc nie było pliku 3MF do odczytania. Żadne ustawienie slicera tego nie zmieni, bo dla tych wydruków nic nie zostało wysłane. Są one nadal archiwizowane z nazwą i czasem, a w Edytuj archiwum możesz ręcznie uzupełnić zużyty filament. Aby uzyskać pełne archiwum, uruchom wydruk z Bambuddy lub ze slicera.',
+      titleFtpsCooloff: 'Niektórych ostatnich wydruków nie udało się zarchiwizować — drukarka odrzuciła połączenie do przesyłu plików',
+      bodyFtpsCooloff: 'Bambuddy otworzył port przesyłu plików drukarki (FTPS 990), a drukarka odpowiedziała czymś, co nie jest TLS, więc nie dało się nic z niej odczytać. Te wydruki są nadal archiwizowane z nazwą i czasem, tylko bez miniatury i metadanych slicera. To nie jest ustawienie slicera ani nic, co zmieniłeś — te same modele i firmware działają normalnie w innych instalacjach, a dotknięta drukarka zwykle po pewnym czasie sama zaczyna znowu działać. Po takim błędzie Bambuddy wstrzymuje przesyły do tej drukarki na pięć minut i wraca po plik, gdy przerwa minie, więc krótki epizod uzupełnia się sam; karta nadal pusta oznacza, że odmowa trwała dłużej niż ponowna próba. Przyczyna nie jest jeszcze znana. Jeśli problem się powtarza, włącz logowanie debugowania na stronie System i dołącz pakiet wsparcia do zgłoszenia.',
+      titleFtpTransferFailed: 'Niektórych ostatnich wydruków nie udało się zarchiwizować — przesył pliku przekroczył limit czasu',
+      bodyFtpTransferFailed: 'Pocięty plik był na karcie drukarki i drukarka go udostępniła, ale przesył nie zakończył się w dozwolonym czasie. Na początku wydruku drukarka obsługuje też kamerę, komunikaty stanu i przesyłanie zadania, a duży plik 3MF nie zawsze przechodzi przy tym wszystkim. Te wydruki są nadal archiwizowane z nazwą i czasem, tylko bez miniatury i metadanych slicera. To nie jest ustawienie slicera ani nic, co zmieniłeś. Bambuddy wraca po plik trzy razy w ciągu kolejnych dziesięciu minut, więc większość z nich uzupełnia się sama; karta nadal pusta oznacza, że każda próba również przekroczyła limit czasu. Jeśli problem się powtarza, zwiększ Connection Timeout w Ustawienia > Sieć > FTP Retry.',
+    },
+    searchPlaceholder: 'Szukaj w archiwach...',
+    filterByPrinter: 'Filtruj wg drukarki',
+    filterByStatus: 'Filtruj wg stanu',
+    sortBy: 'Sortuj wg',
+    sortNewest: 'Najnowsze najpierw',
+    sortOldest: 'Najstarsze najpierw',
+    sortName: 'Nazwa',
+    sortDuration: 'Czas trwania',
+    sortLargest: 'Największe najpierw',
+    sortSmallest: 'Najmniejsze najpierw',
+    sortSize: 'Rozmiar',
+    noArchives: 'Nie znaleziono archiwów',
+    noArchivesSearch: 'Żadne archiwum nie pasuje do wyszukiwania',
+    originalPrintNotVisible: 'Oryginalny wydruk niewidoczny - spróbuj wyczyścić filtry',
+    linkedArchiveNotVisible: 'Powiązane archiwum niewidoczne - spróbuj wyczyścić filtry',
+    noArchivesYet: 'Brak archiwów',
+    prints: 'wydruki',
+    pagination: {
+      showing: 'Wyświetlanie',
+      to: 'do',
+      of: 'z',
+      show: 'Pokaż',
+      page: 'Strona',
+      all: 'Wszystkie',
+    },
+    loadingArchives: 'Wczytywanie archiwów...',
+    releaseToUpload: 'Upuść, aby przesłać',
+    showAll: 'Pokaż wszystkie',
+    showFavoritesOnly: 'Pokaż tylko ulubione',
+    gridView: 'Widok siatki',
+    listView: 'Widok listy',
+    calendarView: 'Widok kalendarza',
+    logView: 'Dziennik wydruków',
+    manageTags: 'Zarządzaj tagami',
+    showFailedPrints: 'Pokaż nieudane wydruki',
+    hideFailedPrints: 'Ukryj nieudane wydruki',
+    hideDuplicates: 'Ukryj duplikaty',
+    filterUnconfirmed: 'Niepotwierdzone',
+    filterUnconfirmedTitle: 'Pokaż tylko wydruki, które wciąż czekają na ocenę wyniku',
+    viewOriginalPrint: 'Kliknij, aby zobaczyć oryginalny wydruk (#{{id}})',
+    printTime: 'Czas druku',
+    filamentUsed: 'Zużyty filament',
+    cost: 'Koszt',
+    preview: 'Podgląd',
+    deleteArchive: 'Usuń archiwum',
+    deleteConfirm: 'Czy na pewno chcesz usunąć to archiwum?',
+    favorite: 'Ulubione',
+    unfavorite: 'Usuń z ulubionych',
+    viewDetails: 'Pokaż szczegóły',
+    status: {
+      completed: 'Ukończono',
+      failed: 'Nieudany',
+      stopped: 'Zatrzymano',
+    },
+    toast: {
+      source3mfAttached: 'Dołączono źródłowy plik 3MF: {{filename}}',
+      failedUploadSource3mf: 'Nie udało się przesłać źródłowego pliku 3MF',
+      source3mfRemoved: 'Usunięto źródłowy plik 3MF',
+      failedRemoveSource3mf: 'Nie udało się usunąć źródłowego pliku 3MF',
+      f3dAttached: 'Dołączono plik F3D: {{filename}}',
+      failedUploadF3d: 'Nie udało się przesłać pliku F3D',
+      f3dRemoved: 'Usunięto plik F3D',
+      failedRemoveF3d: 'Nie udało się usunąć pliku F3D',
+      timelapseAttached: 'Dołączono timelapse: {{filename}}',
+      timelapseAlreadyAttached: 'Timelapse jest już dołączony',
+      noMatchingTimelapse: 'Nie znaleziono pasującego timelapse',
+      failedScanTimelapse: 'Nie udało się wyszukać timelapse',
+      failedAttachTimelapse: 'Nie udało się dołączyć timelapse',
+      timelapseRemoved: 'Usunięto timelapse',
+      failedRemoveTimelapse: 'Nie udało się usunąć timelapse',
+      timelapseUploaded: 'Przesłano timelapse: {{filename}}',
+      failedUploadTimelapse: 'Nie udało się przesłać timelapse',
+      archiveDeleted: 'Usunięto archiwum',
+      failedDeleteArchive: 'Nie udało się usunąć archiwum',
+      addedToFavorites: 'Dodano do ulubionych',
+      removedFromFavorites: 'Usunięto z ulubionych',
+      projectUpdated: 'Zaktualizowano projekt',
+      failedUpdateProject: 'Nie udało się zaktualizować projektu',
+      linkCopied: 'Skopiowano link do schowka',
+      failedCopyLink: 'Nie udało się skopiować linku',
+      photoDeleted: 'Usunięto zdjęcie',
+      failedDeletePhoto: 'Nie udało się usunąć zdjęcia',
+      failedDeleteArchives: 'Nie udało się usunąć archiwów',
+      failedUpdateFavorites: 'Nie udało się zaktualizować ulubionych',
+      exportDownloaded: 'Pobrano eksport',
+      exportFailed: 'Eksport nie powiódł się',
+    },
+    menu: {
+      print: 'Drukuj',
+      openInBambuStudio: 'Otwórz w slicerze',
+      slice: 'Potnij',
+      externalLink: 'Link zewnętrzny',
+      viewOnMakerWorld: 'Zobacz w MakerWorld',
+      confirmOutcome: 'Potwierdź wynik',
+      preview3d: 'Podgląd 3D',
+      viewTimelapse: 'Pokaż timelapse',
+      scanForTimelapse: 'Wyszukaj timelapse',
+      uploadTimelapse: 'Prześlij timelapse',
+      removeTimelapse: 'Usuń timelapse',
+      downloadSource3mf: 'Pobierz źródłowy plik 3MF',
+      uploadSource3mf: 'Prześlij źródłowy plik 3MF',
+      replaceSource3mf: 'Zastąp źródłowy plik 3MF',
+      removeSource3mf: 'Usuń źródłowy plik 3MF',
+      uploadF3d: 'Prześlij F3D',
+      replaceF3d: 'Zastąp F3D',
+      downloadF3d: 'Pobierz F3D',
+      removeF3d: 'Usuń F3D',
+      download: 'Pobierz',
+      copyDownloadLink: 'Kopiuj link do pobrania',
+      qrCode: 'Kod QR',
+      viewPhotos: 'Pokaż zdjęcia',
+      viewPhotosCount: 'Pokaż zdjęcia ({{count}})',
+      projectPage: 'Strona projektu',
+      addToFavorites: 'Dodaj do ulubionych',
+      removeFromFavorites: 'Usuń z ulubionych',
+      edit: 'Edytuj',
+      printLog: 'Dziennik wydruków',
+      goToProject: 'Przejdź do projektu: {{name}}',
+      addToProject: 'Dodaj do projektu',
+      removeFromProject: 'Usuń z projektu',
+      loading: 'Wczytywanie...',
+      noProjectsAvailable: 'Brak dostępnych projektów',
+      searchProjects: 'Szukaj projektów…',
+      select: 'Zaznacz',
+      deselect: 'Odznacz',
+      delete: 'Usuń',
+    },
+    permission: {
+      noReprint: 'Nie masz uprawnień do ponownego wydruku tego archiwum',
+      noAddToQueue: 'Nie masz uprawnień do dodawania do kolejki',
+      noUpdateArchives: 'Nie masz uprawnień do aktualizowania archiwów',
+      noUploadFiles: 'Nie masz uprawnień do przesyłania plików',
+      noDownload: 'Nie masz uprawnień do pobierania archiwów',
+      noCopyLink: 'Nie masz uprawnień do kopiowania linków do pobrania',
+      noDelete: 'Nie masz uprawnień do usunięcia tego archiwum',
+      noEdit: 'Nie masz uprawnień do edycji tego wpisu',
+      noCreate: 'Nie masz uprawnień do tworzenia archiwów',
+    },
+    platePicker: {
+      title: 'Wybierz płytę do podglądu',
+      hint: 'To archiwum ma kilka płyt. Wybierz jedną, aby otworzyć ją w podglądzie G-code.',
+      plateLabel: 'Płyta {{index}}',
+      objectCount: '{{count}} obiekt',
+      objectCount_plural: 'Obiekty: {{count}}',
+      noGcode: 'To archiwum nie zawiera pociętego G-code do podglądu. Otwórz je najpierw w Bambu Studio, aby je pociąć.',
+    },
+    card: {
+      previousPlate: 'Poprzednia płyta',
+      nextPlate: 'Następna płyta',
+      plateNumber: 'Płyta {{index}}',
+      moreOptions: 'Kliknij prawym przyciskiem, aby zobaczyć więcej opcji',
+      addToFavorites: 'Dodaj do ulubionych',
+      removeFromFavorites: 'Usuń z ulubionych',
+      aborted: 'przerwano',
+      cancelled: 'anulowano',
+      failed: 'nieudany',
+      confirmPending: 'wynik?',
+      confirmPendingTitle: 'Ten wydruk czeka na ocenę wyniku — kliknij, aby odpowiedzieć',
+      rejected: 'odrzucony',
+      rejectedTitle: 'Ukończony na drukarce, oznaczony przez użytkownika jako odrzut',
+      confirmedGood: 'dobry',
+      confirmedGoodTitle: 'Potwierdzony przez użytkownika jako dobra część',
+      duplicate: 'duplikat',
+      duplicateTitle: 'Ten model był już drukowany',
+      openSource3mf: 'Otwórz źródłowy plik 3MF w Bambu Studio (prawy przycisk, aby zobaczyć więcej opcji)',
+      downloadF3d: 'Pobierz plik projektu Fusion 360',
+      viewTimelapse: 'Pokaż timelapse',
+      viewPhoto: 'Pokaż 1 zdjęcie',
+      viewPhotos: 'Pokaż zdjęcia ({{count}})',
+      openFolder: 'Otwórz folder: {{name}}',
+      slicedFile: 'Pocięty plik - gotowy do druku',
+      sourceFile: 'Tylko plik źródłowy - brak dostępnego mapowania AMS',
+      gcode: 'GCODE',
+      source: 'ŹRÓDŁO',
+      project: 'Projekt: {{name}}',
+      runsBadge: 'Wydruki: {{count}}',
+      runsBadgeTitle: 'Wydruki łącznie: {{count}} — udane: {{successful}}, nieudane: {{failed}}. Kliknij, aby zobaczyć pełny dziennik wydruków.',
+      estimated: 'Szacowany: {{time}}',
+      actual: 'Rzeczywisty: {{time}}',
+      accuracy: 'Dokładność: {{percent}}%',
+      filament: '{{weight}}g',
+      layer: '{{count}} warstwa',
+      layers: 'Warstwy: {{count}}',
+      wearCost: 'Zużycie drukarki',
+      costEstimate: 'Szacunek — ostateczny koszt zostanie ustalony po zakończeniu wydruku',
+      fullPrintFigure: 'Jeden pełny wydruk tego pliku. Zużycie w tym przebiegu znajdziesz w dzienniku wydruków',
+      object: '{{count}} obiekt',
+      objects: 'Obiekty: {{count}}',
+      slicedFor: 'Pocięty dla {{model}}',
+      uploadedBy: 'Przesłane przez',
+      noPermissionReprint: 'Nie masz uprawnień do ponownego wydruku',
+      noFileForReprint: 'Brak dostępnego pliku 3MF — nie udało się pobrać pliku z drukarki podczas rejestrowania wydruku',
+      slicerAmsMapping: 'Zapisano mapowanie AMS ({{printer}})',
+      slicerAmsMappingTooltip: 'Wybór slotów AMS dokonany przez slicer został zapisany dla {{printer}}. Numery slotów mają znaczenie tylko na tej drukarce, więc ponowny wydruk użyje ich tylko wtedy, gdy znów będzie skierowany na {{printer}}.',
+      noPermissionEdit: 'Nie masz uprawnień do edycji archiwów',
+      noPermissionDelete: 'Nie masz uprawnień do usuwania archiwów',
+      openInBambuStudio: 'Otwórz w slicerze',
+      openInBambuStudioToSlice: 'Otwórz w slicerze, aby pociąć',
+      slice: 'Potnij',
+      externalLink: 'Link zewnętrzny',
+      makerWorld: 'MakerWorld: {{designer}}',
+      viewProject: 'Pokaż projekt',
+      noExternalLink: 'Brak linku zewnętrznego',
+      preview3d: 'Podgląd 3D',
+      download: 'Pobierz',
+      edit: 'Edytuj',
+      delete: 'Usuń',
+    },
+    calendar: {
+      today: 'Dzisiaj',
+      previousMonth: 'Poprzedni miesiąc',
+      nextMonth: 'Następny miesiąc',
+      printsThisMonth: 'Wydruki w tym miesiącu',
+      successful: 'Udane',
+      failed: 'Nieudane',
+      noPrints: 'Brak wydruków tego dnia',
+      selectDay: 'Wybierz dzień, aby zobaczyć jego wydruki',
+    },
+    runLog: {
+      title: 'Dziennik wydruków',
+      modalTitle: 'Dziennik wydruków — {{name}}',
+      modalTitleFallback: 'to archiwum',
+      empty: 'Brak zarejestrowanych zdarzeń druku dla tego archiwum.',
+      col: {
+        date: 'Data',
+        status: 'Stan',
+        duration: 'Czas trwania',
+        filament: 'Filament',
+        cost: 'Koszt',
+        plate: 'Płyta',
+      },
+      status: {
+        completed: 'Ukończono',
+        failed: 'Nieudany',
+        cancelled: 'Anulowano',
+        stopped: 'Zatrzymano',
+        skipped: 'Pominięto',
+        printing: 'Drukowanie',
+        aborted: 'Przerwano',
+      },
+    },
+    modal: {
+      deleteArchive: 'Usuń archiwum',
+      deleteConfirm: 'Czy na pewno chcesz usunąć "{{name}}"? Tej operacji nie można cofnąć.',
+      deleteButton: 'Usuń',
+      deletePurgeStats: 'Usuń też ten wydruk z szybkich statystyk (filament, czas, koszt, energia)',
+      deleteQueueItemsWarning: 'Elementy kolejki powiązane z tym archiwum ({{count}}) również zostaną usunięte.',
+      deleteBlockedByPrinting: 'Nie można usunąć — elementy kolejki w trakcie druku: {{count}}. Najpierw zatrzymaj wydruk, a potem spróbuj ponownie.',
+      removeSource3mf: 'Usuń źródłowy plik 3MF',
+      removeSource3mfConfirm: 'Czy na pewno chcesz usunąć źródłowy plik 3MF z "{{name}}"? Spowoduje to usunięcie oryginalnego pliku projektu slicera.',
+      removeButton: 'Usuń',
+      removeF3d: 'Usuń F3D',
+      removeF3dConfirm: 'Czy na pewno chcesz usunąć plik projektu Fusion 360 z "{{name}}"?',
+      removeTimelapse: 'Usuń timelapse',
+      removeTimelapseConfirm: 'Czy na pewno chcesz usunąć film timelapse z "{{name}}"?',
+      timelapse: '{{name}} - Timelapse',
+      selectTimelapse: 'Wybierz timelapse',
+      selectTimelapseDesc: 'Nie znaleziono automatycznego dopasowania. Wybierz timelapse dla tego wydruku:',
+      deleteArchives: 'Usuń archiwa',
+      deleteArchivesConfirm: 'Czy na pewno chcesz usunąć archiwa ({{count}})? Tej operacji nie można cofnąć.',
+      deleteCount: 'Usuń ({{count}})',
+    },
+    page: {
+      title: 'Archiwa',
+      printsCount: 'Wydruki: {{filtered}} z {{total}}',
+      dropFilesHere: 'Upuść tutaj pliki .3mf',
+      releaseToUpload: 'Upuść, aby przesłać',
+      only3mfSupported: 'Obsługiwane są tylko pliki .3mf',
+      close: 'Zamknij',
+      selected: 'Zaznaczone: {{count}}',
+      selectAll: 'Zaznacz wszystkie',
+      tags: 'Tagi',
+      project: 'Projekt',
+      favorite: 'Ulubione',
+      delete: 'Usuń',
+      toggledFavorites: 'Przełączono ulubione dla archiwów: {{count}}',
+      failedUpdateFavorites: 'Nie udało się zaktualizować ulubionych',
+      archivesDeleted: 'Usunięte archiwa: {{count}}',
+      failedDeleteArchives: 'Nie udało się usunąć archiwów',
+      photoDeleted: 'Usunięto zdjęcie',
+      failedDeletePhoto: 'Nie udało się usunąć zdjęcia',
+    },
+    list: {
+      name: 'Nazwa',
+      printer: 'Drukarka',
+      date: 'Data',
+      size: 'Rozmiar',
+      actions: 'Akcje',
+      hasTimelapse: 'Ma timelapse',
+    },
+    log: {
+      date: 'Data',
+      printName: 'Nazwa wydruku',
+      printer: 'Drukarka',
+      user: 'Użytkownik',
+      status: 'Stan',
+      duration: 'Czas trwania',
+      filament: 'Filament',
+      filamentUsed: 'Zużyty filament',
+      cost: 'Koszt',
+      energy: 'Energia',
+      energyCost: 'Koszt energii',
+      wearCost: 'Koszt zużycia',
+      completedAt: 'Zakończono',
+      columns: 'Kolumny',
+      sortBy: 'Sortuj wg: {{column}}',
+      allPrinters: 'Wszystkie drukarki',
+      allUsers: 'Wszyscy użytkownicy',
+      allStatuses: 'Wszystkie stany',
+      cancelled: 'Anulowano',
+      skipped: 'Pominięto',
+      dateFrom: 'Od',
+      dateTo: 'Do',
+      noEntries: 'Nie znaleziono wpisów w dzienniku wydruków',
+      showing: 'Wyświetlanie {{count}} z {{total}} wpisów',
+      rowsPerPage: 'Wiersze',
+      page: 'Strona',
+      prev: 'Poprz.',
+      next: 'Nast.',
+      clearLog: 'Wyczyść dziennik',
+      clearLogTitle: 'Wyczyść dziennik wydruków',
+      clearLogConfirm: 'Wszystkie wpisy dziennika wydruków zostaną trwale usunięte. Archiwa i elementy kolejki pozostaną bez zmian. Tej operacji nie można cofnąć. Czy na pewno?',
+      clearLogButton: 'Wyczyść wszystko',
+      cleared: 'Wyczyszczone wpisy dziennika: {{count}}',
+      clearFailed: 'Nie udało się wyczyścić dziennika wydruków',
+      deleteEntryTitle: 'Usuń wpis dziennika wydruków',
+      deleteEntryConfirm: 'Ten wpis zostanie usunięty z dziennika, a jego udział w filamencie, czasie i koszcie zniknie z szybkich statystyk. Pasujące archiwum (jeśli istnieje) pozostanie bez zmian. Tej operacji nie można cofnąć.',
+      entryDeleted: 'Usunięto wpis dziennika wydruków',
+      entryDeleteFailed: 'Nie udało się usunąć wpisu dziennika wydruków',
+      editEntryTitle: 'Edytuj wpis dziennika wydruków',
+      editEntryDescription: 'Sklasyfikuj ten przebieg druku. Widżet analizy błędów grupuje według tych wartości, więc zmiany od razu trafiają do statystyk.',
+      entryUpdated: 'Zaktualizowano wpis dziennika wydruków',
+      entryUpdateFailed: 'Nie udało się zaktualizować wpisu dziennika wydruków',
+      statuses: {
+        completed: 'Ukończono',
+        failed: 'Nieudany',
+        stopped: 'Zatrzymano',
+        cancelled: 'Anulowano',
+        skipped: 'Pominięto',
+      },
+    },
+  },
+
+  // Sticky upload-progress toast (#1625 follow-up — restored the
+  // legacy bg-dispatch toast UI for the scheduler-driven dispatch path).
+  // Strings mirror 0b43ac0d's backgroundDispatch namespace.
+  dispatchToast: {
+    untitled: 'Zadanie druku',
+    startingPrints: 'Uruchamianie wydruków',
+    progressSummary: 'Ukończono {{complete}}/{{total}} • W toku: {{processing}}',
+    expandDetails: 'Rozwiń szczegóły wysyłania',
+    collapseDetails: 'Zwiń szczegóły wysyłania',
+    awaitingPrinter: 'Oczekiwanie na drukarkę…',
+    status: {
+      processing: 'Przetwarzanie',
+      completed: 'Ukończono',
+      failed: 'Nieudany',
+    },
+    failed: {
+      generic: 'Wysyłanie nie powiodło się',
+      upload_failed: 'Przesyłanie do drukarki nie powiodło się',
+      start_command_failed: 'Drukarka odrzuciła polecenie startu',
+    },
+    dismiss: 'Zamknij',
+  },
+
+  // Pipeline Runs dashboard (#1425 PR C). Lists every Slicer Pipeline run
+  // across every pipeline with status + pipeline filters and pagination.
+  // Each row expands to per-copy job status; partial-failure runs get a
+  // Retry-failed button; in-flight runs get a Cancel button.
+  pipelineRuns: {
+    title: 'Przebiegi potoków',
+    loading: 'Wczytywanie…',
+    empty: 'Brak przebiegów potoków.',
+    filter: {
+      pipeline: 'Potok',
+      status: 'Stan',
+      target: 'Cel',
+      all: 'Wszystkie',
+      allPipelines: 'Wszystkie potoki',
+      allStatus: 'Wszystkie stany',
+      allTargets: 'Wszystkie cele',
+      clear: 'Wyczyść filtry',
+      noMatches: 'Żaden przebieg nie pasuje do bieżących filtrów.',
+    },
+    totalCount_one: '{{n}} przebieg',
+    totalCount_other: 'Przebiegi: {{n}}',
+    copies: 'Kopie: {{n}}',
+    failedCount: 'Nieudane: {{n}}',
+    copyN: 'Kopia {{n}}',
+    retryFailed: 'Ponów nieudane',
+    retryOf: 'ponowienie #{{n}}',
+    pagination: '{{start}}–{{end}} z {{total}}',
+    cancelledByUser: 'Anulowane przez użytkownika',
+    toast: {
+      cancelled: 'Anulowano przebieg',
+      cancelFailed: 'Nie udało się anulować',
+      retryStarted: 'Rozpoczęto ponowienie',
+      retryFailed: 'Ponowienie nie powiodło się',
+      cleared: 'Wyczyszczone przebiegi: {{n}}',
+      clearFailed: 'Nie udało się wyczyścić',
+    },
+    clearLog: 'Wyczyść dziennik',
+    clearConfirmTitle: 'Wyczyścić dziennik?',
+    clearConfirmBody: 'Usunąć wszystkie ukończone, nieudane, anulowane i częściowo nieudane przebiegi potoków? Przebiegi w toku zostaną zachowane. Tej operacji nie można cofnąć.',
+    clearConfirmAction: 'Wyczyść',
+    jobStatus: {
+      pending: 'oczekuje',
+      awaiting_printer: 'oczekuje na drukarkę',
+      queued: 'w kolejce',
+      printing: 'drukowanie',
+      completed: 'ukończono',
+      failed: 'nieudany',
+      cancelled: 'anulowano',
+      unknown: 'nieznany',
+    },
+  },
+
+  // Queue page
+  queue: {
+    title: 'Kolejka druku',
+    subtitle: 'Planuj zadania druku i zarządzaj nimi',
+    filamentShort: {
+      rowBadge: 'Za mało filamentu na przypisanej szpuli',
+      rowTooltip: 'Harmonogram wysyłania oznaczył ten element. Kliknij Odtwórz, aby zobaczyć braki dla poszczególnych slotów i zdecydować, czy mimo to drukować.',
+      confirmTitle: 'Za mało filamentu',
+      confirmIntro: 'Przypisana szpula nie wystarczy dla co najmniej jednego slotu. Drukować mimo to?',
+      lineItem: 'Slot {{slot}}: potrzeba {{required}} g, pozostało {{remaining}} g',
+      unknown: 'nieznane',
+      printAnyway: 'Drukuj mimo to',
+    },
+    filamentMissing: {
+      confirmTitle: 'Filament niezaładowany',
+      confirmIntro: 'Drukarka nie ma slotu z tym filamentem. Załaduj go i ponownie naciśnij Start albo drukuj mimo to:',
+    },
+    colorSubstitution: {
+      rowBadge: 'Slot {{slot}} wydrukowany w kolorze {{got}}, plik wymaga {{wanted}}',
+      rowTooltip: 'Szpula, z której drukował ten slot, ma inny kolor niż ten w pliku: nie załadowano szpuli w tym kolorze albo slot wybrano ręcznie.',
+    },
+    slicerAmsMapping: {
+      rowBadge: 'Zapisano sloty AMS dla tej drukarki',
+      rowTooltip: 'To archiwum zawiera dokładnie te sloty AMS, które wybrał slicer, zapisane dla drukarki, do której kierowany jest ten element. Ponowny wydruk na niej może użyć tych slotów zamiast ponownie dopasowywać je według typu i koloru.',
+    },
+    // Print modal
+    editQueueItem: 'Edytuj element kolejki',
+    selectAllPlates: 'Zaznacz wszystkie płyty ({{count}})',
+    deselectAll: 'Odznacz wszystkie',
+    printQueued: 'Wydruk dodano do kolejki',
+    printQueuedWillStartWhenIdle: 'Rozpocznie się, gdy drukarka będzie bezczynna',
+    itemsQueued: 'Elementy dodane do kolejki: {{count}}',
+    sending: 'Wysyłanie...',
+    sendingProgress: 'Wysyłanie {{current}}/{{total}}...',
+    adding: 'Dodawanie...',
+    addingProgress: 'Dodawanie {{current}}/{{total}}...',
+    savingProgress: 'Zapisywanie {{current}}/{{total}}...',
+    clearQueue: 'Wyczyść kolejkę',
+    clearHistory: 'Wyczyść historię',
+    emptyQueue: 'Kolejka jest pusta',
+    position: 'Pozycja',
+    scheduledTime: 'Zaplanowany czas',
+    moveUp: 'Przenieś w górę',
+    moveDown: 'Przenieś w dół',
+    startNow: 'Uruchom teraz',
+    printingInProgress: 'Trwa drukowanie...',
+    viewArchive: 'Pokaż archiwum',
+    viewInFileManager: 'Pokaż w menedżerze plików',
+    itemCount: '{{count}} element',
+    itemCount_plural: 'Elementy: {{count}}',
+    dragToReorder: 'Przeciągnij, aby zmienić kolejność (tylko ASAP)',
+    reorderHint: 'Pozycja dotyczy tylko elementów ASAP. Zaplanowane elementy uruchamiają się o ustawionej godzinie.',
+    sjf: {
+      label: 'SJF',
+      tooltip: 'Najkrótsze zadanie najpierw — harmonogram priorytetyzuje krótsze wydruki',
+    },
+    addedBy: 'Dodane przez {{name}}',
+    nextInQueue: 'Następny w kolejce',
+    clearPlateSuccess: 'Płyta wyczyszczona — gotowa do następnego wydruku',
+    plateNumber: 'Płyta {{index}}',
+    // Batch / quantity
+    quantity: 'Ilość',
+    quantityHint: 'Tworzy elementy kolejki: {{count}}',
+    plateQuantityLabel: 'Przebiegi płyty {{plate}}',
+    plateQuantityTotal_one: '{{count}} przebieg łącznie',
+    plateQuantityTotal_other: 'Przebiegi łącznie: {{count}}',
+    batchOrders: {
+      title: 'Zamówienia seryjne',
+      emptyTitle: 'Brak zamówień seryjnych',
+      emptyDescription: 'Dodaj do kolejki plik z wieloma płytami lub więcej niż jedną kopię płyty, a zamówienie pojawi się tutaj wraz z postępem.',
+      filter: {
+        active: 'Aktywne',
+        completed: 'Ukończone',
+        failed: 'Nieudane',
+        cancelled: 'Anulowane',
+        all: 'Wszystkie',
+      },
+      status: {
+        active: 'Aktywne',
+        completed: 'Ukończone',
+        failed: 'Nieudane',
+        cancelled: 'Anulowane',
+      },
+      noTargets: 'Tylko grupowanie',
+      noTargetsHint: 'Utworzone, zanim istniały cele dla poszczególnych płyt, więc śledzi dodane do kolejki przebiegi, a nie cel.',
+      dispatchRemaining: 'Dodaj pozostałe do kolejki ({{count}})',
+      dispatchPlate: 'Dodaj pozostałe do kolejki',
+      strandedPlate: 'Nie ma już skąd skopiować ustawień',
+      strandedNotice: 'Nie można dodać do kolejki {{runs}} z {{owed}} zaległych przebiegów: dla tej płyty nie ma już przebiegu w kolejce ani ukończonego, z którego można skopiować ustawienia. Dodaj płytę raz z pliku albo anuluj zamówienie.',
+      dispatched: 'Dodano do kolejki pozostałe przebiegi dla {{name}}',
+      plateProgress: 'Gotowe: {{completed}} z {{target}}',
+      remaining: 'Zaległe: {{count}}',
+      failed: 'Nieudane: {{count}}',
+      printing: 'Drukowane: {{count}}',
+      wholeFile: 'Cały plik',
+      due: 'Termin: {{date}}',
+      costSoFar: 'Dotąd {{amount}}',
+      costRemaining: '(jeszcze {{amount}})',
+    },
+    activeBatches: 'Aktywne serie',
+    batchProgress: 'Ukończono {{completed}} z {{total}}',
+    cancelBatch: 'Anuluj pozostałe',
+    batchCancelled: 'Anulowano pozostałe elementy serii',
+    cancelBatchConfirmTitle: 'Anuluj serię',
+    cancelBatchConfirmMessage: 'Zamknąć to zamówienie? Przebiegi wciąż w kolejce zostaną anulowane, a zamówienie przestanie domagać się tego, czego jeszcze nie wyprodukowano.',
+    batch: {
+      defaultName: 'Seria',
+      label: '{{count}} element',
+      label_plural: 'Elementy: {{count}}',
+      pendingCount: 'Oczekujące: {{count}}',
+      pendingCount_plural: 'Oczekujące: {{count}}',
+      expand: 'Rozwiń serię',
+      collapse: 'Zwiń serię',
+      groupAsBatch: 'Grupuj jako serię…',
+      groupAsBatchDescription: 'Połącz zaznaczone elementy ({{count}}) w jedną zwijaną serię.',
+      nameLabel: 'Nazwa serii',
+      namePlaceholder: 'np. Prezenty na piątek',
+      create: 'Utwórz serię',
+      ungroup: 'Rozgrupuj',
+      ungroupConfirmTitle: 'Rozgrupować serię?',
+      ungroupConfirmMessage: 'Elementy pozostaną w kolejce, ale nie będą już zgrupowane.',
+      dragGroup: 'Przeciągnij grupę',
+    },
+    // Tabs
+    tabs: {
+      batches: 'Serie',
+      queue: 'Kolejka',
+      history: 'Historia',
+      timeline: 'Oś czasu',
+      pipelines: 'Potoki',
+    },
+    // Layout toggle on the Queue tab — distinct from the sort dropdown
+    // (those control order; these control whether items render as one flat
+    // list or grouped under per-printer section headers).
+    layout: {
+      flatList: 'Lista',
+      byPrinter: 'Wg drukarki',
+      groupByPrinter: 'Grupuj wg drukarki',
+    },
+    // History tab empty state
+    history: {
+      emptyTitle: 'Brak historii',
+      emptyDescription: 'Tutaj pojawią się ukończone, anulowane i nieudane wydruki.',
+      showMore: 'Pokaż więcej',
+      showingCount: 'Wyświetlanie {{shown}} z {{total}}',
+    },
+    // Drag ghost label when multi-dragging
+    dragGhost: {
+      multiCount: 'Elementy: {{count}}',
+      batch: '{{name}} ({{count}} kopia)',
+      batch_plural: '{{name}} (kopie: {{count}})',
+    },
+    // Sections
+    sections: {
+      currentlyPrinting: 'Obecnie drukowane',
+      queued: 'W kolejce',
+      history: 'Historia',
+    },
+    // Status
+    status: {
+      pending: 'Oczekuje',
+      waiting: 'Czeka',
+      printing: 'Drukowanie',
+      paused: 'Wstrzymano',
+      completed: 'Ukończono',
+      failed: 'Nieudany',
+      skipped: 'Pominięto',
+      cancelled: 'Anulowano',
+    },
+    // Summary cards
+    summary: {
+      printing: 'Drukowanie',
+      queued: 'W kolejce',
+      totalTime: 'Łączny czas kolejki',
+      totalWeight: 'Łączna waga kolejki',
+      history: 'Historia',
+    },
+    // Filters
+    filter: {
+      allPrinters: 'Wszystkie drukarki',
+      unassigned: 'Nieprzypisane',
+      allStatus: 'Wszystkie stany',
+      allLocations: 'Wszystkie lokalizacje',
+      any: 'Dowolna',
+    },
+    // Sort
+    sort: {
+      byPosition: 'Sortuj wg pozycji',
+      byName: 'Sortuj wg nazwy',
+      byPrinter: 'Sortuj wg drukarki',
+      bySchedule: 'Sortuj wg harmonogramu',
+      byDate: 'Sortuj wg daty',
+      ascendingOldest: 'Rosnąco (najstarsze najpierw)',
+      descendingNewest: 'Malejąco (najnowsze najpierw)',
+    },
+    // Badges
+    badges: {
+      awaitingReview: 'Czeka na przegląd',
+      staged: 'Przygotowane',
+      requiresPrevious: 'Wymaga powodzenia poprzedniego',
+      autoPowerOff: 'Automatyczne wyłączenie',
+      gcodeInjection: 'G-code',
+      confirmOutcome: 'Pytanie o wynik',
+      confirmOutcomeTitle: 'Po zakończeniu pyta, jak wyszedł wydruk',
+    },
+    // Empty state
+    empty: {
+      title: 'Brak zaplanowanych wydruków',
+      description: 'Zaplanuj wydruk ze strony Archiwa za pomocą opcji "Zaplanuj" w menu kontekstowym albo przeciągnij i upuść pliki, aby rozpocząć.',
+    },
+    // Time
+    time: {
+      etaIfStartedNow: 'Czas ukończenia, gdyby to zadanie zaczęło się teraz',
+      whenFree: 'Gdy drukarka będzie wolna',
+      overdue: 'Po terminie',
+      now: 'Teraz',
+      lessThanMinute: 'Za mniej niż minutę',
+      inMinutes: 'Za {{count}} min',
+      inHours: 'Za {{count}} godz.',
+    },
+    // Actions
+    actions: {
+      startPrint: 'Rozpocznij druk',
+      stopPrint: 'Zatrzymaj druk',
+      requeue: 'Dodaj ponownie do kolejki',
+    },
+    // Bulk edit
+    bulkEdit: {
+      title: 'Edytuj {{count}} element',
+      title_plural: 'Edytuj elementy ({{count}})',
+      description: 'Do zaznaczonych elementów zostaną zastosowane tylko zmienione ustawienia.',
+      printer: 'Drukarka',
+      noChange: '— Bez zmian —',
+      queueOptions: 'Opcje kolejki',
+      staged: 'Przygotowane (ręczny start)',
+      autoPowerOff: 'Automatyczne wyłączenie po wydruku',
+      requirePrevious: 'Wymagaj powodzenia poprzedniego',
+      gcodeInjection: 'Wstrzyknij G-code',
+      printOptions: 'Opcje druku',
+      bedLevelling: 'Poziomowanie stołu',
+      flowCalibration: 'Kalibracja przepływu',
+      vibrationCalibration: 'Kalibracja drgań',
+      layerInspection: 'Inspekcja pierwszej warstwy',
+      timelapse: 'Timelapse',
+      useAms: 'Użyj AMS',
+      confirmOutcome: 'Pytaj o wynik',
+      nozzleOffsetCali: 'Kalibracja przesunięcia dyszy',
+      applyChanges: 'Zastosuj zmiany',
+      selectAll: 'Zaznacz wszystkie',
+      deselectAll: 'Odznacz wszystkie',
+      selected: 'Zaznaczone: {{count}}',
+      editSelected: 'Edytuj zaznaczone',
+      cancelSelected: 'Anuluj zaznaczone',
+    },
+    // Confirmations
+    confirm: {
+      cancelTitle: 'Anuluj zaplanowany wydruk',
+      cancelMessage: 'Czy na pewno chcesz anulować "{{name}}"?',
+      stopTitle: 'Zatrzymaj druk',
+      stopMessage: 'Czy na pewno chcesz zatrzymać bieżący wydruk "{{name}}"? Spowoduje to anulowanie zadania druku na drukarce.',
+      removeTitle: 'Usuń z historii',
+      removeMessage: 'Czy na pewno chcesz usunąć "{{name}}" z historii kolejki?',
+      clearHistoryTitle: 'Wyczyść historię',
+      clearHistoryMessage: 'Czy na pewno chcesz usunąć wszystkie elementy z historii ({{count}})?',
+      cancelButton: 'Anuluj wydruk',
+      stopButton: 'Zatrzymaj druk',
+      thisPrint: 'ten wydruk',
+      thisItem: 'ten element',
+    },
+    // Toast messages
+    toast: {
+      cancelled: 'Anulowano element kolejki',
+      cancelFailed: 'Nie udało się anulować elementu',
+      removed: 'Usunięto element kolejki',
+      keptForOrder: 'Anulowano zamiast usunąć: to jedyny przebieg, z którego zamówienie seryjne może ponownie dodać tę płytę do kolejki',
+      historyKeptForOrders: 'Zachowano elementy potrzebne jeszcze zamówieniom seryjnym: {{kept}}.',
+      removeFailed: 'Nie udało się usunąć elementu',
+      stopped: 'Zatrzymano wydruk',
+      stopFailed: 'Nie udało się zatrzymać wydruku',
+      released: 'Wydruk zwolniony do kolejki',
+      startFailed: 'Nie udało się rozpocząć wydruku',
+      reorderFailed: 'Nie udało się zmienić kolejności kolejki',
+      historyCleared: 'Wyczyszczone elementy historii: {{count}}',
+      clearHistoryFailed: 'Nie udało się wyczyścić historii',
+      updateFailed: 'Nie udało się zaktualizować elementów',
+      bulkUpdated: 'Zaktualizowane zadania: {{updated}}',
+      bulkUpdatedSome: 'Zaktualizowane zadania: {{updated}}; nie udało się zmienić: {{skipped}}',
+      bulkUpdatedNone: 'Nie zaktualizowano żadnych zadań',
+      bulkCancelled: 'Anulowane elementy: {{count}}',
+      bulkCancelFailed: 'Nie udało się anulować elementów',
+      batchCreated: 'Utworzono serię "{{name}}"',
+      batchCreateFailed: 'Nie udało się utworzyć serii',
+      batchUngrouped: 'Rozgrupowane elementy: {{count}}',
+      batchUngroupFailed: 'Nie udało się rozgrupować serii',
+      resumedAfterFailure: 'Wznowiono kolejkę — zadania przywrócone do oczekujących: {{restored}}',
+      resumedModelAfterFailure: 'Zdjęto blokadę z nieudanych wydruków: {{count}}',
+      resumeAfterFailureFailed: 'Nie udało się wznowić kolejki',
+    },
+    resumeModelAfterFailure: {
+      banner: 'Zadania dla dowolnej {{model}} czekają ({{count}}): ostatni wydruk nie powiódł się na każdej wolnej {{model}}',
+      bannerHint: 'Napraw drukarki, a potem wznów, aby zdjąć blokadę. Zadania uruchomią się wtedy na następnej wolnej {{model}}.',
+      confirmMessage: 'Zdejmij blokadę po poprzednim wydruku na każdej drukarce {{model}}, której możesz używać. Przed kontynuowaniem upewnij się, że drukarki są gotowe.',
+    },
+    resumeAfterFailure: {
+      banner: '{{printer}} jest zablokowana przez nieudany poprzedni wydruk — pominięte zadania: {{count}}',
+      bannerHint: 'Usuń problem z drukarką, a potem wznów, aby przywrócić pominięte zadania i zdjąć blokadę.',
+      button: 'Wznów po błędzie',
+      confirmTitle: 'Wznowić kolejkę po błędzie?',
+      confirmMessage: 'Przywróć pominięte zadania ({{count}}) na {{printer}} do oczekujących i zdejmij blokadę po poprzednim wydruku. Przed kontynuowaniem upewnij się, że drukarka jest gotowa.',
+    },
+    // Timeline view
+    timeline: {
+      listView: 'Lista',
+      timelineView: 'Oś czasu',
+      unassigned: 'Nieprzypisane',
+      noData: 'Brak zaplanowanych wydruków na ten dzień',
+      nothingCommitted: 'Brak zatwierdzonych harmonogramów w tym oknie. Elementy przygotowane, oczekujące i zadania ASAP na bezczynnych drukarkach nie są pokazywane — ustaw zaplanowany czas lub zwolnij przygotowany element, aby go tu zobaczyć.',
+      allDoneBy: 'Wszystkie wydruki szacunkowo gotowe do {{time}}',
+      staged: 'Przygotowane',
+      filterAll: 'Pokaż wszystkie',
+      filterPrinting: 'Drukowanie',
+      filterQueued: 'W kolejce',
+      time: {
+        anyMoment: 'lada chwila',
+        minutesLeft: 'pozostało {{minutes}} min',
+        hoursLeft: 'pozostało {{hours}} godz.',
+        hoursMinutesLeft: 'pozostało {{hours}} godz. {{minutes}} min',
+      },
+      day: {
+        previous: 'Poprzedni dzień',
+        next: 'Następny dzień',
+        today: 'Dzisiaj',
+      },
+      // Rolling-24h Gantt window
+      window: {
+        back12h: '12 godzin wstecz',
+        forward12h: '12 godzin naprzód',
+        now: 'Teraz',
+      },
+      printerColumnHeader: 'Drukarka',
+    },
+    // Permissions
+    permissions: {
+      noStopPrint: 'Nie masz uprawnień do zatrzymywania wydruków',
+      noStartPrint: 'Nie masz uprawnień do uruchamiania wydruków',
+      awaitingReview: 'Czeka na przegląd: to zadanie uruchomi osoba zarządzająca kolejką',
+      noEdit: 'Nie masz uprawnień do edycji tego elementu kolejki',
+      noCancel: 'Nie masz uprawnień do anulowania tego elementu kolejki',
+      noRequeue: 'Nie masz uprawnień do ponownego dodawania elementów do kolejki',
+      noRemove: 'Nie masz uprawnień do usunięcia tego elementu kolejki',
+      noClearHistory: 'Nie masz uprawnień do czyszczenia całej historii',
+      noEditItems: 'Nie masz uprawnień do edycji elementów kolejki',
+      noCancelItems: 'Nie masz uprawnień do anulowania elementów kolejki',
+    },
+  },
+
+  // Statistics page
+  stats: {
+    title: 'Statystyki',
+    subtitle: 'Przeciągnij widżety, aby zmienić ich układ. Kliknij ikonę oka, aby ukryć.',
+    overview: 'Przegląd',
+    totalPrints: 'Wszystkie wydruki',
+    successRate: 'Skuteczność',
+    totalPrintTime: 'Łączny czas druku',
+    printTime: 'Czas druku',
+    totalFilament: 'Łączne zużycie filamentu',
+    filamentUsed: 'Zużyty filament',
+    filamentCost: 'Koszt filamentu',
+    totalCost: 'Łączny koszt',
+    energyUsed: 'Zużyta energia',
+    energyCost: 'Koszt energii',
+    wearCost: 'Koszt zużycia',
+    energyWarmingUpTooltip: 'Śledzenie energii wciąż zbiera godzinowe migawki. Sumy dla zakresu dat staną się dokładne, gdy istnieje co najmniej jedna migawka sprzed wybranego zakresu. Wczesne wartości mogą być zaniżone.',
+    averagePrintTime: 'Średni czas druku',
+    printsPerDay: 'Wydruki dziennie',
+    byPrinter: 'Wg drukarki',
+    printsByPrinter: 'Wydruki wg drukarki',
+    byMaterial: 'Wg materiału',
+    byMonth: 'Wg miesiąca',
+    last7Days: 'Ostatnie 7 dni',
+    last30Days: 'Ostatnie 30 dni',
+    last90Days: 'Ostatnie 90 dni',
+    allTime: 'Cały okres',
+    // Widgets
+    quickStats: 'Szybkie statystyki',
+    printActivity: 'Aktywność druku',
+    filamentTypes: 'Rodzaje filamentu',
+    filamentTrends: 'Trendy filamentu',
+    // Consumption/cost grouped by the internal material number (#2870).
+    materialNumbers: {
+      title: 'Wg numeru materiału',
+      empty: 'Nie przypisano jeszcze numerów materiałów. Dodaj je do szpul w magazynie, aby grupować tutaj zużycie i koszty.',
+      loadFailed: 'Nie udało się wczytać statystyk numerów materiałów.',
+      spools: 'Szpule',
+      remaining: 'Pozostało',
+      consumed: 'Zużyto',
+      cost: 'Koszt',
+    },
+    // Consumption/cost grouped by purchase-source supplier (#2988).
+    suppliers: {
+      title: 'Wg dostawcy',
+      empty: 'Nie zarejestrowano jeszcze zakupów. Zaznacz przy szpuli, u którego dostawcy została kupiona, aby grupować tutaj zużycie i koszty.',
+      error: 'Nie udało się wczytać statystyk dostawców',
+      supplier: 'Dostawca',
+      spools: 'Szpule',
+      remaining: 'Pozostało',
+      consumed: 'Zużyto',
+      cost: 'Koszt',
+    },
+    failureAnalysis: 'Analiza niepowodzeń',
+    timeAccuracy: 'Dokładność czasu',
+    successful: 'Udane:',
+    failed: 'Nieudane:',
+    cancelled: 'Anulowane:',
+    perfectEstimate: '100% = idealny szacunek',
+    noTimeAccuracyData: 'Brak jeszcze danych o dokładności czasu',
+    noFilamentData: 'Brak danych o filamencie',
+    noPrinterData: 'Brak danych o drukarkach',
+    noPrintData: 'Brak danych o wydrukach',
+    noPrintDataLast30Days: 'Brak danych o wydrukach z ostatnich 30 dni',
+    failureReasons: 'Przyczyny niepowodzeń',
+    topFailureReasons: 'Najczęstsze przyczyny niepowodzeń',
+    failedPrintsCount: 'Nieudane wydruki: {{failed}} / {{total}}',
+    rejectedPrintsCount: 'Odrzucone po ukończeniu: {{rejected}}',
+    yieldRate: 'Uzysk: {{rate}}%',
+    lastWeekRate: 'Ostatni tydzień: {{rate}}%',
+    // Actions
+    resetLayout: 'Resetuj układ',
+    recalculateCosts: 'Przelicz koszty',
+    recalculateCostsHint: 'Przelicz koszty wszystkich archiwów według bieżących cen filamentu',
+    exportStats: 'Eksportuj statystyki',
+    exportAsCsv: 'Eksportuj jako CSV',
+    exportAsExcel: 'Eksportuj jako Excel',
+    hiddenCount: 'Ukryte: {{count}}',
+    // Toast
+    exportDownloaded: 'Pobrano eksport',
+    exportFailed: 'Eksport nie powiódł się',
+    layoutReset: 'Zresetowano układ',
+    recalculatedCosts: 'Przeliczono koszty archiwów: {{count}}',
+    recalculateSpoolmanUnreachable: 'Nie udało się połączyć ze Spoolman: rekordy zużycia jego szpul zachowały starą cenę (liczba: {{count}})',
+    recalculateFailed: 'Nie udało się przeliczyć kosztów',
+    // Loading
+    loadingStats: 'Wczytywanie statystyk...',
+    // Permissions
+    noPermissionResetLayout: 'Nie masz uprawnień do resetowania układu',
+    noPermissionRecalculate: 'Nie masz uprawnień do przeliczania kosztów',
+    noPrintDataInRange: 'Brak danych o wydrukach w wybranym zakresie',
+    periodFilament: 'Filament w okresie',
+    periodCost: 'Koszt w okresie',
+    avgPerPrint: 'Średnio na wydruk',
+    usageOverTime: 'Zużycie w czasie',
+    energyOverTime: 'Energia w czasie',
+    filamentByWeight: 'Waga',
+    printDuration: 'Czas trwania druku',
+    printerUtilization: 'Wykorzystanie drukarek',
+    filamentSuccess: 'Skuteczność wg materiału',
+    printHabits: 'Nawyki drukowania',
+    printTimeOfDay: 'Pora dnia druku',
+    colorDistribution: 'Rozkład kolorów',
+    noColorData: 'Brak danych o kolorach',
+    records: 'Rekordy',
+    longestPrint: 'Najdłuższy wydruk',
+    heaviestPrint: 'Najcięższy wydruk',
+    mostExpensivePrint: 'Najdroższy',
+    busiestDay: 'Najbardziej pracowity dzień',
+    successStreak: 'Seria sukcesów',
+    streakPrint: 'udany wydruk z rzędu',
+    streakPrints: 'Udane wydruki z rzędu: {{count}}',
+    printerStats: 'Statystyki drukarek',
+    hours: 'godz.',
+    avgPrints: 'Śr. wydruków',
+    noArchiveData: 'Brak danych o wydrukach',
+    filamentByTime: 'Czas',
+    avgWeight: 'Śr. waga',
+    avgTime: 'Śr. czas',
+    filamentByPrints: 'Wydruki',
+    timeframe: {
+      'today': 'Dzisiaj',
+      'this-week': 'Ten tydzień',
+      'this-month': 'Ten miesiąc',
+      'last-7': 'Ostatnie 7 dni',
+      'last-30': 'Ostatnie 30 dni',
+      'last-90': 'Ostatnie 90 dni',
+      'this-year': 'Ten rok',
+      'all-time': 'Cały okres',
+      'custom': 'Zakres niestandardowy',
+      from: 'Od',
+      to: 'Do',
+    },
+    // User filter
+    allUsers: 'Wszyscy użytkownicy',
+    noUser: 'Brak użytkownika (system)',
+    filterByUser: 'Filtruj wg użytkownika',
+  },
+
+  // Maintenance page
+  maintenance: {
+    title: 'Konserwacja',
+    overview: 'Przegląd',
+    allOk: 'Cała konserwacja jest aktualna',
+    dueCount: '{{count}} zadanie do wykonania',
+    dueCount_plural: 'Zadania do wykonania: {{count}}',
+    warningCount: '{{count}} ostrzeżenie',
+    warningCount_plural: 'Ostrzeżenia: {{count}}',
+    totalPrintTime: 'Łączny czas druku',
+    nextMaintenance: 'Następna konserwacja',
+    nothingDue: 'Nic do wykonania',
+    tasks: 'Zadania',
+    lastPerformed: 'Ostatnio wykonano',
+    interval: 'Interwał',
+    hoursRemaining: 'Pozostało {{hours}} godz.',
+    hoursOverdue: 'Po terminie {{hours}} godz.',
+    markDone: 'Oznacz jako wykonane',
+    performMaintenance: 'Wykonaj konserwację',
+    history: 'Historia',
+    noHistory: 'Brak historii konserwacji',
+    editPrintHours: 'Edytuj godziny druku',
+    currentHours: 'Bieżące godziny',
+    // Tabs
+    statusTab: 'Status',
+    settingsTab: 'Ustawienia',
+    // Status
+    overdueCount: 'Po terminie: {{count}}',
+    dueSoonCount: 'Wkrótce do wykonania: {{count}}',
+    dueSoon: 'Wkrótce',
+    allGood: 'Wszystko w porządku',
+    overdueBy: 'Po terminie o {{duration}}',
+    dueIn: 'Termin za {{duration}}',
+    timeLeft: 'Pozostało: {{duration}}',
+    // Duration formats
+    day: '1 dzień',
+    days: '{{count}} dni',
+    week: '1 tydzień',
+    weeks: '{{count}} tyg.',
+    month: '1 miesiąc',
+    months: '{{count}} mies.',
+    year: '1 rok',
+    // Settings
+    maintenanceTypes: 'Typy konserwacji',
+    maintenanceTypesDescription: 'Typy systemowe i twoje własne zadania konserwacyjne',
+    addCustomType: 'Dodaj własny typ',
+    restoreDefaults: 'Przywróć domyślne zadania',
+    intervalType: 'Typ interwału',
+    intervalValue: 'Interwał ({{type}})',
+    icon: 'Ikona',
+    documentationLink: 'Link do dokumentacji (opcjonalnie)',
+    assignToPrinters: 'Przypisz do drukarek',
+    selectAtLeastOnePrinter: 'Wybierz co najmniej jedną drukarkę',
+    addType: 'Dodaj typ',
+    custom: 'Własny',
+    printHours: 'Godziny druku',
+    calendarDays: 'Dni kalendarzowe',
+    exampleName: 'np. Wymień filtr HEPA',
+    viewDocumentation: 'Zobacz dokumentację',
+    timeBasedInterval: 'Interwał czasowy',
+    // Interval overrides
+    intervalOverrides: 'Nadpisania interwałów',
+    intervalOverridesDescription: 'Dostosuj interwały dla wybranych drukarek',
+    // Printer assignment
+    assignedToPrinters: 'Przypisano do drukarek:',
+    noPrintersAssigned: 'Nie przypisano drukarek',
+    addPrinterShort: 'Dodaj:',
+    printersAssignedClick: 'Przypisane drukarki: {{count}} – kliknij, aby zarządzać',
+    removeFromPrinter: 'Usuń z tej drukarki',
+    // Types
+    types: {
+      lubricateCarbonRods: 'Nasmaruj pręty węglowe',
+      lubricateRails: 'Nasmaruj prowadnice liniowe',
+      cleanNozzle: 'Wyczyść dyszę/hotend',
+      checkBelts: 'Sprawdź naciąg pasków',
+      cleanBuildPlate: 'Wyczyść płytę roboczą',
+      checkExtruder: 'Sprawdź koła zębate ekstrudera',
+      checkCooling: 'Sprawdź wentylatory chłodzące',
+      generalInspection: 'Przegląd ogólny',
+      cleanCarbonRods: 'Wyczyść pręty węglowe',
+      lubricateSteelRods: 'Nasmaruj pręty stalowe',
+      cleanSteelRods: 'Wyczyść pręty stalowe',
+      cleanLinearRails: 'Wyczyść prowadnice liniowe',
+      checkPtfeTube: 'Sprawdź rurkę PTFE',
+      replaceHepaFilter: 'Wymień filtr HEPA',
+      replaceCarbonFilter: 'Wymień filtr węglowy',
+      lubricateLeftNozzleRail: 'Nasmaruj prowadnicę lewej dyszy',
+    },
+    // Toast
+    maintenanceComplete: 'Oznaczono konserwację jako wykonaną',
+    typeUpdated: 'Zaktualizowano typ konserwacji',
+    typeDeleted: 'Usunięto typ konserwacji',
+    defaultsRestored: 'Przywrócone domyślne zadania: {{count}}',
+    printHoursUpdated: 'Zaktualizowano godziny druku',
+    printerAssigned: 'Przypisano drukarkę',
+    printerRemoved: 'Usunięto drukarkę',
+    // Confirmation
+    deleteTypeConfirm: 'Usunąć „{{name}}”?',
+    deleteTypeAllPrinters: 'Spowoduje to usunięcie go ze wszystkich drukarek, nie tylko twoich, łącznie z historią konserwacji.',
+    deleteSystemTypeTitle: 'Usunąć domyślne zadanie konserwacyjne?',
+    deleteSystemTypeMessage: 'Czy na pewno chcesz usunąć domyślne zadanie konserwacyjne „{{name}}”?',
+    // Permissions
+    noPermissionUpdate: 'Nie masz uprawnień do aktualizowania elementów konserwacji',
+    noPermissionPerform: 'Nie masz uprawnień do wykonywania konserwacji',
+    noPermissionEditTypes: 'Nie masz uprawnień do edytowania typów konserwacji',
+    noPermissionDeleteTypes: 'Nie masz uprawnień do usuwania typów konserwacji',
+    noPermissionEditHours: 'Nie masz uprawnień do edytowania godzin druku',
+    noPermissionRemovePrinter: 'Nie masz uprawnień do usuwania przypisań drukarek',
+    noPermissionAssignPrinter: 'Nie masz uprawnień do przypisywania drukarek',
+    noPermissionEditIntervals: 'Nie masz uprawnień do edytowania interwałów',
+    // Configure link
+    configureSettings: 'Skonfiguruj typy i interwały konserwacji',
+  },
+
+  // Settings page
+  settings: {
+    sliceEngine: 'Silnik slicowania',
+    sliceEngineSidecar: 'Sidecar na serwerze',
+    sliceEngineSidecarHint: 'Slicowanie odbywa się na serwerze, w kontenerze sidecar slicera.',
+    sliceEngineBrowser: 'W przeglądarce',
+    sliceEngineBrowserHint: 'Slicowanie odbywa się na tym urządzeniu, bez udziału serwera.',
+    title: 'Ustawienia',
+    general: 'Ogólne',
+    // Tab names
+    tabs: {
+      general: 'Ogólne',
+      smartPlugs: 'Inteligentne gniazdka',
+      sensors: 'Czujniki',
+      notifications: 'Powiadomienia',
+      queue: 'Przepływ pracy',
+      queueDispatch: 'Kolejka i wysyłanie',
+      queuePipelines: 'Potoki',
+      filament: 'Filament',
+      camera: 'Kamera',
+      network: 'Sieć',
+      apiKeys: 'Klucze API',
+      virtualPrinter: 'Wirtualna drukarka',
+      spoolbuddy: 'SpoolBuddy',
+      failureDetection: 'Wykrywanie błędów',
+      users: 'Uwierzytelnianie',
+      backup: 'Kopia zapasowa',
+      emailAuth: 'Uwierzytelnianie e-mail',
+      ldap: 'LDAP',
+      twoFa: 'Uwierzytelnianie dwuskładnikowe',
+      oidc: 'SSO / OIDC',
+      security: 'Bezpieczeństwo',
+    },
+    spoolbuddy: {
+      infoTitle: 'Urządzenia SpoolBuddy',
+      infoBody: 'Kioski SpoolBuddy rejestrują się automatycznie przez heartbeat. Wyrejestruj tutaj urządzenie, jeśli nie jest już używane lub jeśli po awarii demona pozostał nieaktualny duplikat.',
+      duplicatesTitle: 'Zarejestrowane urządzenia: {{count}}',
+      duplicatesBody: 'Interfejs kiosku używa tylko pierwszego zarejestrowanego urządzenia. Jeśli któreś z nich jest nieaktualnym duplikatem po awarii, wyrejestruj je — urządzenie online zarejestruje się ponownie przy następnym heartbeacie.',
+      empty: 'Nie zarejestrowano jeszcze urządzeń SpoolBuddy.',
+      online: 'Online',
+      offline: 'Offline',
+      unregister: 'Wyrejestruj',
+      unregisterSuccess: 'Wyrejestrowano urządzenie',
+      unregisterError: 'Nie udało się wyrejestrować urządzenia',
+      confirmTitle: 'Wyrejestrować urządzenie SpoolBuddy?',
+      confirmBody: 'Spowoduje to usunięcie „{{hostname}}” ({{deviceId}}) z bazy danych. Jeśli urządzenie jest online, zarejestruje się ponownie przy następnym heartbeacie.',
+      ipAddress: 'Adres IP',
+      firmware: 'Firmware',
+      lastSeen: 'Ostatnio widziane',
+      daemonUptime: 'Czas działania demona',
+      systemUptime: 'Czas działania systemu',
+      never: 'nigdy',
+      nfc: 'NFC',
+      scale: 'Waga',
+      cpuTemp: 'Temp. CPU',
+      cpuLoad: 'Obciążenie CPU',
+      memory: 'Pamięć',
+      disk: 'Dysk',
+      // Device actions
+      update: 'Aktualizuj',
+      updateConfirmTitle: 'Zaktualizować demona Spoolbuddy?',
+      updateConfirmBody: 'Uruchomić aktualizację oprogramowania na „{{hostname}}”? Demon uruchomi się ponownie po zastosowaniu aktualizacji.',
+      restartBrowser: 'Uruchom ponownie przeglądarkę',
+      restartBrowserConfirmTitle: 'Uruchomić ponownie przeglądarkę kiosku?',
+      restartBrowserConfirmBody: 'Uruchomić ponownie przeglądarkę kiosku na „{{hostname}}”? Ekran na chwilę zgaśnie.',
+      restartDaemon: 'Uruchom ponownie demona',
+      restartDaemonConfirmTitle: 'Uruchomić ponownie demona Spoolbuddy?',
+      restartDaemonConfirmBody: 'Uruchomić ponownie demona Spoolbuddy na „{{hostname}}”? Urządzenie będzie offline przez kilka sekund.',
+      reboot: 'Uruchom ponownie',
+      rebootConfirmTitle: 'Uruchomić ponownie urządzenie?',
+      rebootConfirmBody: 'Uruchomić ponownie „{{hostname}}”? Urządzenie będzie offline przez około minutę.',
+      shutdown: 'Wyłącz',
+      shutdownConfirmTitle: 'Wyłączyć urządzenie?',
+      shutdownConfirmBody: 'Wyłączyć „{{hostname}}”? Aby je ponownie włączyć, potrzebny będzie fizyczny dostęp.',
+      commandConfirm: 'Potwierdź',
+      commandQueued: 'Polecenie dodane do kolejki',
+      commandError: 'Nie udało się wysłać polecenia',
+    },
+    // LDAP settings
+    ldap: {
+      title: 'Uwierzytelnianie LDAP',
+      enabledDesc: 'Uwierzytelnianie LDAP jest włączone',
+      disabledDesc: 'Uwierzytelnianie LDAP jest wyłączone',
+      disabledHint: 'Skonfiguruj i zapisz poniżej ustawienia LDAP, a następnie włącz.',
+      enabled: 'Włączono uwierzytelnianie LDAP',
+      disabled: 'Wyłączono uwierzytelnianie LDAP',
+      feature1: 'Użytkownicy mogą logować się danymi LDAP',
+      feature2: 'Lokalne konto administratora pozostaje jako rezerwowe',
+      feature3: 'Grupy LDAP są mapowane na grupy BamBuddy przy logowaniu',
+      serverConfig: 'Konfiguracja serwera LDAP',
+      serverUrl: 'URL serwera',
+      serverUrlHint: 'Użyj ldaps:// dla SSL lub ldap:// ze StartTLS',
+      security: 'Bezpieczeństwo',
+      securityHint: 'StartTLS przełącza zwykłe połączenie na TLS. LDAPS używa TLS od początku.',
+      bindDn: 'Bind DN (konto usługi)',
+      bindPassword: 'Hasło bind',
+      searchBase: 'Bazowy DN wyszukiwania',
+      userFilter: 'Filtr wyszukiwania użytkowników',
+      userFilterHint: '{username} jest zastępowane nazwą użytkownika podaną przy logowaniu. Dla OpenLDAP użyj (uid={username}).',
+      advanced: 'Zaawansowane',
+      autoProvision: 'Automatyczne tworzenie użytkowników',
+      autoProvisionHint: 'Automatycznie utwórz konto BamBuddy przy pierwszym logowaniu LDAP',
+      defaultGroup: 'Grupa domyślna',
+      defaultGroupNone: '— Brak (bez grupy rezerwowej) —',
+      defaultGroupHint: 'Grupa rezerwowa przypisywana, gdy użytkownik LDAP się uwierzytelni, ale nie należy do żadnej zmapowanej grupy LDAP. Pozostaw puste, aby niezmapowani użytkownicy nie mieli uprawnień.',
+      groupMapping: 'Mapowanie grup (JSON)',
+      groupMappingHint: 'Mapuj DN grup LDAP na grupy BamBuddy. Dostępne grupy: ',
+      testConnection: 'Testuj połączenie',
+      settingsSaved: 'Zapisano ustawienia LDAP',
+      errors: {
+        serverRequired: 'URL serwera LDAP jest wymagany',
+        searchBaseRequired: 'Bazowy DN wyszukiwania jest wymagany',
+        enableAuthFirst: 'Najpierw włącz uwierzytelnianie',
+        configureLdapFirst: 'Najpierw zapisz ustawienia LDAP',
+      },
+    },
+    // Email settings
+    email: {
+      smtpSettings: 'Konfiguracja SMTP',
+      smtpHost: 'Serwer SMTP',
+      smtpPort: 'Port SMTP',
+      security: 'Bezpieczeństwo',
+      authentication: 'Uwierzytelnianie',
+      username: 'Nazwa użytkownika',
+      password: 'Hasło',
+      fromEmail: 'E-mail nadawcy',
+      fromName: 'Nazwa nadawcy',
+      testConnection: 'Testuj połączenie SMTP',
+      testRecipient: 'E-mail odbiorcy testowego',
+      sendTest: 'Wyślij testowy e-mail',
+      sending: 'Wysyłanie...',
+      save: 'Zapisz ustawienia',
+      saving: 'Zapisywanie...',
+      advancedAuth: 'Zaawansowane uwierzytelnianie',
+      advancedAuthEnabled: 'Zaawansowane uwierzytelnianie jest włączone',
+      advancedAuthEnabledDesc: 'Funkcje zarządzania użytkownikami oparte na e-mailu są aktywne. Nowi użytkownicy otrzymają automatycznie wygenerowane hasła e-mailem, a użytkownicy mogą resetować hasła za pomocą funkcji „Nie pamiętam hasła”.',
+      advancedAuthDisabled: 'Zaawansowane uwierzytelnianie jest wyłączone',
+      advancedAuthDisabledDesc: 'Włącz zaawansowane uwierzytelnianie, aby aktywować funkcje zarządzania użytkownikami oparte na e-mailu.',
+      enable: 'Włącz',
+      disable: 'Wyłącz',
+      feature1: 'Hasła są generowane automatycznie i wysyłane e-mailem do nowych użytkowników',
+      feature2: 'Użytkownicy mogą logować się nazwą użytkownika lub adresem e-mail',
+      feature3: 'Dostępna jest funkcja „Nie pamiętam hasła”',
+      feature4: 'Administratorzy mogą resetować hasła użytkowników przez e-mail',
+      // Error messages
+      errors: {
+        requiredFields: 'Wypełnij wszystkie wymagane pola',
+        usernameRequired: 'Nazwa użytkownika jest wymagana, gdy uwierzytelnianie jest włączone',
+        enterTestEmail: 'Wprowadź testowy adres e-mail',
+        smtpServerAndEmail: 'Przed testem wypełnij pola Serwer SMTP i E-mail nadawcy',
+        usernamePasswordRequired: 'Nazwa użytkownika i hasło są wymagane, gdy uwierzytelnianie jest włączone',
+        configureSmtpFirst: 'Najpierw skonfiguruj i przetestuj ustawienia SMTP',
+        enableAuthFirst: 'Najpierw włącz uwierzytelnianie, aby korzystać z funkcji opartych na e-mailu.',
+      },
+      // Success messages
+      success: {
+        settingsSaved: 'Pomyślnie zapisano ustawienia SMTP',
+      },
+      // Security options
+      securityOptions: {
+        starttls: 'STARTTLS (port 587)',
+        ssl: 'SSL/TLS (port 465)',
+        none: 'Brak (port 25)',
+      },
+      // Authentication options
+      authOptions: {
+        enabled: 'Włączone',
+        disabled: 'Wyłączone',
+      },
+    },
+    appearance: 'Wygląd',
+    notifications: 'Powiadomienia',
+    smartPlugs: 'Inteligentne gniazdka',
+    spoolman: 'Spoolman',
+    updates: 'Aktualizacje',
+    language: 'Język',
+    languageDescription: 'Wybierz preferowany język',
+    theme: 'Motyw',
+    themeLight: 'Jasny',
+    themeDark: 'Ciemny',
+    themeSystem: 'Systemowy',
+    defaultView: 'Widok domyślny',
+    defaultViewDescription: 'Strona wyświetlana po otwarciu aplikacji',
+    checkForUpdates: 'Sprawdź aktualizacje',
+    autoUpdate: 'Automatyczna aktualizacja',
+    currentVersion: 'Bieżąca wersja',
+    latestVersion: 'Najnowsza wersja',
+    upToDate: 'Masz najnowszą wersję',
+    updateAvailable: 'Dostępna aktualizacja',
+    // Notifications
+    bedCooledThreshold: 'Próg ostygnięcia stołu',
+    bedCooledThresholdDescription: 'Temperatura, poniżej której stół uznaje się za ostygnięty po wydruku',
+    pauseWarningMinutes: 'Uprzedzenie o pauzie',
+    pauseWarningMinutesDescription: 'Ile minut przed pauzą dodaną w slicerze wysłać powiadomienie „Zbliża się pauza”',
+    userNotificationsEnabled: 'Powiadomienia użytkowników',
+    userNotificationsEnabledDescription: 'Włącz menu powiadomień użytkowników i powiadomienia e-mail o zdarzeniach zadań druku. Wymaga zaawansowanego uwierzytelniania.',
+    userNotificationsDisabledHint: 'Włącz zaawansowane uwierzytelnianie, aby korzystać z powiadomień użytkowników.',
+    notificationProviders: 'Dostawcy powiadomień',
+    addProvider: 'Dodaj dostawcę',
+    editProvider: 'Edytuj dostawcę',
+    providerType: 'Typ dostawcy',
+    testNotification: 'Powiadomienie testowe',
+    testSuccess: 'Pomyślnie wysłano powiadomienie testowe',
+    testFailed: 'Nie udało się wysłać powiadomienia testowego',
+    quietHours: 'Godziny ciszy',
+    quietHoursDescription: 'Nie przeszkadzaj w tych godzinach',
+    quietHoursStart: 'Początek',
+    quietHoursEnd: 'Koniec',
+    events: {
+      title: 'Zdarzenia powiadomień',
+      printStart: 'Rozpoczęto wydruk',
+      printComplete: 'Ukończono wydruk',
+      printFailed: 'Wydruk nieudany',
+      printStopped: 'Zatrzymano wydruk',
+      printProgress: 'Etapy postępu',
+      printProgressDescription: 'Powiadamiaj przy 25%, 50%, 75%',
+      printerOffline: 'Drukarka offline',
+      printerError: 'Błąd drukarki',
+      filamentLow: 'Mało filamentu',
+      maintenanceDue: 'Wymagana konserwacja',
+      maintenanceDueDescription: 'Powiadamiaj, gdy potrzebna jest konserwacja',
+    },
+    // Smart Plugs
+    smartPlug: {
+      title: 'Inteligentne gniazdka',
+      add: 'Dodaj inteligentne gniazdko',
+      edit: 'Edytuj inteligentne gniazdko',
+      name: 'Nazwa',
+      ipAddress: 'Adres IP',
+      linkedPrinter: 'Powiązana drukarka',
+      autoOn: 'Automatyczne włączanie',
+      autoOnDescription: 'Włącz, gdy rozpoczyna się wydruk',
+      autoOff: 'Automatyczne wyłączanie',
+      autoOffDescription: 'Wyłącz po ukończeniu wydruku',
+      offDelay: 'Opóźnienie wyłączenia',
+      offDelayMinutes: 'Minuty po wydruku',
+      offDelayTemp: 'Gdy dysza ostygnie poniżej temperatury',
+      currentState: 'Bieżący stan',
+      turnOn: 'Włącz',
+      turnOff: 'Wyłącz',
+    },
+    // Filament Tracking Mode
+    filamentTracking: 'Śledzenie filamentu',
+    filamentTrackingDesc: 'Wybierz sposób śledzenia szpul filamentu. Możesz użyć wbudowanego magazynu lub połączyć zewnętrzny serwer Spoolman.',
+    autoAddUnknownRfid: 'Automatycznie dodawaj nieznane szpule RFID',
+    autoAddUnknownRfidDesc: 'Automatycznie twórz wpis w magazynie po wykryciu szpuli z nieznanym tagiem RFID. Wyłącz, jeśli rejestrujesz nowe szpule ręcznie z wyprzedzeniem, aby uniknąć duplikatów.',
+    filamentChecks: 'Kontrole filamentu',
+    disableFilamentWarnings: 'Wyłącz ostrzeżenia o filamencie',
+    disableFilamentWarningsDesc: 'Nie pokazuj ostrzeżeń o niewystarczającej ilości filamentu podczas drukowania lub dodawania do kolejki',
+    preferLowestFilament: 'Preferuj najmniejszą pozostałą ilość filamentu',
+    preferLowestFilamentDesc: 'Gdy pasuje kilka szpul, użyj tej, na której zostało najmniej filamentu',
+    preferLowestFilamentBackupNote: 'Działa tylko wtedy, gdy na drukarce włączono AMS Filament Backup — w przeciwnym razie drukarka nie może przełączyć się na drugą szpulę, gdy wybrana się skończy.',
+    trackingModeBuiltIn: 'Wbudowany magazyn',
+    trackingModeBuiltInDesc: 'Zawiera automatyczne dopasowanie RFID i śledzenie zużycia',
+    trackingModeSpoolmanDesc: 'Zewnętrzny serwer zarządzania filamentem',
+    builtInFeatureRfid: 'Automatycznie wykrywa szpule RFID Bambu Lab w AMS',
+    builtInFeatureUsage: 'Śledzi zużycie filamentu na każdy wydruk',
+    builtInFeatureCatalog: 'Zarządzaj szpulami, kolorami i profilami współczynnika K',
+    builtInFeatureThirdParty: 'Szpule innych producentów można przypisać do szpul w magazynie',
+    amsSyncButton: 'Synchronizuj wagi z AMS',
+    amsSyncTitle: 'Synchronizuj wagi szpul z AMS',
+    amsSyncMessage: 'Spowoduje to nadpisanie wag wszystkich szpul w magazynie bieżącymi wartościami pozostałego % z AMS podłączonych drukarek. Użyj tego, aby odzyskać uszkodzone dane o wadze. Drukarki muszą być online.',
+    amsSyncing: 'Synchronizowanie...',
+    amsSyncSuccess: 'Zsynchronizowane szpule: {{synced}}, pominięte: {{skipped}}',
+    amsSyncError: 'Nie udało się zsynchronizować wag z AMS',
+    amsSyncSkippedPrinting: 'Pominięte szpule na drukarce, która drukuje: {{count}}. Zsynchronizuj ponownie po zakończeniu wydruku.',
+    spoolmanAmsSyncButton: 'Synchronizuj wagi Spoolman z AMS',
+    spoolmanAmsSyncTitle: 'Synchronizuj wagi szpul Spoolman z AMS',
+    spoolmanAmsSyncMessage: 'Spowoduje to aktualizację wag wszystkich szpul w Spoolman na podstawie bieżących wartości pozostałego % z AMS podłączonych drukarek. Drukarki muszą być online.',
+    spoolmanAmsSyncing: 'Synchronizowanie...',
+    spoolmanAmsSyncSuccess: 'Zsynchronizowane szpule: {{synced}}, pominięte: {{skipped}}',
+    spoolmanAmsSyncError: 'Nie udało się zsynchronizować wag Spoolman z AMS',
+    spoolmanAmsSyncErrorUnreachable: 'Nie udało się zsynchronizować wag Spoolman (Spoolman niedostępny)',
+    spoolmanAmsSyncErrorNotConfigured: 'Nie udało się zsynchronizować wag Spoolman (Spoolman nieskonfigurowany)',
+    nativeTagsTitle: 'Natywne tagi Spoolman',
+    nativeTagsDesc: 'Spoolman 0.27 sam powiązuje tagi NFC. Skopiuj tagi, które Bambuddy przechowuje w extra.tag, aby Spoolman i inne czytniki również znajdowały szpule. extra.tag pozostaje bez zmian.',
+    nativeTagsCheck: 'Sprawdź tagi',
+    nativeTagsToMove: 'Do skopiowania',
+    nativeTagsAlready: 'Już w Spoolman',
+    nativeTagsSlotIds: 'ID slotów AMS (pozostają w extra.tag)',
+    nativeTagsConflicts: 'Konflikty',
+    nativeTagsConflictSpool: 'Szpula #{{spool}}: tag {{tag}} należy już do szpuli #{{holder}}',
+    nativeTagsConflictElsewhere: 'Szpula #{{spool}}: tag {{tag}} należy już do filamentu lub lokalizacji',
+    nativeTagsMove: 'Kopiuj tagi',
+    nativeTagsMoved: 'Tagi skopiowane do Spoolman: {{count}}',
+    nativeTagsNothing: 'Wszystkie tagi są w Spoolman.',
+    nativeTagsError: 'Nie udało się skopiować tagów do Spoolman',
+    spoolmanNotConfigured: 'Spoolman nieskonfigurowany',
+    // Spoolman filament catalog section in spool catalog settings
+    spoolmanFilamentCatalogTitle: 'Katalog filamentów Spoolman',
+    spoolmanFilamentCatalogDesc: 'Nazwy filamentów i wagi tary z twojej instancji Spoolman. Nazwę i wagę szpuli można edytować tutaj; wszystkimi innymi właściwościami zarządza się bezpośrednio w Spoolman.',
+    // Spoolman settings
+    spoolmanUrl: 'URL Spoolman',
+    spoolmanUrlHint: 'URL twojego serwera Spoolman (np. http://localhost:7912)',
+    spoolmanConnected: 'Połączono',
+    spoolmanDisconnected: 'Rozłączono',
+    status: 'Status',
+    connect: 'Połącz',
+    disconnect: 'Rozłącz',
+    howSyncWorks: 'Jak działa synchronizacja',
+    syncInfoRfidOnly: 'Synchronizowane są tylko oryginalne szpule Bambu Lab z RFID',
+    syncInfoAutoCreate: 'Nowe szpule są automatycznie tworzone w Spoolman przy pierwszej synchronizacji',
+    syncInfoThirdPartySkipped: 'Szpule spoza Bambu Lab (innych producentów, ponownie nawinięte) są pomijane',
+    linkingExistingSpools: 'Łączenie istniejących szpul',
+    linkingExistingSpoolsDesc: 'Aby połączyć istniejące szpule Spoolman z AMS, najedź na slot AMS i kliknij „Połącz ze Spoolman”.',
+    syncMode: 'Tryb synchronizacji',
+    syncModeAuto: 'Automatyczny',
+    syncModeManual: 'Tylko ręczny',
+    syncModeAutoDesc: 'Dane AMS synchronizują się automatycznie po wykryciu zmian',
+    syncModeManualDesc: 'Synchronizuj tylko po ręcznym uruchomieniu',
+    syncAmsData: 'Synchronizuj dane AMS',
+    syncAmsDataDesc: 'Ręcznie synchronizuj dane AMS drukarek ze Spoolman',
+    allPrinters: 'Wszystkie drukarki',
+    // Default printer
+    noDefaultPrinter: 'Brak domyślnej (pytaj za każdym razem)',
+    // Sidebar
+    sidebarOrder: 'Kolejność paska bocznego',
+    // Camera
+    captureFinishPhoto: 'Zrób zdjęcie po ukończeniu',
+    noPrintersConfigured: 'Nie skonfigurowano drukarek',
+    // Updates
+    checkForUpdatesLabel: 'Sprawdzaj aktualizacje',
+    checkPrinterFirmware: 'Sprawdzaj firmware drukarek',
+    includeBetaUpdates: 'Uwzględniaj wersje beta',
+    includeBetaUpdatesDesc: 'Powiadamiaj o wersjach beta i przedpremierowych podczas sprawdzania aktualizacji',
+    announcementsEnabled: 'Otrzymuj ogłoszenia',
+    announcementsEnabledDesc: 'Wiadomości od opiekunów Bambuddy, np. o poprawkach bezpieczeństwa i zmianach niezgodnych wstecz. Bambuddy co kilka godzin pobiera podpisany plik z GitHub; żadne informacje o tej instalacji nie są wysyłane.',
+    announcementsLearnMore: 'Dowiedz się więcej',
+    announcementsAllUsers: 'Pokazuj wszystkim użytkownikom',
+    announcementsAllUsersDesc: 'Wyłączone: widzą je tylko administratorzy. Nie ma znaczenia, gdy uwierzytelnianie jest wyłączone.',
+    localLogin: {
+      disable: 'Wyłącz lokalne logowanie nazwą użytkownika i hasłem',
+      disableHint: 'Po włączeniu logować się można tylko przez dostawców SSO. Nie dotyczy LDAP. Ustaw BAMBUDDY_LOCAL_LOGIN=true na serwerze, aby zachować drogę odzyskania dostępu.',
+    },
+    // Queue
+    enableRetry: 'Włącz ponawianie',
+    // Home Assistant
+    homeAssistantDescription: 'Steruj inteligentnymi gniazdkami przez Home Assistant',
+    environmentManagedLabel: '(zarządzane przez środowisko)',
+    autoEnabledViaEnv: 'Włączone automatycznie przez zmienne środowiskowe',
+    urlFromEnvReadOnly: 'Wartość ustawiona przez zmienną środowiskową HA_URL (tylko do odczytu)',
+    tokenFromEnvReadOnly: 'Wartość ustawiona przez zmienną środowiskową HA_TOKEN (tylko do odczytu)',
+    // MQTT
+    mqttConnectedTo: 'Połączono z',
+    // Prometheus
+    prometheusDescription: 'Udostępniaj dane drukarek w formacie Prometheus',
+    // Smart plugs empty state
+    noSmartPlugsTitle: 'Nie skonfigurowano inteligentnych gniazdek',
+    noSmartPlugsDescription: 'Dodaj inteligentne gniazdko z Tasmota, aby śledzić zużycie energii i automatyzować sterowanie zasilaniem.',
+    // Notifications empty state
+    noProvidersTitle: 'Nie skonfigurowano dostawców',
+    noProvidersDescription: 'Dodaj dostawcę, aby otrzymywać alerty.',
+    noTemplatesAvailable: 'Brak dostępnych szablonów. Uruchom ponownie backend, aby utworzyć szablony domyślne.',
+    // API permissions
+    apiPermissionView: 'Wyświetlanie stanu drukarek i kolejki',
+    apiPermissionEdit: 'Dodawanie i usuwanie elementów z kolejki druku',
+    // API keys
+    apiKeysEmptyTitle: 'Brak kluczy API',
+    apiKeysEmptyDescription: 'Utwórz klucz API, aby zintegrować się z usługami zewnętrznymi.',
+    // Users
+    noUsersFound: 'Nie znaleziono użytkowników',
+    noGroupsFound: 'Nie znaleziono grup',
+    noGroupsAvailable: 'Brak dostępnych grup',
+    passwordsDoNotMatch: 'Hasła nie są zgodne',
+    systemGroupWarning: 'Nazw grup systemowych nie można zmieniać',
+    // Auth disabled
+    authDisabledTitle: 'Uwierzytelnianie jest wyłączone',
+    authDisabledFeature1: 'Wymagaj logowania, aby uzyskać dostęp do systemu',
+    authDisabledFeature2: 'Twórz wielu użytkowników z uprawnieniami opartymi na grupach',
+    authDisabledFeature3: 'Kontroluj dostęp za pomocą ponad 50 szczegółowych uprawnień',
+    // User deletion
+    userHasCreated: 'Ten użytkownik utworzył:',
+    userItemsQuestion: 'Co chcesz zrobić z tymi elementami?',
+    deleteUserConfirm: 'Czy na pewno chcesz usunąć tego użytkownika?',
+    actionCannotBeUndone: 'Tej operacji nie można cofnąć.',
+    // Smart plugs
+    addFirstSmartPlug: 'Dodaj pierwsze inteligentne gniazdko',
+    // Notifications
+    providers: 'Dostawcy',
+    log: 'Dziennik',
+    testAll: 'Testuj wszystkie',
+    testResults: 'Wyniki testu',
+    testPassedCount: 'Zaliczone: {{count}}',
+    testFailedCount: 'Nieudane: {{count}}',
+    messageTemplates: 'Szablony wiadomości',
+    messageTemplatesDescription: 'Dostosuj treść powiadomień dla każdego zdarzenia.',
+    // API Keys section
+    apiKeys: 'Klucze API',
+    apiKeysDescription: 'Twórz klucze API dla integracji zewnętrznych i webhooków.',
+    createKey: 'Utwórz klucz',
+    apiKeyCreated: 'Pomyślnie utworzono klucz API',
+    apiKeyCopyWarning: "Skopiuj ten klucz teraz — nie zostanie wyświetlony ponownie!",
+    useInApiBrowser: 'Użyj w przeglądarce API',
+    apiKeyQrButton: 'Kod QR',
+    apiKeyQrTitle: 'Zeskanuj, aby skonfigurować',
+    apiKeyQrCaption: 'Zeskanuj aplikacją mobilną, aby dodać ten serwer i klucz API.',
+    apiKeyQrWarning: "Zawiera twój tajny klucz API — nie udostępniaj go ani nie rób zrzutu ekranu tam, gdzie inni mogą go zobaczyć.",
+    createNewApiKey: 'Utwórz nowy klucz API',
+    keyName: 'Nazwa klucza',
+    keyNamePlaceholder: 'np. Home Assistant, OctoPrint',
+    readStatus: 'Odczyt stanu',
+    readStatusDescription: 'Wyświetlanie stanu drukarek, kolejki, biblioteki, archiwów i potoków slicera',
+    manageQueue: 'Zarządzanie kolejką',
+    manageQueueDescription: 'Dodawanie i usuwanie elementów z kolejki druku. Razem z Zarządzaniem biblioteką: uruchamianie potoków slicera',
+    controlPrinter: 'Sterowanie drukarką',
+    controlPrinterDescription: 'Wstrzymywanie, wznawianie i zatrzymywanie wydruków',
+    manageLibrary: 'Zarządzanie biblioteką',
+    manageLibraryDescription: 'Przesyłanie, zmiana nazw, usuwanie i slicowanie plików biblioteki; import modeli z MakerWorld. Razem z Zarządzaniem kolejką: uruchamianie potoków slicera',
+    manageInventory: 'Zarządzanie magazynem',
+    manageInventoryDescription: 'Tworzenie, aktualizowanie i usuwanie szpul oraz rekordów magazynu. Wymagane dla kiosków SpoolBuddy (skanowanie NFC, odczyty wagi, polecenia systemowe kiosku).',
+    manageMaintenance: 'Zarządzanie konserwacją',
+    manageMaintenanceDescription: 'Rejestrowanie wykonanej konserwacji, resetowanie liczników, edycja interwałów i zarządzanie katalogiem typów konserwacji. Odpowiednie dla automatyzacji Home Assistant, które zapisują „Wyczyściłem dyszę” bez przyznawania szerszej kontroli nad drukarką.',
+    manageArchives: 'Zarządzanie archiwami',
+    manageArchivesDescription: 'Edytowanie i usuwanie archiwów wydruków, w tym usuwanie starych wydruków i ich udziału w statystykach. Odpowiednie dla automatyzacji porządkujących historię wydruków.',
+    manageProjects: 'Zarządzanie projektami',
+    manageProjectsDescription: 'Tworzenie, aktualizowanie i usuwanie projektów oraz dodawanie do nich archiwów. Odpowiednie dla automatyzacji porządkujących wydruki w projekty.',
+    libraryBadge: 'Biblioteka',
+    inventoryBadge: 'Magazyn',
+    maintenanceBadge: 'Konserwacja',
+    archivesBadge: 'Archiwa',
+    projectsBadge: 'Projekty',
+    cloudAccess: 'Zezwól na dostęp do chmury',
+    cloudAccessDescription: 'Odczytuj w twoim imieniu profile i filamenty z Bambu Cloud. Wymaga zalogowania do Bambu Cloud.',
+    cloudBadge: 'Chmura',
+    updateEnergyCost: 'Aktualizuj cenę energii elektrycznej',
+    updateEnergyCostDescription: 'Pozwól temu kluczowi wysyłać (POST) nową cenę energii za kWh do /settings/electricity-price. Przydatne w automatyzacjach dynamicznych taryf w Home Assistant (Tibber, Octopus itp.). To jedyne pole ustawień, które można zapisać kluczem API.',
+    energyCostBadge: 'Energia',
+    sendNotifications: 'Wysyłaj powiadomienia',
+    sendNotificationsDescription: 'Pozwól temu kluczowi wysyłać wiadomości przez kanały powiadomień, które przyjmują wiadomości z połączonych aplikacji (POST /notifications/app-message), oraz wyświetlać licznik przy linku paska bocznego wskazującym na aplikację (PUT /external-links/badge). Dla aplikacji takich jak Bambuddy Orders. Nic więcej: klucz nie może odczytywać ani zmieniać kanałów ani linków.',
+    sendNotificationsBadge: 'Powiadomienia',
+    legacyKey: 'Starszy',
+    legacyKeyTooltip: 'Utworzony przed wprowadzeniem własności per użytkownik; utwórz ponownie, aby korzystać z dostępu do chmury',
+    unnamedKey: 'Klucz bez nazwy',
+    lastUsed: 'Ostatnio użyty',
+    read: 'Odczyt',
+    control: 'Sterowanie',
+    createFirstKey: 'Utwórz pierwszy klucz',
+    webhookEndpoints: 'Endpointy webhooków',
+    webhookApiKeyHint: 'Użyj klucza API w nagłówku X-API-Key.',
+    webhook: {
+      addToQueue: 'Dodaj do kolejki druku',
+      startNext: 'Uruchom następne zadanie z kolejki',
+      stopPrint: 'Zatrzymaj wydruk',
+      cancelPrint: 'Anuluj wydruk',
+      getSpecificStatus: 'Pobierz stan wybranej drukarki',
+      queueStatus: 'Pobierz stan kolejki',
+    },
+    apiBrowser: 'Przeglądarka API',
+    apiBrowserDescription: 'Przeglądaj i testuj wszystkie dostępne endpointy API.',
+    apiKeyForTesting: 'Klucz API do testów',
+    apiKeyPlaceholder: 'Wklej tutaj klucz API, aby testować endpointy wymagające uwierzytelnienia...',
+    apiKeyHint: 'Ten klucz będzie wysyłany w nagłówku X-API-Key wraz z żądaniami.',
+    deleteApiKeyTitle: 'Usuń klucz API',
+    deleteApiKeyMessage: 'Czy na pewno chcesz usunąć ten klucz API? Wszystkie integracje używające tego klucza przestaną działać.',
+    deleteKey: 'Usuń klucz',
+    // Filament tab
+    amsDisplayThresholds: 'Progi wyświetlania AMS',
+    amsThresholdsDescription: 'Skonfiguruj progi kolorów wskaźników wilgotności i temperatury AMS.',
+    humidity: 'Wilgotność',
+    goodGreen: 'Dobra (zielony)',
+    fairOrange: 'Średnia (pomarańczowy)',
+    aboveFairBad: 'Powyżej progu średniego wyświetla się na czerwono (zła)',
+    fairAlsoDryingThreshold: 'Ten próg służy też do uruchamiania automatycznego suszenia, gdy jest włączone',
+    fairBelowDryingFloor: 'Automatyczne suszenie nie osiągnie tej wartości: AMS odczytuje {{floor}}% lub więcej, gdy grzałka pracuje, więc każdy cykl kończyłby się i natychmiast zaczynał od nowa. Podnieś ją powyżej {{floor}}%, jeśli automatyczne suszenie jest włączone.',
+    temperature: 'Temperatura',
+    goodBlue: 'Dobra (niebieski)',
+    aboveFairHot: 'Powyżej progu średniego wyświetla się na czerwono (gorąco)',
+    tempAlarmThreshold: 'Alarm powyżej',
+    tempAlarmSeparateFromBand: 'Powiadomienia wysyła tylko próg alarmu — progi Dobra i Średnia barwią tylko wyświetlanie. Pozostaw puste, aby alarm włączał się przy progu średnim, jak dotychczas.',
+    tempAlarmMustBePositive: 'Próg 0 lub mniejszy jest ignorowany — alarm wraca do progu średniego.',
+    historyRetention: 'Przechowywanie historii',
+    keepSensorHistory: 'Przechowuj historię czujników przez',
+    keepPrinterTemperatureHistory: 'Przechowuj historię temperatur drukarki (dysza, stół, komora) przez',
+    historyRetentionDescription: 'Starsze dane o wilgotności i temperaturze będą automatycznie usuwane',
+    defaultPrintOptions: 'Domyślne opcje druku',
+    defaultPrintOptionsDescription: 'Ustaw domyślne wartości opcji druku przy uruchamianiu nowych wydruków. Można je zmienić dla każdego wydruku w oknie druku.',
+    defaultBedLevelling: 'Poziomowanie stołu',
+    defaultBedLevellingDesc: 'Automatycznie poziomuj stół przed wydrukiem',
+    defaultFlowCali: 'Kalibracja przepływu',
+    defaultFlowCaliDesc: 'Kalibruj przepływ ekstruzji',
+    defaultVibrationCali: 'Kalibracja drgań',
+    defaultVibrationCaliDesc: 'Ogranicz artefakty ringingu',
+    defaultLayerInspect: 'Inspekcja pierwszej warstwy',
+    defaultLayerInspectDesc: 'Inspekcja pierwszej warstwy przez AI',
+    defaultTimelapse: 'Timelapse',
+    defaultTimelapseDesc: 'Nagrywaj film timelapse',
+    defaultConfirmOutcome: 'Pytaj o wynik',
+    defaultConfirmOutcomeDesc: 'Po ukończeniu pytaj, czy wydruk się udał',
+    confirmOutcomeExternalPrints: 'Pytaj także o wydruki uruchomione poza Bambuddy',
+    confirmOutcomeExternalPrintsDesc: 'Wydruki uruchomione na drukarce, w Bambu Studio lub w aplikacji Handy również są archiwizowane przez Bambuddy. Po włączeniu otrzymują to samo pytanie o wynik co wydruki z kolejki.',
+    confirmDefaultGoodOnPlateClear: 'Traktuj nieudzielone odpowiedzi o wyniku jako dobre po zwolnieniu płyty',
+    confirmDefaultGoodOnPlateClearDescription: 'Gdy płyta zostanie zwolniona (ręcznie lub przez następny wydruk z kolejki), a pytanie o wynik wydruku nadal nie ma odpowiedzi, automatycznie zapisz go jako dobrą część. Wydruk liczy się wtedy jako dobry od razu po zwolnieniu płyty; późniejsza odpowiedź przez Telegram lub link pokazuje już tylko zapisany wynik.',
+    defaultNozzleOffsetCali: 'Kalibracja przesunięcia dysz',
+    defaultNozzleOffsetCaliDesc: 'Kalibruj przesunięcia dysz między ekstruderami',
+    tempFanPresetsTitle: 'Wartości temperatury i wentylatora',
+    tempFanPresetsDescription: 'Dostosuj wartości szybkiego wyboru w okienkach temperatury i prędkości wentylatora na karcie drukarki. Przycisk Wyłącz jest zawsze widoczny.',
+    tempFanPresetsNozzle: 'Temperatura dyszy',
+    tempFanPresetsBed: 'Temperatura stołu',
+    tempFanPresetsChamber: 'Temperatura komory',
+    tempFanPresetsFan: 'Prędkość wentylatora',
+    tempFanPresetsReset: 'Przywróć domyślne',
+    concurrentUploadsTitle: 'Równoczesne przesyłanie',
+    concurrentUploadsDescription: 'Do ilu drukarek kolejka może jednocześnie wysyłać pliki. Drukarki odbierają pliki powoli (duży wydruk może trwać kilka minut), a każda czeka na swoją kolej — dlatego przy większej flocie zwiększenie tej wartości sprawia, że ostatnia drukarka w partii nie czeka na zakończenie wszystkich wcześniejszych transferów. Zmniejsz ją, jeśli sieć lub host Bambuddy nie radzi sobie z równoległymi transferami.',
+    concurrentUploadsLabel: 'Liczba drukarek jednocześnie',
+    concurrentUploadsHelp: '1 wysyła do jednej drukarki naraz (dawne zachowanie). Domyślnie 4.',
+    staggeredStart: 'Start rozłożony w czasie',
+    staggeredStartDescription: 'Domyślna wielkość grupy i odstęp przy rozkładaniu w czasie startu partii na wielu drukarkach. Można je zmienić dla każdej partii w oknie druku.',
+    preheatTitle: 'Podgrzewanie i wygrzewanie',
+    preheatDescription: 'Podgrzej stół (i komorę, jeśli jest obsługiwana) i utrzymaj temperaturę przed startem każdego wydruku z kolejki. Pomocne przy filamentach technicznych (PA, ABS) na drukarkach bez aktywnego grzania komory — stół ogrzewa komorę przez promieniowanie, gdy odlicza się czas wygrzewania. Temperatura docelowa stołu jest odczytywana z pliku wydruku; zachowanie komory zależy od modelu drukarki.',
+    preheatEnabled: 'Włącz podgrzewanie i wygrzewanie',
+    preheatEnabledDesc: 'Po wyłączeniu wydruki z kolejki są wysyłane natychmiast. Każdy element kolejki może to zmienić dla danego wydruku.',
+    preheatFilamentTargetsLabel: 'Docelowa temperatura komory dla filamentu (°C)',
+    preheatFilamentTargetsHint: 'Bambuddy wybiera najwyższą wartość docelową spośród załadowanych slotów AMS. Wydruk, którego wszystkie sloty dają 0 — PLA, PETG, TPU, PVA — całkowicie pomija podgrzewanie i startuje natychmiast.',
+    preheatFilamentTargetsReset: 'Przywróć domyślne',
+    preheatFilamentTargetsDefaultRow: 'Inne / niezmapowane',
+    preheatMaxWait: 'Maks. czas oczekiwania (sekundy)',
+    preheatMaxWaitHelp: 'Limit fazy nagrzewania komory, po którym następuje przejście dalej.',
+    preheatSoak: 'Wygrzewanie (sekundy)',
+    preheatSoakHelp: 'Czas utrzymania po osiągnięciu temperatury docelowej lub upływie maks. czasu oczekiwania.',
+    preheatHardwareTitle: 'Zachowanie wg drukarki:',
+    preheatHardwareDetail: 'H2C/H2D/H2D Pro/H2S/X2D/X1E aktywnie grzeją komorę przez M141. X1C/P2S odczytują temperaturę komory, ale polegają na ogrzewaniu promieniowaniem stołu. P1S/P1P/A1/A1 Mini nie mają czujnika komory — działa tylko czas wygrzewania.',
+    preheatPerItemDesc: 'Podgrzej stół i komorę przed startem tego wydruku. Domyślnie zgodnie z globalnym przełącznikiem Ustawienia → Przepływ pracy.',
+    preheatOverride_inherit: 'Dziedzicz',
+    preheatOverride_on: 'Wł.',
+    preheatOverride_off: 'Wył.',
+    calibrationMode_off: 'Wył.',
+    calibrationMode_on: 'Wł.',
+    calibrationMode_auto: 'Auto',
+    preheatTargetOverride: 'Nadpisanie temperatury docelowej komory (°C, puste = domyślna dla filamentu)',
+    preheatTargetOverrideHelp: '0 podgrzewa stół i wykonuje wygrzewanie bez komory. Pozostaw puste, a wydruk bez wymagań co do komory całkowicie pominie podgrzewanie.',
+    plateClear: 'Potwierdzenie opróżnienia płyty',
+    requirePlateClear: 'Wymagaj potwierdzenia opróżnienia płyty',
+    requirePlateClearDescription: 'Po włączeniu harmonogram czeka na potwierdzenie opróżnienia płyty dla danej drukarki, zanim uruchomi wydruki z kolejki na drukarkach z ukończonymi zadaniami. Wyłączenie ukrywa też plakietkę stanu płyty i przycisk „Oznacz płytę jako opróżnioną” na kartach drukarek.',
+    keepBedWarm: 'Utrzymuj ciepły stół między wydrukami',
+    keepBedWarmDesc: 'Podczas oczekiwania na opróżnienie płyty utrzymuj stół w podanej poniżej temperaturze podtrzymania, aby komora pozostała gorąca — lub w temperaturze stołu następnego wydruku, jeśli jest wyższa. Dotyczy tylko sytuacji, gdy następny wydruk wymaga ogrzewania komory (ASA, ABS, PA, PC itp.). Wymaga włączonego potwierdzenia opróżnienia płyty.',
+    keepWarmBedTemp: 'Temperatura podtrzymania stołu (°C)',
+    keepWarmBedTempHelp: 'Używana zawsze, gdy zadaniem stołu jest ogrzewanie komory — przy podtrzymaniu ciepła oraz przy podgrzewaniu, gdy plik wydruku nie zawiera temperatury stołu. Wyższa temperatura stołu z pliku wydruku zawsze ma pierwszeństwo.',
+    keepWarmMaxMinutes: 'Przestań podtrzymywać ciepło po (minuty)',
+    keepWarmMaxMinutesHelp: 'Jeśli płyta nie zostanie opróżniona w tym czasie, grzałki zostaną wyłączone zamiast pracować bez końca.',
+    gcodeInjection: 'Wstrzykiwanie G-code',
+    gcodeInjectionDescription: 'Skonfiguruj własny G-code wstrzykiwany na początku i/lub końcu wydruków dla systemów automatycznego drukowania, takich jak Farmloop, SwapMod, AutoClear i Printflow 3D. Fragmenty konfiguruje się dla modelu drukarki i są stosowane, gdy w elemencie kolejki włączono „Wstrzyknij G-code”.',
+    gcodeInjectionNoPrinters: 'Nie znaleziono drukarek. Dodaj drukarki, aby skonfigurować fragmenty G-code.',
+    gcodeStartLabel: 'G-code początkowy',
+    gcodeEndLabel: 'G-code końcowy',
+    gcodeStartPlaceholder: 'G-code dodawany przed startem wydruku...',
+    gcodeEndPlaceholder: 'G-code dodawany po zakończeniu wydruku...',
+    staggerGroupSize: 'Wielkość grupy',
+    staggerGroupSizeHelp: 'Liczba drukarek uruchamianych jednocześnie w grupie',
+    staggerInterval: 'Odstęp (minuty)',
+    staggerIntervalHelp: 'Opóźnienie między startem kolejnych grup',
+    queueDrying: 'Automatyczne suszenie w kolejce',
+    queueDryingDescription: 'Automatycznie susz filament w AMS, gdy drukarka jest bezczynna między wydrukami z kolejki. Do uruchamiania suszenia używa powyższego progu wilgotności.',
+    queueDryingEnabled: 'Włącz automatyczne suszenie',
+    queueDryingEnabledDescription: 'Automatycznie uruchamiaj suszenie AMS, gdy drukarka jest bezczynna, a wilgotność przekracza próg',
+    queueDryingBlock: 'Czekaj na zakończenie suszenia',
+    queueDryingBlockDescription: 'Blokuj kolejkę druku do zakończenia suszenia. Po wyłączeniu wydruki mają pierwszeństwo przed suszeniem.',
+    ambientDryingEnabled: 'Suszenie otoczenia',
+    ambientDryingEnabledDescription: 'Automatycznie susz filament na bezczynnych drukarkach, gdy wilgotność przekracza próg, nawet bez wydruków w kolejce.',
+    ambientDryingSustainedEnabled: 'Wymagaj utrzymującej się wilgotności',
+    ambientDryingSustainedDescription: 'Przed rozpoczęciem suszenia otoczenia czekaj, aż wilgotność utrzyma się powyżej progu przez określony czas — pozwala przeczekać skok po otwarciu pokrywy AMS.',
+    ambientDryingSustainedMinutes: 'Czas utrzymania (minuty)',
+    printDryingEnabled: 'Kontynuuj suszenie podczas drukowania',
+    printDryingEnabledDescription: 'Pozwól, aby automatyczne suszenie działało podczas wydruku na obsługiwanym sprzęcie (H2D, H2C, H2S, P2S, H2D Pro, X2D, X1C, A2L z aktualnym firmware). Temperatura suszenia jest automatycznie ograniczana do 5°C poniżej ustawienia dla bezczynności, aby chronić szpule.',
+    dryingPresets: 'Ustawienia suszenia',
+    dryingPresetsDescription: 'Temperatura i czas dla każdego rodzaju filamentu. AMS 2 Pro używa niższych temperatur, AMS-HT obsługuje wyższe.',
+    dryingFilament: 'Filament',
+    humidityThresholds: 'Progi wilgotności',
+    humidityThresholdsDescription: 'Próg wilgotności dla każdego filamentu, uruchamiający automatyczne suszenie i alarmy. Przy mieszanym załadunku jednego AMS używany jest najniższy próg.',
+    humidityThresholdCol: 'Próg',
+    humidityThresholdDefault: 'Domyślny (nieznane rodzaje)',
+    printModal: 'Okno druku',
+    expandCustomMapping: 'Domyślnie rozwijaj własne mapowanie',
+    expandCustomMappingDescription: 'Przy drukowaniu na wielu drukarkach pokazuj rozwinięte mapowanie AMS dla każdej drukarki',
+    // User management
+    authentication: 'Uwierzytelnianie',
+    authEnabledDescription: 'Twoja instancja jest zabezpieczona uwierzytelnianiem użytkowników',
+    authDisabledDescription: 'Włącz, aby wymagać logowania i zarządzać dostępem użytkowników',
+    authDisabledMessage: 'Włącz uwierzytelnianie, aby tworzyć konta użytkowników, zarządzać uprawnieniami i zabezpieczyć swoją instancję Bambuddy.',
+    enableAuthentication: 'Włącz uwierzytelnianie',
+    currentUser: 'Bieżący użytkownik',
+    changePassword: 'Zmień hasło',
+    admin: 'Administrator',
+    users: 'Użytkownicy',
+    addUser: 'Dodaj użytkownika',
+    groups: 'Grupy',
+    addGroup: 'Dodaj grupę',
+    system: 'System',
+    noDescription: 'Brak opisu',
+    userCount: 'Użytkownicy: {{count}}',
+    permissionCount: 'Uprawnienia: {{count}}',
+    createUser: 'Utwórz użytkownika',
+    username: 'Nazwa użytkownika',
+    enterUsername: 'Wprowadź nazwę użytkownika',
+    password: 'Hasło',
+    enterPassword: 'Wprowadź hasło',
+    passwordRequirements: 'Co najmniej 8 znaków, w tym jedna wielka litera, jedna mała litera, jedna cyfra i jeden znak specjalny.',
+    confirmPassword: 'Potwierdź hasło',
+    confirmPasswordPlaceholder: 'Potwierdź hasło',
+    // Title tooltips
+    viewReleaseOnGitHub: 'Zobacz wydanie na GitHub',
+    turnAllPlugsOn: 'Włącz wszystkie gniazdka',
+    turnAllPlugsOff: 'Wyłącz wszystkie gniazdka',
+    // Modal: Clear logs
+    clearNotificationLogs: 'Wyczyść dziennik powiadomień',
+    clearLogsMessage: 'Spowoduje to trwałe usunięcie wszystkich wpisów dziennika powiadomień starszych niż 30 dni. Tej operacji nie można cofnąć.',
+    clearLogs: 'Wyczyść dziennik',
+    // Modal: Reset UI
+    resetUiPreferences: 'Resetuj preferencje interfejsu',
+    resetUiPreferencesMessage: 'Spowoduje to przywrócenie domyślnych wartości wszystkich preferencji interfejsu: kolejności paska bocznego, motywu, układu pulpitu, trybów widoku i preferencji sortowania. Twoje drukarki, archiwa i ustawienia serwera NIE zostaną zmienione. Po wyczyszczeniu strona zostanie przeładowana.',
+    resetPreferences: 'Resetuj preferencje',
+    // Modal: Delete group
+    deleteGroupTitle: 'Usuń grupę',
+    deleteGroupMessage: 'Czy na pewno chcesz usunąć tę grupę? Użytkownicy tej grupy stracą te uprawnienia.',
+    deleteGroup: 'Usuń grupę',
+    // Modal: Disable auth
+    disableAuthenticationTitle: 'Wyłącz uwierzytelnianie',
+    disableAuthenticationMessage: 'Czy na pewno chcesz wyłączyć uwierzytelnianie? Twoja instancja Bambuddy będzie dostępna bez logowania. Wszyscy użytkownicy pozostaną w bazie danych, ale uwierzytelnianie zostanie wyłączone.',
+    disableAuthentication: 'Wyłącz uwierzytelnianie',
+    // Additional settings
+    configureBambuddy: 'Konfiguruj Bambuddy',
+    systemDefault: 'Domyślne systemowe',
+    archiveSettings: 'Ustawienia archiwum',
+    newWindow: 'Nowe okno',
+    embeddedOverlay: 'Wbudowana nakładka',
+    preferredSlicer: 'Preferowany slicer',
+    preferredSlicerDescription: 'Slicer używany do slicowania w aplikacji przez sidecar API',
+    openInSlicerLabel: 'Otwórz w slicerze',
+    openInSlicerInherit: 'Taki sam jak slicer API',
+    openInSlicerDescription: "Slicer desktopowy używany przez przycisk „Otwórz w slicerze”. Pozostaw „Taki sam jak slicer API”, aby dziedziczyć, lub wybierz inny slicer do użytku lokalnego.",
+    orcaslicerKnownIssuesWarning: 'OrcaSlicer 2.3.2 / 2.4.0-dev mają znane błędy CLI, które blokują slicowanie wielu plików 3MF utworzonych przez Bambu — zobacz zgłoszenia upstream #12426 (segfault na malowanych plikach z wieloma ekstruderami) i #13386 (odrzucenie przez ścisłą walidację zakresu parametrów). Do czasu wprowadzenia poprawek upstream zalecane jest Bambu Studio.',
+    useSlicerApi: 'Używaj API slicera',
+    useSlicerApiDescription: 'Po włączeniu akcje „Slicuj” otwierają okno slicera w aplikacji i wywołują sidecar API slicera. Po wyłączeniu (domyślnie) przekazują plik do slicera desktopowego przez schemat URI.',
+    slicerCard: 'Slicer',
+    orcaslicerApiUrl: 'URL sidecara OrcaSlicer',
+    bambuStudioApiUrl: 'URL sidecara Bambu Studio',
+    slicerStallTimeout: 'Limit czasu zawieszenia slicera (minuty)',
+    slicerStallTimeoutDescription: 'Przerwij slicowanie po tym czasie bez postępu ze strony sidecara. Ciężkie modele, które stale raportują postęp, nigdy nie są przerywane, niezależnie od czasu trwania. Dla sidecarów, które nie raportują postępu, jest to całkowity limit czasu.',
+    slicerApiUrlDescription: 'URL kontenera sidecar API slicera. Pozostaw puste, aby użyć domyślnych wartości ze zmiennych środowiskowych SLICER_API_URL / BAMBU_STUDIO_API_URL.',
+    externalCameras: 'Kamery zewnętrzne',
+    costTracking: 'Śledzenie kosztów',
+    billingEnabled: 'Włącz rozliczenia',
+    billingEnabledDescription: 'Obciążaj użytkowników za wydruki i włącz funkcje finansowe',
+    printerKillSwitch: 'Wyłącznik nieautoryzowanych wydruków',
+    printerKillSwitchDescription: 'Natychmiast zatrzymuj wydruki uruchomione bez autoryzacji.',
+    financeBudgetReset: 'Miesięczny reset budżetu',
+    financeBudgetResetDay: 'Dzień resetu',
+    financeBudgetResetDayHelp: 'W krótszych miesiącach reset następuje ostatniego dnia miesiąca.',
+    financeBudgetResetTimezone: 'Strefa czasowa resetu',
+    financeBudgetResetTimezoneHelp: 'Początek okresu budżetu jest liczony w tej strefie czasowej.',
+    rebuildLedger: 'Odbuduj księgę portfela',
+    rebuildLedgerStarted: 'Rozpoczęto odbudowę księgi',
+    rebuildLedgerConfirmTitle: 'Odbudować księgę portfela?',
+    rebuildLedgerConfirmMessage:
+      'Spowoduje to odbudowanie księgi portfela w celu naprawy historycznych wartości sald. Uruchamiaj to tylko, jeśli wiesz, co robisz.',
+    rebuildLedgerInProgress: 'Rozpoczynanie odbudowy...',
+    printsOnly: 'Tylko wydruki',
+    totalConsumption: 'Całkowite zużycie',
+    dataManagement: 'Zarządzanie danymi',
+    storageUsage: 'Zajęte miejsce',
+    storageUsageDescription: 'Podział zajętego miejsca według kategorii',
+    storageUsageTotal: 'Łącznie',
+    storageUsageErrors: 'Błędy',
+    storageUsageOtherBreakdown: 'Inne (w tym zasoby statyczne, skrypty i pliki konfiguracyjne)',
+    storageUsageSystem: 'System',
+    storageUsageData: 'Dane',
+    storageUsageUnavailable: 'Informacje o zajętym miejscu są niedostępne',
+    clearNotificationLogsDescription: 'Usuń wpisy dziennika powiadomień starsze niż 30 dni',
+    resetUiPreferencesDescription: 'Resetuj kolejność paska bocznego, motyw, tryby widoku i preferencje układu. Drukarki, archiwa i ustawienia nie zostaną zmienione.',
+    enableHomeAssistant: 'Włącz Home Assistant',
+    enableMqtt: 'Włącz MQTT',
+    useTls: 'Używaj TLS',
+    enableMetricsEndpoint: 'Włącz endpoint metryk',
+    availableMetrics: 'Dostępne metryki',
+    editUser: 'Edytuj użytkownika',
+    deleteUserTitle: 'Usuń użytkownika',
+    groupName: 'Nazwa grupy',
+    // Placeholders
+    leaveEmptyForAnonymous: 'Pozostaw puste dla dostępu anonimowego',
+    leaveEmptyForNoAuth: 'Pozostaw puste, aby nie używać uwierzytelniania',
+    enterNewPassword: 'Wprowadź nowe hasło',
+    confirmNewPassword: 'Potwierdź nowe hasło',
+    enterGroupName: 'Wprowadź nazwę grupy',
+    enterDescriptionOptional: 'Wprowadź opis (opcjonalnie)',
+    enterCurrentPassword: 'Wprowadź bieżące hasło',
+    enterNewPasswordMin6: 'Wprowadź nowe hasło (min. 6 znaków)',
+    toast: {
+      keyCopied: 'Skopiowano klucz do schowka',
+      copyFailed: 'Nie udało się skopiować klucza',
+      keyAddedToBrowser: 'Dodano klucz do przeglądarki API',
+      clearLogsFailed: 'Nie udało się wyczyścić dziennika',
+      uiPreferencesReset: 'Zresetowano preferencje interfejsu. Odświeżanie...',
+      authDisabled: 'Pomyślnie wyłączono uwierzytelnianie',
+      authDisableFailed: 'Nie udało się wyłączyć uwierzytelniania',
+      apiKeyCreated: 'Utworzono klucz API',
+      apiKeyDeleted: 'Usunięto klucz API',
+      userCreated: 'Pomyślnie utworzono użytkownika',
+      userUpdated: 'Pomyślnie zaktualizowano użytkownika',
+      userDeleted: 'Pomyślnie usunięto użytkownika',
+      groupCreated: 'Pomyślnie utworzono grupę',
+      groupUpdated: 'Pomyślnie zaktualizowano grupę',
+      groupDeleted: 'Pomyślnie usunięto grupę',
+      fillRequiredFields: 'Wypełnij wszystkie wymagane pola',
+      passwordsDoNotMatch: 'Hasła nie są zgodne',
+      passwordTooShort: 'Hasło musi mieć co najmniej 8 znaków',
+      passwordNeedsUppercase: 'Hasło musi zawierać co najmniej jedną wielką literę',
+      passwordNeedsLowercase: 'Hasło musi zawierać co najmniej jedną małą literę',
+      passwordNeedsDigit: 'Hasło musi zawierać co najmniej jedną cyfrę',
+      passwordNeedsSpecial: 'Hasło musi zawierać co najmniej jeden znak specjalny',
+      enterGroupName: 'Wprowadź nazwę grupy',
+      settingsSaved: 'Zapisano ustawienia',
+      noPermissionUpdate: 'Nie masz uprawnień do zmiany ustawień',
+      settingsSaveFailed: 'Nie zapisano ustawień: {{message}}',
+      cameraSettingsSaved: 'Zapisano ustawienia kamery',
+      enterCameraUrl: 'Wprowadź URL kamery',
+      passwordChanged: 'Pomyślnie zmieniono hasło',
+      connectionFailed: 'Połączenie nie powiodło się',
+      testFailed: 'Test nie powiódł się',
+      cameraConnected: 'Połączono z kamerą{{resolution}}',
+      cameraConnectedCoalesced: 'Połączono z kamerą{{resolution}} (współdzielone z już trwającym przechwytywaniem)',
+      cameraConnectedLiveView: 'Kamera działa{{resolution}} (klatka z podglądu na żywo, który korzysta z kamery)',
+    },
+    testConnection: 'Testuj połączenie',
+    catalog: {
+      spoolCatalog: 'Katalog szpul',
+      spoolCatalogDescription: 'Wagi pustych szpul według producenta/rodzaju. Używane do automatycznego wyszukiwania wagi przy dodawaniu szpul.',
+      searchCatalog: 'Szukaj w katalogu...',
+      addNewEntry: 'Dodaj nowy wpis',
+      namePlaceholder: 'Nazwa (np. Bambu Lab - plastikowa)',
+      weight: 'Waga',
+      type: 'Rodzaj',
+      default: 'Domyślny',
+      custom: 'Własny',
+      noMatch: 'Żaden wpis nie pasuje do wyszukiwania',
+      empty: 'Brak wpisów w katalogu',
+      deleteEntry: 'Usuń wpis',
+      deleteConfirm: 'Czy na pewno chcesz usunąć „{{name}}”?',
+      resetCatalog: 'Resetuj katalog',
+      resetConfirm: 'Przywrócić domyślny katalog? Spowoduje to usunięcie wszystkich własnych wpisów.',
+      loadFailed: 'Nie udało się wczytać katalogu szpul',
+      nameWeightRequired: 'Nazwa i waga są wymagane',
+      entryAdded: 'Dodano wpis',
+      addFailed: 'Nie udało się dodać wpisu',
+      entryUpdated: 'Zaktualizowano wpis',
+      updateFailed: 'Nie udało się zaktualizować wpisu',
+      entryDeleted: 'Usunięto wpis',
+      deleteFailed: 'Nie udało się usunąć wpisu',
+      resetSuccess: 'Przywrócono domyślny katalog',
+      resetFailed: 'Nie udało się zresetować katalogu',
+      exported: 'Wyeksportowane wpisy: {{count}}',
+      imported: 'Zaimportowane wpisy: {{added}} (pominięte: {{skipped}})',
+      importFailed: 'Import nie powiódł się: nieprawidłowy format JSON',
+      exportTooltip: 'Eksportuj katalog do JSON',
+      importTooltip: 'Importuj katalog z JSON',
+      resetTooltip: 'Przywróć domyślne',
+      selectedCount: 'Zaznaczone: {{count}}',
+      deleteSelected: 'Usuń zaznaczone',
+      bulkDeleteConfirm: 'Czy na pewno chcesz usunąć wpisy (liczba: {{count}})?',
+      bulkDeleted: 'Usunięte wpisy: {{count}}',
+      bulkDeleteFailed: 'Nie udało się usunąć wpisów',
+      material: 'Materiał',
+      spoolWeight: 'Waga szpuli',
+      color: 'Kolor',
+      updateSpoolWeight: 'Aktualizuj wagę szpuli',
+      filamentUpdated: 'Zaktualizowano filament',
+      filamentUpdateFailed: 'Nie udało się zaktualizować filamentu',
+      filamentUpdateInvalid: 'Nieprawidłowe dane filamentu',
+      keepExistingSpoolWeight: 'Zachowaj starą wagę dla istniejących szpul',
+      keepExistingSpoolWeightDesc: 'Szpule już utworzone z tym rodzajem filamentu zachowują starą wagę tary. Nowe szpule używają zaktualizowanej wartości.',
+      applyToAllSpools: 'Zastosuj do wszystkich szpul',
+      applyToAllSpoolsDesc: 'Wszystkie obliczenia wagi dla tego rodzaju filamentu od razu używają nowej wagi tary.',
+    },
+    colorCatalog: {
+      title: 'Katalog kolorów',
+      description: 'Kolory filamentów według producenta/materiału. Używane do automatycznego wyszukiwania koloru przy dodawaniu szpul.',
+      searchColors: 'Szukaj kolorów...',
+      allManufacturers: 'Wszyscy producenci',
+      addNewColor: 'Dodaj nowy kolor',
+      manufacturer: 'Producent',
+      colorName: 'Nazwa koloru',
+      hex: 'Hex',
+      materialOptional: 'Materiał (opcjonalnie)',
+      showing: 'Wyświetlane kolory: {{filtered}} z {{total}}',
+      noMatch: 'Żaden kolor nie pasuje do wyszukiwania',
+      empty: 'Brak kolorów w katalogu',
+      deleteColor: 'Usuń kolor',
+      deleteConfirm: 'Czy na pewno chcesz usunąć „{{name}}”?',
+      resetCatalog: 'Resetuj katalog kolorów',
+      resetConfirm: 'Przywrócić domyślny katalog? Spowoduje to usunięcie wszystkich własnych kolorów.',
+      sync: 'Synchronizuj',
+      starting: 'Uruchamianie...',
+      syncTooltip: 'Synchronizuj z FilamentColors.xyz (ponad 2000 kolorów, może potrwać minutę)',
+      loadFailed: 'Nie udało się wczytać katalogu kolorów',
+      fieldsRequired: 'Producent, nazwa koloru i kolor hex są wymagane',
+      colorAdded: 'Dodano kolor',
+      addFailed: 'Nie udało się dodać koloru',
+      colorUpdated: 'Zaktualizowano kolor',
+      updateFailed: 'Nie udało się zaktualizować koloru',
+      colorDeleted: 'Usunięto kolor',
+      deleteFailed: 'Nie udało się usunąć koloru',
+      resetSuccess: 'Przywrócono domyślny katalog kolorów',
+      resetFailed: 'Nie udało się zresetować katalogu',
+      syncUpToDate: 'Już aktualny (sprawdzone kolory: {{count}})',
+      syncComplete: 'Dodane nowe kolory: {{added}} (już istniejące: {{skipped}})',
+      syncError: 'Błąd synchronizacji',
+      syncFailed: 'Nie udało się zsynchronizować z FilamentColors.xyz',
+      exported: 'Wyeksportowane kolory: {{count}}',
+      imported: 'Zaimportowane kolory: {{added}} (pominięte: {{skipped}})',
+      importFailed: 'Import nie powiódł się: nieprawidłowy format JSON',
+      selectedCount: 'Zaznaczone: {{count}}',
+      deleteSelected: 'Usuń zaznaczone',
+      bulkDeleteConfirm: 'Czy na pewno chcesz usunąć kolory (liczba: {{count}})?',
+      bulkDeleted: 'Usunięte kolory: {{count}}',
+      bulkDeleteFailed: 'Nie udało się usunąć kolorów',
+    },
+    // General tab
+    dateFormat: 'Format daty',
+    dateFormatUs: 'USA (MM/DD/YYYY)',
+    dateFormatEu: 'UE (DD/MM/YYYY)',
+    dateFormatIso: 'ISO (YYYY-MM-DD)',
+    timeFormat: 'Format czasu',
+    timeFormat12: '12-godzinny (3:30 PM)',
+    timeFormat24: '24-godzinny (15:30)',
+    defaultPrinter: 'Drukarka domyślna',
+    defaultPrinterDescription: 'Wstępnie wybieraj tę drukarkę przy przesyłaniu, ponownym drukowaniu i innych operacjach.',
+    slicerBambuStudio: 'Bambu Studio',
+    slicerOrcaSlicer: 'OrcaSlicer',
+    sidebarOrderDescription: 'Użyj paska bocznego, aby zmieniać kolejność elementów, resetować widoczność i zarządzać własnymi linkami.',
+    setDefault: 'Ustaw domyślne',
+    sidebarOrderSetDefaultHint: 'Ustaw domyślne stosuje bieżącą kolejność menu dla użytkowników, którzy nie dostosowali własnej.',
+    sidebarDefaultSet: 'Ustawiono domyślną kolejność menu.',
+    sidebarDefaultCleared: 'Wyczyszczono domyślną kolejność menu.',
+    sidebarDefaultFailed: 'Nie udało się ustawić domyślnej kolejności menu.',
+    reset: 'Resetuj',
+    // Appearance
+    darkMode: 'Tryb ciemny',
+    lightMode: 'Tryb jasny',
+    active: '(aktywny)',
+    background: 'Tło',
+    accent: 'Akcent',
+    style: 'Styl',
+    bgNeutral: 'Neutralne',
+    bgWarm: 'Ciepłe',
+    bgCool: 'Chłodne',
+    bgOled: 'Czerń OLED',
+    bgSlate: 'Łupkowy błękit',
+    bgForest: 'Leśna zieleń',
+    accentGreen: 'Zielony',
+    accentTeal: 'Morski',
+    accentBlue: 'Niebieski',
+    accentOrange: 'Pomarańczowy',
+    accentPurple: 'Fioletowy',
+    accentRed: 'Czerwony',
+    styleClassic: 'Klasyczny',
+    styleGlow: 'Poświata',
+    styleVibrant: 'Żywy',
+    themeToggleHint: 'Przełączaj między trybem ciemnym, jasnym i systemowym za pomocą ikony na pasku bocznym.',
+    progressInTitle: 'Postęp druku w karcie',
+    progressInTitleDescription: 'Pokazuj postęp aktywnego wydruku w tytule karty przeglądarki i na favikonie.',
+    tabDisplay: 'Wyświetlanie w karcie',
+    tabDisplayPercentage: 'Procent',
+    tabDisplayTime: 'Pozostały czas',
+    // Archive
+    autoArchivePrints: 'Automatycznie archiwizuj wydruki',
+    autoArchiveDescription: 'Automatycznie zapisuj pliki 3MF po ukończeniu wydruków. Po wyłączeniu wydruki uruchomione poza Bambuddy nie są archiwizowane na żadnej drukarce.',
+    captureFinishPhotoDescription: 'Zrób zdjęcie kamerą drukarki po ukończeniu wydruku. Podczas wydruku Bambuddy nagrywa krótki timelapse, aby zdjęcie mogło pochodzić z chwili przed opuszczeniem stołu; plik timelapse zostaje zachowany, jeśli włączono timelapse dla tego wydruku, w przeciwnym razie jest automatycznie usuwany po zrobieniu zdjęcia.',
+    finishPhotoRestorePlate: 'Przywróć płytę do zdjęcia końcowego',
+    finishPhotoRestorePlateDescription: 'Po zakończeniu wydruku drukarka opuszcza płytę roboczą o około 100 mm, przez co gotowy wydruk znajduje się poniżej kadru kamery. Bambuddy podnosi ją z powrotem tuż nad ostatnią wydrukowaną warstwę, robi zdjęcie, a potem znów ją opuszcza. Pomijane, gdy wysokość wydruku jest nieznana lub w kolejce czeka inne zadanie.',
+    ffmpegNotInstalled: 'ffmpeg nie jest zainstalowany',
+    ffmpegRequired: 'Przechwytywanie z kamery wymaga ffmpeg. Zainstaluj go poleceniem <brew>brew install ffmpeg</brew> (macOS) lub <apt>apt install ffmpeg</apt> (Linux).',
+    // Camera
+    camera: 'Kamera',
+    cameraViewMode: 'Tryb widoku kamery',
+    cameraOverlayDescription: 'Kamera otwiera się w nakładce o zmiennym rozmiarze na ekranie głównym',
+    cameraWindowDescription: 'Kamera otwiera się w osobnym oknie przeglądarki',
+    externalCamerasDescription: 'Skonfiguruj kamery zewnętrzne zastępujące wbudowaną kamerę drukarki. Obsługiwane są strumienie MJPEG, RTSP, zrzuty HTTP i kamery USB (V4L2). Po włączeniu kamera zewnętrzna jest używana do podglądu na żywo i zdjęć końcowych.',
+    cameraPlaceholderUsb: 'Ścieżka urządzenia (/dev/video0)',
+    usbCameraDevice: 'Urządzenie USB',
+    usbCameraSelect: 'Wybierz urządzenie',
+    usbCameraSearching: 'Wyszukiwanie urządzeń…',
+    usbCameraNotFound: '{{device}} (nie znaleziono)',
+    usbCameraRefresh: 'Wyszukaj urządzenia ponownie',
+    usbCameraListFailed: 'Nie udało się wyświetlić listy urządzeń wideo.',
+    usbCameraNoneFound: 'Bambuddy nie widzi żadnych urządzeń wideo. W Dockerze przekaż kamerę do kontenera:',
+    usbCameraEnterManually: 'Wprowadź ścieżkę ręcznie',
+    usbCameraPickFromList: 'Wybierz wykryte urządzenie',
+    cameraPlaceholderUrl: 'URL kamery (rtsp://... lub http://...)',
+    cameraTypeMjpeg: 'Strumień MJPEG',
+    cameraTypeRtsp: 'Strumień RTSP',
+    cameraTypeSnapshot: 'Zrzut HTTP',
+    cameraTypeUsb: 'Kamera USB (V4L2)',
+    cameraSnapshotUrl: 'URL zrzutu (opcjonalnie)',
+    cameraSnapshotUrlPlaceholder: 'http://192.168.1.61:1984/api/frame.jpeg?src=printer',
+    cameraSnapshotUrlHelp: 'URL pojedynczej klatki używany do miniatur w powiadomieniach, zdjęć końcowych, klatek timelapse warstw i wykrywania płyty. Timelapse i wykrywanie płyty wymagają osobnego przełącznika dla każdej drukarki — ten URL to tylko źródło obrazu, z którego korzystają, gdy są aktywne. Pozostaw puste, aby przechwytywać z powyższego strumienia na żywo. Przydatne dla go2rtc (/api/frame.jpeg) i kamer IP z osobnym endpointem zrzutów.',
+    cameraRotation: 'Obrót',
+    cameraLight: 'Włączaj oświetlenie komory dla kamery',
+    cameraLightHint: 'Włącza oświetlenie, gdy ktoś ogląda obraz z kamery, oraz przy automatycznych zrzutach, takich jak zdjęcia w powiadomieniach, zdjęcia końcowe i obrazy dla Home Assistant. Potem je wyłącza, ale tylko jeśli włączył je Bambuddy.',
+    cameraLightDelay: 'Czekaj przed zrzutem',
+    cameraLightDelayHint: 'Tylko gdy oświetlenie było wyłączone. Daje oświetleniu i wszelkim zsynchronizowanym z nim światłom czas na włączenie się.',
+    cameraLightMode_off: 'Wył.',
+    cameraLightMode_all: 'Wszystkie drukarki',
+    cameraLightMode_selected: 'Wybrane drukarki',
+    cameraLightDelayUnit: 'sekundy',
+    cameraLightNoneSelected: 'Nie wybrano jeszcze drukarki.',
+    cameraLightAddPrinter: 'Dodaj drukarkę',
+    cameraLightRemovePrinter: 'Usuń {{name}}',
+    externalCameraAdd: 'Dodaj kamerę zewnętrzną',
+    externalCameraRemove: 'Usuń kamerę zewnętrzną z {{name}}',
+    printerPickerSearch: 'Szukaj drukarek',
+    printerPickerNoMatch: 'Żadna drukarka nie pasuje.',
+    cameraShowSettings: 'Ustawienia kamery',
+    test: 'Testuj',
+    connected: 'Połączono',
+    disconnected: 'Rozłączono',
+    // Cost tracking
+    currency: 'Waluta',
+    defaultFilamentCost: 'Domyślny koszt filamentu (za kg)',
+    electricityCost: 'Koszt energii elektrycznej za kWh',
+    energyPriceSource: 'Źródło ceny energii elektrycznej',
+    energyPriceSourceFixed: 'Stała cena',
+    energyPriceSourceHomeAssistant: 'Czujnik Home Assistant',
+    energyPriceHaEntity: 'Czujnik ceny',
+    energyPriceLastRead: 'Ostatnio odczytana cena za kWh',
+    energyPriceFixedHint: 'Nowa cena dotyczy energii zużytej od tego momentu; energia już zużyta zachowuje cenę, po której została zużyta.',
+    energyPriceHaHint: 'Odczytywana co godzinę oraz na początku i końcu każdego wydruku, a każda godzina energii jest wyceniana po własnej cenie. Czujnik musi podawać cenę za kWh (ceny za MWh i za Wh są przeliczane).',
+    energyPriceHaNotConfigured: 'Home Assistant nie jest skonfigurowany. Połącz go w Ustawienia → Sieć → Home Assistant.',
+    energyDisplayMode: 'Tryb wyświetlania energii',
+    energyModePrintDescription: 'Pulpit pokazuje sumę energii zużytej podczas wydruków',
+    energyModeTotalDescription: 'Pulpit pokazuje całkowitą energię z inteligentnych gniazdek',
+    // File Manager
+    fileManager: 'Menedżer plików',
+    lowDiskSpaceWarning: 'Ostrzeżenie o małej ilości miejsca na dysku',
+    lowDiskSpaceDescription: 'Pokazuj ostrzeżenie, gdy wolne miejsce na dysku spadnie poniżej tego progu',
+    // Updates
+    printerFirmware: 'Firmware drukarek',
+    checkFirmwareDescription: 'Sprawdzaj aktualizacje firmware drukarek od Bambu Lab',
+    bambuddySoftware: 'Oprogramowanie Bambuddy',
+    autoCheckDescription: 'Automatycznie sprawdzaj nowe wersje przy uruchamianiu',
+    checkNow: 'Sprawdź teraz',
+    updateAvailableVersion: 'Dostępna aktualizacja: v{{version}}',
+    releaseNotes: 'Informacje o wydaniu',
+    updateViaDocker: 'Aktualizacja przez Docker Compose:',
+    composeDirectory: 'Katalog Compose',
+    composeDirectoryHint: 'Katalog zawierający docker-compose.yml. Pozostaw puste, aby pominąć cd.',
+    copyUpdateCommand: 'Kopiuj polecenie aktualizacji',
+    updateViaHomeAssistant: 'Aktualizacjami zarządza Home Assistant Supervisor. Otwórz w Home Assistant Ustawienia → Dodatki → Bambuddy, aby zainstalować nową wersję.',
+    updateViaWindowsInstaller: 'Instalacje Windows aktualizuje się przez ponowne uruchomienie instalatora. Pobierz nową wersję poniżej — twoje dane, ustawienia i drukarki zostaną zachowane.',
+    downloadWindowsInstaller: 'Pobierz instalator dla v{{version}}',
+    installUpdate: 'Zainstaluj aktualizację',
+    latestVersionRunning: "Używasz najnowszej wersji",
+    failedToCheckUpdates: 'Nie udało się sprawdzić aktualizacji: {{error}}',
+    // Data Management
+    backupRestore: 'Kopia zapasowa i przywracanie',
+    backupRestoreDescription: 'Eksportuj/importuj ustawienia i skonfiguruj kopię zapasową w GitHub',
+    goToBackup: 'Przejdź do kopii zapasowej',
+    // Network tab
+    externalUrl: 'Zewnętrzny URL',
+    externalUrlDescription: 'Zewnętrzny URL, pod którym dostępny jest Bambuddy. Używany do obrazów w powiadomieniach i integracji zewnętrznych.',
+    bambuddyUrl: 'URL Bambuddy',
+    externalUrlHint: 'Podaj protokół i port (np. http://192.168.1.100:8000)',
+    adminOnlySetting: 'Tylko administrator może to zmienić.',
+    ftpRetry: 'Ponawianie FTP',
+    ftpRetryDescription: 'Ponawiaj operacje FTP, gdy WiFi drukarki jest niestabilne. Dotyczy pobierania 3MF, przesyłania wydruków, pobierania timelapse i aktualizacji firmware.',
+    autoRetryDescription: 'Automatycznie ponawiaj nieudane operacje FTP',
+    retryAttempts: 'Liczba prób',
+    retryDelay: 'Opóźnienie ponowienia',
+    connectionTimeout: 'Limit czasu połączenia',
+    time_one: '{{count}} raz',
+    time_other: '{{count}} razy',
+    second_one: '{{count}} sekunda',
+    second_other: '{{count}} s',
+    nSeconds: '{{count}} s',
+    increaseForWeakWifi: 'Zwiększ dla drukarek ze słabym WiFi',
+    // Home Assistant
+    homeAssistant: 'Home Assistant',
+    homeAssistantFullDescription: 'Połącz się z Home Assistant, aby sterować inteligentnymi gniazdkami przez REST API HA. Obsługuje encje switch, light, input_boolean i script.',
+    homeAssistantUrl: 'URL Home Assistant',
+    longLivedAccessToken: 'Token dostępu o długim okresie ważności',
+    haTokenHint: 'Utwórz token w HA: Profil → Tokeny dostępu o długim okresie ważności → Utwórz token',
+    connectionSuccessful: 'Połączenie udane',
+    connectionFailed: 'Połączenie nieudane',
+    haConnectionSuccess: 'Pomyślnie połączono z Home Assistant.',
+    haConnectionFailed: 'Nie udało się połączyć z Home Assistant.',
+    // MQTT
+    mqttPublishing: 'Publikowanie MQTT',
+    mqttDescription: 'Publikuj zdarzenia BamBuddy do zewnętrznego brokera MQTT w celu integracji z Node-RED, Home Assistant i innymi systemami automatyzacji.',
+    mqttEnableDescription: 'Publikuj zdarzenia do zewnętrznego brokera MQTT',
+    brokerHostname: 'Nazwa hosta brokera',
+    port: 'Port',
+    usernameOptional: 'Nazwa użytkownika (opcjonalnie)',
+    passwordOptional: 'Hasło (opcjonalnie)',
+    topicPrefix: 'Prefiks tematu',
+    topicPrefixHint: 'Tematy będą miały postać: {{prefix}}/printers/<serial>/status itd.',
+    // Prometheus
+    prometheusMetrics: 'Metryki Prometheus',
+    prometheusEndpointDescription: 'Udostępniaj metryki drukarek pod <code>/api/v1/metrics</code> do monitorowania w Prometheus/Grafana.',
+    bearerTokenOptional: 'Token Bearer (opcjonalnie)',
+    bearerTokenHint: 'Jeśli ustawiony, żądania muszą zawierać <code>Authorization: Bearer <token></code>',
+    metricsConnectionStatus: 'Stan połączenia',
+    metricsPrinterState: 'Stan drukarki (bezczynna/drukuje itp.)',
+    metricsPrintProgress: 'Postęp druku 0-100%',
+    metricsBedTemp: 'Temperatura stołu',
+    metricsNozzleTemp: 'Temperatura dyszy',
+    metricsPrintsTotal: 'Łączna liczba wydruków wg wyniku',
+    metricsMore: '...i więcej (warstwy, wentylatory, kolejka, zużycie filamentu)',
+    // Smart Plugs
+    smartPlugsDescription: 'Podłącz inteligentne gniazdka (Tasmota lub Home Assistant), aby automatyzować sterowanie zasilaniem i śledzić zużycie energii drukarek.',
+    allOn: 'Wszystkie wł.',
+    allOff: 'Wszystkie wył.',
+    addSmartPlug: 'Dodaj inteligentne gniazdko',
+    energySummary: 'Podsumowanie energii',
+    currentPower: 'Bieżąca moc',
+    plugsOnline: 'Gniazdka online: {{reachable}}/{{total}}',
+    today: 'Dzisiaj',
+    yesterday: 'Wczoraj',
+    total: 'Łącznie',
+    enablePlugsForSummary: 'Włącz gniazdka, aby zobaczyć podsumowanie energii',
+    addNotificationProvider: 'Dodaj',
+    // Users
+    systemBadge: '(system)',
+    creating: 'Tworzenie...',
+    changing: 'Zmienianie...',
+    deleteUserAndItems: 'Usuń użytkownika ORAZ jego elementy',
+    deleteUserKeepItems: 'Usuń użytkownika, zachowaj elementy (staną się bez właściciela)',
+    ok: 'OK',
+
+    // 2FA settings
+    twoFa: {
+      totpTitle: 'Aplikacja uwierzytelniająca (TOTP)',
+      totpDesc: 'Użyj aplikacji uwierzytelniającej, np. Google Authenticator, Aegis lub Authy.',
+      emailOtpTitle: 'Kod OTP e-mailem',
+      emailOtpDesc: 'Wysyłaj jednorazowy kod na {{email}} przy logowaniu.',
+      emailOtpNoEmail: 'Dodaj adres e-mail do swojego konta, aby włączyć tę metodę.',
+      addEmailFirst: 'Twoje konto nie ma adresu e-mail. Poproś administratora o dodanie go przed włączeniem kodów OTP e-mailem.',
+      setupTotp: 'Skonfiguruj aplikację uwierzytelniającą',
+      setupAuthApp: 'Skonfiguruj aplikację uwierzytelniającą',
+      setupInstructions: 'Zeskanuj poniższy kod QR aplikacją uwierzytelniającą, a następnie potwierdź kodem.',
+      manualEntry: 'Nie możesz zeskanować? Wprowadź ten sekret ręcznie:',
+      scannedContinue: 'Kod zeskanowany — dalej',
+      enterCodeToConfirm: 'Wprowadź 6-cyfrowy kod z aplikacji uwierzytelniającej, aby potwierdzić konfigurację.',
+      activate: 'Aktywuj',
+      disableTotp: 'Wyłącz aplikację uwierzytelniającą',
+      disableConfirmHint: 'Wprowadź prawidłowy kod TOTP lub kod zapasowy, aby wyłączyć aplikację uwierzytelniającą.',
+      totpDisabled: 'Wyłączono aplikację uwierzytelniającą.',
+      emailOtpEnabled: 'Włączono kody OTP e-mailem.',
+      emailOtpDisabled: 'Wyłączono kody OTP e-mailem.',
+      smtpRequired: 'Najpierw skonfiguruj i przetestuj ustawienia SMTP.',
+      invalidCode: 'Nieprawidłowy kod. Spróbuj ponownie.',
+      enableEmailOtp: 'Włącz kody OTP e-mailem',
+      disableEmailOtp: 'Wyłącz kody OTP e-mailem',
+      emailSetupEnterCode: 'Na twój adres e-mail wysłano kod weryfikacyjny. Wprowadź go poniżej, aby potwierdzić, że jesteś właścicielem tej skrzynki.',
+      verifyAndEnable: 'Zweryfikuj i włącz',
+      emailDisablePasswordHint: 'Wprowadź hasło do konta, aby potwierdzić wyłączenie kodów OTP e-mailem.',
+      passwordPlaceholder: 'Wprowadź hasło',
+      backupCodesTitle: 'Zapisz kody zapasowe',
+      backupCodesWarning: 'Zapisz te kody w bezpiecznym miejscu. Każdy kod można użyć tylko raz i nie zostaną one wyświetlone ponownie.',
+      backupCodesRemaining: 'Pozostałe kody zapasowe: {{count}}',
+      savedCodes: 'Kody zapisane',
+      regenBackup: 'Wygeneruj nowe kody zapasowe',
+      regenBackupHint: 'Wprowadź bieżący kod TOTP, aby wygenerować 10 nowych kodów zapasowych. Wszystkie istniejące kody zapasowe zostaną unieważnione.',
+      newBackupCodes: 'Nowe kody zapasowe',
+      linkedAccounts: 'Powiązane konta SSO',
+      linkedAccountsDesc: 'Ci zewnętrzni dostawcy tożsamości są powiązani z twoim kontem.',
+      oidcUnlinked: 'Odłączono konto.',
+      oidcUnlinkConfirmTitle: 'Odłączyć konto?',
+      oidcUnlinkConfirmMessage: 'Logowanie przez {{provider}} nie będzie już możliwe.',
+      oidcUnlinkConfirmAction: 'Odłącz',
+    },
+
+    // Session Policy (#1706) — admin-configurable session lifetime ceiling.
+    sessionPolicy: {
+      title: 'Zasady sesji',
+      description: 'Maksymalny czas trwania sesji dla nowych logowań użytkowników. Już wydane tokeny zachowują pierwotny czas wygaśnięcia.',
+      preset24h: '24 godziny',
+      preset7d: '7 dni',
+      preset30d: '30 dni',
+      customHoursLabel: 'Własny czas trwania sesji w godzinach',
+      hoursSuffix: 'godz.',
+      warning: 'Dłuższe sesje osłabiają ochronę przez automatyczne wylogowanie. Zalecane tylko w zaufanych wdrożeniach z jednym użytkownikiem.',
+    },
+
+    // OIDC provider settings
+    oidc: {
+      title: 'Dostawcy SSO / OIDC',
+      desc: 'Skonfiguruj dostawców OpenID Connect, aby umożliwić logowanie jednokrotne przez zewnętrznych dostawców tożsamości.',
+      addProvider: 'Dodaj dostawcę',
+      newProvider: 'Nowy dostawca',
+      empty: 'Nie skonfigurowano jeszcze dostawców OIDC.',
+      created: 'Utworzono dostawcę.',
+      updated: 'Zaktualizowano dostawcę.',
+      deleted: 'Usunięto dostawcę.',
+      refreshIcon: 'Odśwież ikonę',
+      removeIcon: 'Usuń ikonę',
+      iconRefreshed: 'Odświeżono ikonę.',
+      iconRemoved: 'Usunięto ikonę.',
+      iconFetchFailed: 'Nie udało się pobrać ikony z URL dostawcy.',
+      deleteTitle: 'Usuń dostawcę',
+      deleteMessage: 'Usunąć „{{name}}”? Wszystkie powiązane konta użytkowników zostaną odłączone.',
+      form: {
+        name: 'Nazwa wyświetlana',
+        issuerUrl: 'URL wystawcy',
+        clientId: 'Client ID',
+        clientSecret: 'Client Secret',
+        scopes: 'Zakresy',
+        iconUrl: 'URL ikony (opcjonalnie)',
+        enabled: 'Włączony',
+        autoCreate: 'Automatycznie twórz użytkowników',
+        autoCreateDesc: 'Automatycznie twórz konto lokalne przy pierwszym logowaniu.',
+        autoLink: 'Automatycznie łącz istniejące konta',
+        autoLinkDesc: 'Przy pierwszym logowaniu łącz istniejące konta lokalne na podstawie zgodnego adresu e-mail.',
+        secretHint: 'pozostaw puste, aby zachować bieżący',
+        secretPlaceholder: 'nowy sekret',
+        emailClaim: 'Claim e-mail',
+        emailClaimDesc: "Claim JWT używany jako tożsamość e-mail. Dla Azure Entra ID (który nie wysyła email_verified) użyj 'preferred_username' lub 'upn'. Używaj tylko zaufanych nazw claimów.",
+        emailClaimPlaceholder: 'email',
+        emailClaimCustomClaimAutoLinkWarning: "Własne claimy są bezpieczne dla automatycznego łączenia tylko wtedy, gdy wartością zarządza administrator dzierżawy (np. upn / preferred_username w Azure Entra ID). Nie włączaj automatycznego łączenia, jeśli twój IdP pozwala użytkownikom samodzielnie ustawiać ten claim.",
+        requireEmailVerified: 'Wymagaj zweryfikowanego e-maila',
+        requireEmailVerifiedDesc: 'Akceptuj claim e-mail tylko wtedy, gdy dostawca oznacza go jako zweryfikowany.',
+        requireEmailVerifiedWarning: 'Uwaga: e-mail będzie akceptowany nawet bez weryfikacji. Używaj tylko z zaufanymi dostawcami.',
+        requireEmailVerifiedAutoLink: 'Najpierw wyłącz automatyczne łączenie, aby zmienić to ustawienie.',
+        defaultGroup: 'Grupa domyślna',
+        defaultGroupDesc: 'Grupa przypisywana automatycznie tworzonym użytkownikom. Jeśli nie ustawiono, używana jest grupa Viewers.',
+        defaultGroupViewersFallback: 'Viewers (domyślna)',
+        autologin: 'Automatyczne logowanie',
+        autologinDesc: 'Przekierowuj nieuwierzytelnionych odwiedzających bezpośrednio do tego dostawcy. Tę opcję może mieć tylko jeden dostawca.',
+        groupClaim: 'Claim grup',
+        groupClaimDesc: 'Claim JWT zawierający grupy użytkownika u dostawcy tożsamości. Większość dostawców używa \'groups\'; wartości mogą być tablicą JSON lub ciągiem znaków.',
+        groupMapping: 'Mapowanie grup',
+        groupMappingDesc: 'Zmapowane grupy są synchronizowane przy każdym logowaniu. Grupy niewymienione tutaj pozostają nietknięte, więc ręczne przypisania zostają zachowane. Pozostaw puste, aby wyłączyć synchronizację grup.',
+        groupMappingIdpGroupPlaceholder: 'Nazwa grupy u dostawcy tożsamości',
+        groupMappingSelectGroup: 'Wybierz grupę Bambuddy…',
+        groupMappingAddRow: 'Dodaj mapowanie',
+        groupMappingDeletedGroupOption: '{{group}} (usunięta)',
+        groupMappingDeletedGroupWarning: 'Ta grupa Bambuddy została usunięta. Wybierz zastępczą lub usuń to mapowanie.',
+        groupMappingIncompleteRow: 'Wprowadź grupę dostawcy tożsamości i wybierz grupę Bambuddy albo usuń to mapowanie.',
+        groupMappingDuplicateRow: 'Ta grupa dostawcy tożsamości jest już zmapowana powyżej. Nazwy grup są porównywane bez uwzględniania wielkości liter.',
+        groupSync: 'Synchronizacja grup',
+        groupSyncOn: 'Wł.',
+      },
+    },
+
+    encryption: {
+      title: 'Stan szyfrowania MFA',
+      enabledFromEnv: 'Szyfrowanie danych w spoczynku włączone (klucz ze zmiennej środowiskowej MFA_ENCRYPTION_KEY)',
+      enabledFromFile: 'Szyfrowanie danych w spoczynku włączone (klucz wczytany z katalogu danych)',
+      enabledGenerated: 'Szyfrowanie danych w spoczynku włączone z automatycznie wygenerowanym kluczem',
+      notConfigured: 'Szyfrowanie danych w spoczynku nie jest skonfigurowane',
+      notConfiguredDesc: 'Sekrety TOTP i client_secret OIDC są przechowywane jawnym tekstem. Ustaw MFA_ENCRYPTION_KEY lub uruchom ponownie Bambuddy z zapisywalnym katalogiem danych, aby wygenerować klucz automatycznie.',
+      allEncrypted: 'Wszystkie sekrety MFA są zaszyfrowane w spoczynku.',
+      legacyRowsLabel: 'Starsze wiersze jawnym tekstem',
+      encryptedRowsLabel: 'Zaszyfrowane wiersze',
+      legacyRowsWarning: 'Wykryte starsze wiersze jawnym tekstem: {{count}}. Zapisz ponownie dostawcę OIDC lub ponownie zarejestruj aplikację uwierzytelniającą użytkownika, aby przenieść je do zaszyfrowanego magazynu.',
+      backupHint: 'Automatycznie wygenerowany klucz jest przechowywany w DATA_DIR/.mfa_encryption_key i dołączany do lokalnych kopii zapasowych ZIP. Chroń swoje kopie zapasowe lub ustaw jawnie MFA_ENCRYPTION_KEY.',
+      decryptionBrokenTitle: 'Brak klucza szyfrowania',
+      decryptionBrokenError: 'Zaszyfrowane rekordy, których nie można odszyfrować, bo klucz szyfrowania nie jest już dostępny: {{count}}. Przywróć poprzedni MFA_ENCRYPTION_KEY lub DATA_DIR/.mfa_encryption_key, aby je odzyskać.',
+      migrationErrorWarning: 'Starsze wiersze, których nie udało się ponownie zaszyfrować przy uruchomieniu: {{count}}. Sprawdź logi serwera i uruchom ponownie Bambuddy, aby spróbować jeszcze raz.',
+    },
+
+    // Slicer Pipeline limits (#1425 PR C). Admin-tunable cap that constrains
+    // the copies input in the Run-with-pipeline modal. Lives on the Workflow
+    // tab's Queue & Dispatch sub-tab.
+    pipelineLimits: {
+      title: 'Limity potoków slicera',
+      maxCopiesLabel: 'Maks. liczba kopii na uruchomienie',
+      maxCopiesDesc: 'Górny limit kopii, o które operatorzy mogą prosić przy uruchamianiu potoku. Twardy limit po stronie serwera wynosi 1000.',
+    },
+
+    // Slicer Pipelines (#1425): list/edit/delete preset bundles users saved
+    // from the Slice dialog. Lives in Settings → Workflow → Pipelines sub-tab.
+    pipelines: {
+      title: 'Potoki slicera',
+      subtitle: 'Zestawy profili wielokrotnego użytku (drukarka + proces + filamenty + rodzaj płyty). Zapisz zestaw w oknie slicowania i zastosuj go jednym kliknięciem przy następnym pliku.',
+      loading: 'Wczytywanie potoków…',
+      loadError: 'Nie udało się wczytać potoków.',
+      confirmDelete: 'Usunąć ten potok? Tej operacji nie można cofnąć.',
+      staleWarning: 'Co najmniej jeden użyty profil już nie istnieje. Zapisz ponownie ten potok w oknie slicowania, aby to naprawić.',
+      empty: {
+        title: 'Brak jeszcze potoków.',
+        howto: 'Otwórz okno slicowania dla dowolnego pliku, wybierz drukarkę / proces / filamenty / rodzaj płyty, a następnie kliknij „Zapisz jako potok”. Zapisane potoki pojawią się tutaj.',
+      },
+      field: {
+        name: 'Nazwa potoku',
+        description: 'Opis',
+        targetPrinter: 'Drukarka docelowa',
+        noTarget: '— Brak celu —',
+        // PR C
+        targetKind: 'Rodzaj celu',
+        targetKindSpecific: 'Konkretna drukarka',
+        targetKindClass: 'Klasa drukarek',
+        targetModelClass: 'Model drukarki',
+        fanoutStrategy: 'Strategia rozdziału',
+        fanout: {
+          max_parallel: 'Maks. równolegle — rozdzielaj na dowolne bezczynne pasujące drukarki',
+          round_robin: 'Po kolei — cyklicznie przez kwalifikujące się drukarki',
+          fill_one_first: 'Najpierw jedna — wszystkie kopie na jednej drukarce',
+        },
+        // Short labels for the inline target chip on each pipeline card.
+        // The verbose ones above explain the strategy in the editor; the
+        // card just needs a compact reminder of which one is in use.
+        fanoutShort: {
+          max_parallel: 'równolegle',
+          round_robin: 'po kolei',
+          fill_one_first: 'najpierw jedna',
+        },
+      },
+      action: {
+        save: 'Zapisz',
+        cancel: 'Anuluj',
+        rename: 'Zmień nazwę',
+        delete: 'Usuń',
+      },
+      slot: {
+        printer: 'Drukarka',
+        process: 'Proces',
+        filament: 'Filament',
+        filamentN: 'Filament {{n}}',
+        filamentAll: 'Wszystkie sloty ({{n}})',
+        bed: 'Płyta',
+      },
+      // PR C polish — grouped sections in the card body, plus the
+      // panel-level search + filter row.
+      group: {
+        profiles: 'Profile',
+        filaments: 'Filamenty',
+      },
+      searchPlaceholder: 'Szukaj potoków…',
+      filterTargetType: 'Filtruj wg rodzaju celu',
+      filterTarget: 'Filtruj wg celu',
+      filter: {
+        all: 'Wszystkie cele',
+        noTarget: 'Bez ustawionego celu',
+        count: '{{shown}} / {{total}}',
+        noMatches: 'Żaden potok nie pasuje do bieżących filtrów.',
+      },
+      toast: {
+        saved: 'Zapisano potok',
+        saveFailed: 'Zapis nie powiódł się',
+        deleted: 'Usunięto potok',
+        deleteFailed: 'Usuwanie nie powiodło się',
+      },
+      // PR B target binding + last-run summary
+      noTargetHint: 'Ustaw drukarkę docelową, aby to uruchomić',
+      noTargetWarning: 'Przed uruchomieniem tego potoku ustaw drukarkę docelową.',
+      runs: {
+        lastRun: 'Ostatnie uruchomienie',
+        status: {
+          queued: 'w kolejce',
+          slicing: 'slicowanie',
+          dispatching: 'wysyłanie',
+          in_progress: 'drukowanie',
+          completed: 'ukończono',
+          failed: 'nieudane',
+          partial_failure: 'częściowo nieudane',
+          cancelled: 'anulowano',
+        },
+      },
+    },
+  },
+
+  // Notifications (for push notifications)
+  notification: {
+    printStarted: {
+      title: 'Rozpoczęto wydruk',
+      body: '{{printer}}: rozpoczęto drukowanie {{filename}}',
+    },
+    printCompleted: {
+      title: 'Wydruk ukończony',
+      body: '{{printer}}: {{filename}} ukończono pomyślnie',
+    },
+    printFailed: {
+      title: 'Wydruk nieudany',
+      body: '{{printer}}: wydruk {{filename}} nie powiódł się',
+    },
+    printStopped: {
+      title: 'Wydruk zatrzymany',
+      body: '{{printer}}: wydruk {{filename}} został zatrzymany',
+    },
+    printProgress: {
+      title: 'Postęp wydruku',
+      body: '{{printer}}: {{filename}} ukończono w {{percent}}%',
+    },
+    printerOffline: {
+      title: 'Drukarka offline',
+      body: '{{printer}} jest offline',
+    },
+    printerError: {
+      title: 'Błąd drukarki',
+      body: '{{printer}}: {{error}}',
+    },
+    filamentLow: {
+      title: 'Mało filamentu',
+      body: '{{printer}}: kończy się filament',
+    },
+    maintenanceDue: {
+      title: 'Wymagana konserwacja',
+      body: '{{printer}}: wymaga uwagi: {{items}}',
+    },
+  },
+
+  // Errors
+  errors: {
+    generic: 'Coś poszło nie tak',
+    networkError: 'Błąd sieci. Sprawdź połączenie.',
+    notFound: 'Nie znaleziono',
+    unauthorized: 'Brak autoryzacji',
+    serverError: 'Błąd serwera',
+    validationError: 'Sprawdź wprowadzone dane',
+    printerConnectionFailed: 'Nie udało się połączyć z drukarką',
+    saveFailed: 'Nie udało się zapisać zmian',
+    deleteFailed: 'Nie udało się usunąć',
+    loadFailed: 'Nie udało się wczytać danych',
+  },
+
+  // HMS Errors modal
+  hmsErrors: {
+    title: 'Błędy - {{name}}',
+    noErrors: 'Brak błędów',
+    viewOnWiki: 'Zobacz w Bambu Lab Wiki',
+    mqttVerifyFailedRemedy: 'Włącz tryb dewelopera na drukarce, uruchom drukarkę ponownie, a następnie ponownie rozpocznij zadanie.',
+    mqttVerifyFailedDescription: "Drukarka odrzuciła polecenie, ponieważ nie mogła go zweryfikować. Wydruki, zmiany temperatury i ładowanie filamentu wysyłane z Bambuddy będą ignorowane, dopóki nie zostanie to naprawione.",
+    severityError: "Błąd",
+    severityWarning: "Ostrzeżenie",
+    severityNotice: "Informacja",
+    severityUnknown: "Nieznany poziom",
+    uncountedSummary: "Zgłoszone również, niewliczane ({{n}})",
+    uncountedHint: "Informacje, które nie wymagają twojej uwagi, oraz kody, dla których Bambu nie publikuje opisu. Nie są liczone jako problemy na karcie drukarki i nie wysyłają powiadomień.",
+    unknownCode: 'Nieznany kod HMS — szczegóły znajdziesz w Bambu Lab Wiki.',
+    clearInstructions: 'Wyczyść błędy na drukarce, aby ukryć je tutaj.',
+    clearErrors: 'Wyczyść błędy',
+    clearSuccess: 'Wyczyszczono błędy HMS',
+    clearFailed: 'Nie udało się wyczyścić błędów HMS',
+    actionSuccess: 'Wysłano akcję do drukarki',
+    actionFailed: 'Nie udało się wysłać akcji',
+    runoutExpectedSlot: 'Skończył się filament w {{ranOut}}. Drukarka czeka teraz na zgodny filament w {{expected}}. Włóż szpulę do {{expected}}, a następnie wybierz Ponów.',
+    runoutExpectedSlotOnly: 'Drukarka czeka na zgodny filament w {{expected}}. Włóż tam szpulę, a następnie wybierz Ponów.',
+    runoutSlotUnknown: 'Skończył się filament i wydruk został wstrzymany. Bambuddy nie mógł ustalić, którego slotu drukarka teraz oczekuje — sprawdź żądany slot na ekranie drukarki.',
+    actions: {
+      RESUME_PRINTING: "Wznów drukowanie",
+      RESUME_PRINTING_DEFECTS: "Wznów (wady dopuszczalne)",
+      RESUME_PRINTING_PROBELM_SOLVED: "Wznów (problem rozwiązany)",
+      STOP_PRINTING: "Zatrzymaj drukowanie",
+      CHECK_ASSISTANT: "Sprawdź asystenta",
+      FILAMENT_EXTRUDED: "Filament wytłoczony, kontynuuj",
+      RETRY_FILAMENT_EXTRUDED: "Jeszcze nie wytłoczony, ponów",
+      CONTINUE: "Gotowe, kontynuuj",
+      LOAD_VIRTUAL_TRAY: "Załaduj filament",
+      OK_BUTTON: "OK",
+      FILAMENT_LOAD_RESUME: "Filament załadowany, wznów",
+      JUMP_TO_LIVEVIEW: "Pokaż podgląd na żywo",
+      NO_REMINDER_NEXT_TIME: "Nie przypominaj następnym razem",
+      REFRESH_NOZZLE: "Sprawdź ponownie",
+      IGNORE_NO_REMINDER_NEXT_TIME: "Ignoruj. Nie przypominaj następnym razem",
+      IGNORE_RESUME: "Zignoruj i wznów",
+      PROBLEM_SOLVED_RESUME: "Problem rozwiązany, wznów",
+      TURN_OFF_FIRE_ALARM: "Rozumiem, wyłącz alarm pożarowy.",
+      RETRY_PROBLEM_SOLVED: "Ponów (problem rozwiązany)",
+      CANCLE: "Anuluj",
+      STOP_DRYING: "Zatrzymaj suszenie",
+      PROCEED: "Kontynuuj",
+      OK_JUMP_RACK: "OK",
+      ABORT: "Przerwij",
+      DISABLE_PURIFICATION: "Wyłącz oczyszczanie dla tego wydruku",
+      DONT_REMIND_NEXT_TIME: "Nie przypominaj mi",
+      DBL_CHECK_CANCEL: "Anuluj",
+      DBL_CHECK_DONE: "Gotowe",
+      DBL_CHECK_RETRY: "Ponów",
+      DBL_CHECK_RESUME: "Wznów",
+      DBL_CHECK_OK: "Potwierdź",
+      REMOVE_CLOSE_BTN: "Zamknij",
+    }
+  },
+
+  // MQTT Debug modal
+  mqttDebug: {
+    title: 'Dziennik debugowania MQTT',
+    searchPlaceholder: 'Szukaj tematu lub treści...',
+    noMessages: 'Nie zarejestrowano jeszcze żadnych wiadomości',
+    startLoggingHint: 'Kliknij "Rozpocznij rejestrowanie", aby zacząć przechwytywać wiadomości MQTT',
+    noMessagesMatch: 'Żadne wiadomości nie pasują do filtra',
+    adjustFilterHint: 'Spróbuj zmienić wyszukiwanie lub kryteria filtrowania',
+    incoming: 'Przychodzące',
+    outgoing: 'Wychodzące',
+    loggingStopped: 'Rejestrowanie zatrzymane',
+    loggingActive: 'Rejestrowanie aktywne - wiadomości odświeżają się automatycznie',
+    startLogging: 'Rozpocznij rejestrowanie',
+    stopLogging: 'Zatrzymaj rejestrowanie',
+    clearLog: 'Wyczyść dziennik',
+    topic: 'Temat',
+    timestamp: 'Znacznik czasu',
+    direction: 'Kierunek',
+    all: 'Wszystkie',
+  },
+
+  // Printer File Manager modal (printer internal storage)
+  printerFiles: {
+    zipStarted_one: 'Rozpoczęto pobieranie ZIP ({{count}} plik)',
+    zipStarted_other: 'Rozpoczęto pobieranie ZIP (pliki: {{count}})',
+    zipPartial: 'Rozpoczęto pobieranie ZIP z {{successful}} z {{total}} plików; pozostałych nie udało się pobrać',
+    downloadFailed: 'Pobieranie nie powiodło się: {{error}}',
+    unknownError: 'Nieznany błąd',
+    shiftSelectHint: 'Kliknij z klawiszem Shift, aby zaznaczyć zakres',
+    selectFile: 'Zaznacz {{name}}',
+    deselectFile: 'Odznacz {{name}}',
+    title: 'Menedżer plików',
+    storageUsed: 'Zajęte:',
+    storageFree: 'Wolne:',
+    filterPlaceholder: 'Filtruj pliki...',
+    deleteButton: 'Usuń',
+    deleteFiles: 'Usuń pliki ({{count}})',
+    deleteFileConfirm: 'Usunąć "{{name}}"? Tej operacji nie można cofnąć.',
+    deleteFilesConfirm: 'Usunąć zaznaczone pliki ({{count}})? Tej operacji nie można cofnąć.',
+    noFiles: 'Brak plików na drukarce',
+    printerUnavailable: 'Usługa plików drukarki jest niedostępna. Spróbuj ponownie, gdy drukarka będzie osiągalna.',
+    listingTimedOut: 'Drukarka odpowiada, ale wyświetlanie zawartości tego folderu trwa zbyt długo (duży folder na wolnej karcie SD). Spróbuj ponownie za chwilę.',
+    loadingFiles: 'Wczytywanie plików...',
+    failedToLoad: 'Nie udało się wczytać plików',
+    toast: {
+      filesDeleted: 'Usunięte pliki: {{count}}',
+      deleteFailed: 'Usuwanie nie powiodło się: {{error}}',
+    },
+  },
+
+  // Confirmations
+  confirm: {
+    delete: 'Czy na pewno chcesz to usunąć?',
+    unsavedChanges: 'Masz niezapisane zmiany. Czy na pewno chcesz wyjść?',
+    clearQueue: 'Czy na pewno chcesz wyczyścić kolejkę?',
+  },
+
+  // Login page
+  login: {
+    retrying: 'Nie można połączyć się z Bambuddy. Ponawianie…',
+    title: 'Logowanie do Bambuddy',
+    subtitle: 'Zaloguj się na swoje konto',
+    username: 'Nazwa użytkownika',
+    usernamePlaceholder: 'Wpisz nazwę użytkownika',
+    usernameOrEmail: 'Nazwa użytkownika lub e-mail',
+    usernameOrEmailPlaceholder: 'Nazwa użytkownika lub @ e-mail',
+    password: 'Hasło',
+    passwordPlaceholder: 'Wpisz hasło',
+    signIn: 'Zaloguj się',
+    signingIn: 'Logowanie...',
+    rememberMe: 'Zapamiętaj mnie',
+    forgotPassword: 'Nie pamiętasz hasła?',
+    autologinFailed: 'Automatyczne logowanie SSO nie powiodło się. Wybierz dostawcę poniżej, aby kontynuować.',
+    localDisabledNotice: 'Logowanie lokalne jest wyłączone. Użyj jednego z dostawców SSO poniżej.',
+    loginSuccess: 'Zalogowano pomyślnie',
+    loginFailed: 'Logowanie nie powiodło się',
+    enterCredentials: 'Wpisz nazwę użytkownika i hasło',
+    enterEmail: 'Wpisz swój adres e-mail',
+    oidcLoginFailed: 'Logowanie OIDC nie powiodło się',
+    oidcErrors: {
+      providerError: 'Dostawca tożsamości zwrócił błąd',
+      missingParameters: 'W wywołaniu zwrotnym OIDC brakuje wymaganych parametrów',
+      invalidState: 'Stan OIDC jest nieprawidłowy lub został już użyty',
+      stateExpired: 'Sesja logowania OIDC wygasła — spróbuj ponownie',
+      providerNotFound: 'Nie znaleziono dostawcy OIDC',
+      discoveryFailed: 'Nie udało się pobrać dokumentu wykrywania OIDC',
+      invalidDiscovery: 'Dokument wykrywania OIDC jest nieprawidłowy',
+      networkError: 'Błąd sieci podczas wymiany tokenu OIDC',
+      badResponse: 'Nieoczekiwana odpowiedź podczas wymiany tokenu OIDC',
+      noIdToken: 'Dostawca OIDC nie zwrócił tokenu ID',
+      validationFailed: 'Weryfikacja tokenu OIDC nie powiodła się',
+      nonceMismatch: 'Niezgodność nonce OIDC — możliwy atak typu replay',
+      missingSubClaim: 'W tokenie OIDC brakuje oświadczenia sub',
+      noLinkedAccount: 'Z tą tożsamością OIDC nie jest powiązane żadne konto lokalne',
+      accountInactive: 'Twoje konto jest nieaktywne',
+      userResolutionFailed: 'Nie udało się ustalić twojego konta',
+      internalError: 'Podczas logowania OIDC wystąpił błąd wewnętrzny',
+      tokenExchangeFailed: 'Wymiana tokenu OIDC nie powiodła się',
+    },
+    forgotPasswordTitle: 'Nie pamiętasz hasła',
+    forgotPasswordMessage: "Jeśli nie pamiętasz hasła, skontaktuj się z administratorem systemu, aby je zresetować.",
+    forgotPasswordEmailMessage: "Wpisz swój adres e-mail, a wyślemy ci link do ustawienia nowego hasła.",
+    emailAddress: 'Adres e-mail',
+    emailPlaceholder: 'twoj.email@example.com',
+    cancel: 'Anuluj',
+    sending: 'Wysyłanie...',
+    sendResetEmail: 'Wyślij e-mail resetujący',
+    howToReset: 'Jak zresetować hasło:',
+    resetStep1: 'Skontaktuj się z administratorem Bambuddy',
+    resetStep2: 'Poproś o zresetowanie hasła w Zarządzaniu użytkownikami',
+    resetStep3: 'Administrator może ustawić dla ciebie nowe hasło tymczasowe',
+    resetStep4: 'Zaloguj się nowym hasłem i zmień je w Ustawieniach',
+    gotIt: 'Rozumiem',
+    resetPassword: {
+      title: 'Ustaw nowe hasło',
+      subtitle: 'Wpisz i potwierdź nowe hasło poniżej.',
+      newPassword: 'Nowe hasło',
+      newPasswordPlaceholder: 'Co najmniej 8 znaków',
+      confirmPassword: 'Potwierdź hasło',
+      confirmPasswordPlaceholder: 'Powtórz nowe hasło',
+      saving: 'Zapisywanie…',
+      submit: 'Ustaw nowe hasło',
+      backToLogin: 'Powrót do logowania',
+      passwordsDoNotMatch: 'Hasła nie są zgodne',
+      passwordTooShort: 'Hasło musi mieć co najmniej 8 znaków',
+      resetFailed: 'Resetowanie hasła nie powiodło się. Link mógł wygasnąć.',
+    },
+    twoFA: {
+      title: 'Uwierzytelnianie dwuskładnikowe',
+      subtitle: 'Twoje konto jest chronione przez 2FA. Wpisz kod weryfikacyjny poniżej.',
+      methodAuthenticator: 'Aplikacja uwierzytelniająca',
+      methodEmail: 'Kod e-mail',
+      methodBackup: 'Kod zapasowy',
+      instructionsTotp: 'Otwórz aplikację uwierzytelniającą i wpisz 6-cyfrowy kod dla Bambuddy.',
+      instructionsEmail: '6-cyfrowy kod został wysłany na twój adres e-mail. Wygasa po 10 minutach.',
+      instructionsEmailNotSent: 'Kliknij przycisk poniżej, aby otrzymać kod weryfikacyjny e-mailem.',
+      instructionsBackup: 'Wpisz jeden z 8-znakowych zapasowych kodów odzyskiwania. Każdego kodu można użyć tylko raz.',
+      sendCodeButton: 'Wyślij kod e-mailem',
+      sendingCode: 'Wysyłanie...',
+      resendCode: 'Wyślij kod ponownie',
+      codeLabel: 'Kod weryfikacyjny',
+      backupCodeLabel: 'Kod zapasowy',
+      codePlaceholder: '000000',
+      backupCodePlaceholder: 'XXXXXXXX',
+      verifyButton: 'Zweryfikuj',
+      verifyingButton: 'Weryfikowanie...',
+      backToLogin: '← Powrót do logowania',
+      orContinueWith: 'lub kontynuuj przez',
+      signInWith: 'Zaloguj się przez {{provider}}',
+      enterCode: 'Wpisz kod weryfikacyjny',
+      sendCodeFailed: 'Nie udało się wysłać kodu weryfikacyjnego',
+      invalidCode: 'Nieprawidłowy kod. Spróbuj ponownie.',
+    },
+
+  },
+
+  // Setup page
+  setup: {
+    title: 'Konfiguracja Bambuddy',
+    subtitle: 'Skonfiguruj uwierzytelnianie dla swojej instancji Bambuddy',
+    enableAuth: 'Włącz uwierzytelnianie',
+    adminAccount: 'Konto administratora',
+    adminAccountDesc: 'Jeśli istnieją już administratorzy, uwierzytelnianie zostanie włączone z użyciem istniejących kont administratorów. Pozostaw poniższe pola puste, aby użyć istniejących administratorów, lub wpisz nowe dane, aby utworzyć nowego administratora.',
+    adminUsername: 'Nazwa administratora',
+    adminPassword: 'Hasło administratora',
+    optionalIfAdminExists: '(opcjonalne, jeśli istnieją administratorzy)',
+    adminUsernamePlaceholder: 'Wpisz nazwę administratora (opcjonalnie)',
+    adminPasswordPlaceholder: 'Wpisz hasło administratora (opcjonalnie)',
+    confirmPassword: 'Potwierdź hasło',
+    confirmPasswordPlaceholder: 'Potwierdź hasło administratora',
+    settingUp: 'Konfigurowanie...',
+    completeSetup: 'Zakończ konfigurację',
+    toast: {
+      authEnabledAdminCreated: 'Włączono uwierzytelnianie i utworzono administratora',
+      authEnabledExistingAdmins: 'Włączono uwierzytelnianie z użyciem istniejących administratorów',
+      setupCompleted: 'Konfiguracja zakończona',
+      enterBothCredentials: 'Wpisz nazwę i hasło administratora lub pozostaw oba pola puste, aby użyć istniejących administratorów',
+      passwordsDoNotMatch: 'Hasła nie są zgodne',
+      passwordTooShort: 'Hasło musi mieć co najmniej 6 znaków',
+    },
+  },
+
+  // Password change
+  changePassword: {
+    title: 'Zmień hasło',
+    currentPassword: 'Obecne hasło',
+    currentPasswordPlaceholder: 'Wpisz obecne hasło',
+    newPassword: 'Nowe hasło',
+    newPasswordPlaceholder: 'Wpisz nowe hasło (min. 6 znaków)',
+    confirmPassword: 'Potwierdź nowe hasło',
+    confirmPasswordPlaceholder: 'Potwierdź nowe hasło',
+    passwordsDoNotMatch: 'Hasła nie są zgodne',
+    passwordTooShort: 'Hasło musi mieć co najmniej 6 znaków',
+    changing: 'Zmienianie...',
+    success: 'Hasło zostało zmienione',
+    failed: 'Nie udało się zmienić hasła',
+  },
+
+  // Plate detection alert
+  plateAlert: {
+    title: 'Wydruk wstrzymany!',
+    message: 'Wykryto obiekty na płycie roboczej. Wydruk został automatycznie wstrzymany. Oczyść płytę i wznów wydruk.',
+    understand: 'Rozumiem',
+  },
+
+  // Camera page
+  cameraLauncher: {
+    title: 'Kamery',
+    noPrinters: 'Brak drukarek',
+    open: 'Pokaż kamerę',
+    close: 'Zamknij kamerę',
+  },
+  camera: {
+    title: 'Widok kamery',
+    invalidPrinterId: 'Nieprawidłowy identyfikator drukarki',
+    popOut: 'Otwórz w osobnym oknie',
+    popIn: 'Pokaż jako nakładkę w Bambuddy',
+    popInNoTab: 'Nie jest otwarta żadna karta Bambuddy, w której można pokazać kamerę.',
+    poppedIn: 'Ta kamera jest teraz wyświetlana w Bambuddy. Możesz zamknąć to okno.',
+    live: 'Na żywo',
+    snapshot: 'Zdjęcie',
+    restartStream: 'Uruchom strumień ponownie',
+    refreshSnapshot: 'Odśwież zdjęcie',
+    fullscreen: 'Pełny ekran',
+    exitFullscreen: 'Zamknij pełny ekran',
+    connectingToCamera: 'Łączenie z kamerą...',
+    capturingSnapshot: 'Robienie zdjęcia...',
+    connectionLost: 'Utracono połączenie',
+    connectionFailed: 'Połączenie z kamerą nie powiodło się',
+    reconnecting: 'Ponowne łączenie za {{countdown}} s... (próba {{attempt}}/{{max}})',
+    reconnectNow: 'Połącz ponownie teraz',
+    cameraUnavailable: 'Kamera niedostępna',
+    cameraUnavailableDesc: 'Upewnij się, że drukarka jest włączona i połączona.',
+    noCamera: 'Brak dostępnej kamery',
+    retry: 'Ponów',
+    cameraStream: 'Strumień kamery',
+    zoomOut: 'Pomniejsz',
+    zoomIn: 'Powiększ',
+    resetZoom: 'Resetuj powiększenie',
+    recording: 'Nagrywanie',
+    startRecording: 'Rozpocznij nagrywanie',
+    stopRecording: 'Zatrzymaj nagrywanie',
+    chamberLight: 'Przełącz oświetlenie komory',
+    unavailable: 'Kamera niedostępna',
+    diagnose: {
+      button: 'Diagnozuj',
+      modalTitle: 'Diagnostyka kamery',
+      running: 'Trwa diagnostyka...',
+      runFailed: 'Nie udało się uruchomić diagnostyki: {{error}}',
+      retry: 'Uruchom ponownie',
+      stage: {
+        tcp_reachable: 'Osiągalność w sieci',
+        first_frame: 'Przechwytywanie klatki',
+        live_stream_active: 'Aktywny strumień na żywo',
+      },
+      summary: {
+        all_ok: 'Kamera działa. Diagnostyka pomyślnie ukończyła wszystkie etapy.',
+        live_stream_active_healthy: 'Kamera właśnie przesyła strumień z bieżącymi klatkami — test nie jest potrzebny.',
+        printer_unreachable: 'Drukarka jest nieosiągalna. Sprawdź adres IP, połączenie sieciowe i czy drukarka jest włączona.',
+        camera_port_closed: 'Drukarka jest osiągalna, ale port kamery jest zamknięty. Upewnij się, że w ustawieniach drukarki włączone są tryb tylko LAN i tryb dewelopera.',
+        no_frame: 'Połączono z kamerą, ale nie odebrano żadnych klatek. Spróbuj ponownie lub sprawdź, czy kamera jest włączona w ustawieniach drukarki.',
+        unknown_failure: 'Diagnostyka kamery nie powiodła się z nieznanego powodu. Szczegóły znajdziesz w dzienniku wsparcia.',
+      },
+      meta: {
+        protocol: 'Protokół',
+        port: 'Port',
+        profile: 'Profil',
+      },
+    },
+  },
+
+  // Groups management
+  groups: {
+    title: 'Zarządzanie grupami',
+    subtitle: 'Zarządzaj grupami uprawnień do kontroli dostępu',
+    backToSettings: 'Powrót do ustawień',
+    createGroup: 'Utwórz grupę',
+    noPermission: 'Nie masz uprawnień dostępu do tej strony.',
+    system: 'Systemowa',
+    noDescription: 'Brak opisu',
+    usersCount: 'Użytkownicy: {{count}}',
+    permissionsCount: 'Uprawnienia: {{count}}',
+    edit: 'Edytuj',
+    delete: 'Usuń',
+    toast: {
+      created: 'Grupa została utworzona',
+      updated: 'Grupa została zaktualizowana',
+      deleted: 'Grupa została usunięta',
+      enterGroupName: 'Wpisz nazwę grupy',
+    },
+    modal: {
+      editGroup: 'Edytuj grupę',
+      createGroup: 'Utwórz grupę',
+      cancel: 'Anuluj',
+      saving: 'Zapisywanie...',
+      creating: 'Tworzenie...',
+      saveChanges: 'Zapisz zmiany',
+    },
+    form: {
+      groupName: 'Nazwa grupy',
+      groupNamePlaceholder: 'Wpisz nazwę grupy',
+      systemGroupWarning: 'Nazw grup systemowych nie można zmieniać',
+      description: 'Opis',
+      descriptionPlaceholder: 'Wpisz opis (opcjonalnie)',
+      permissions: 'Uprawnienia (zaznaczone: {{count}})',
+    },
+    deleteModal: {
+      title: 'Usuń grupę',
+      message: 'Czy na pewno chcesz usunąć tę grupę? Użytkownicy tej grupy utracą te uprawnienia.',
+      confirm: 'Usuń grupę',
+    },
+    editor: {
+      title: 'Edytuj grupę',
+      createTitle: 'Utwórz grupę',
+      search: 'Szukaj uprawnień...',
+      selectAll: 'Zaznacz wszystkie',
+      clearAll: 'Wyczyść wszystkie',
+      permissionsSelected: 'Zaznaczone: {{count}}',
+      noResults: 'Żadne uprawnienia nie pasują do wyszukiwania',
+      websocketHint: 'Wymagane do aktualizacji na żywo. Bez tego interfejs przechodzi na okresowe odpytywanie.',
+      printerAccess: 'Dostęp do drukarek',
+      adminsSeeAllPrinters: 'Administratorzy zawsze widzą wszystkie drukarki.',
+      printerAccessAfterCreate: 'Po utworzeniu grupy wybierz jej drukarki w Ustawienia → Uwierzytelnianie → Dostęp do drukarek.',
+      printerAccessLimited: 'Ograniczony: wybrane drukarki: {{printers}}, lokalizacje: {{locations}}',
+      printerAccessOpen: 'Bez ograniczeń: członkowie widzą wszystkie drukarki.',
+      managePrinterAccess: 'Zarządzaj dostępem do drukarek',
+    },
+  },
+
+  // Printer access per group (#1727)
+  printerAccess: {
+    tab: 'Dostęp do drukarek',
+    intro: 'Wybierz, które drukarki mogą widzieć i obsługiwać członkowie każdej grupy. Grupa bez ograniczeń niczego nie zawęża: użytkownik, który nie należy do żadnej ograniczonej grupy, widzi wszystkie drukarki, a administratorzy widzą je zawsze.',
+    byGroup: 'Według grupy',
+    byPrinter: 'Według drukarki',
+    searchGroups: 'Szukaj grup',
+    groupFilter: {
+      all: 'Wszystkie',
+      limited: 'Ograniczone',
+      open: 'Bez ograniczeń',
+    },
+    noGroupsMatch: 'Brak pasujących grup.',
+    alwaysAll: 'Zawsze wszystkie drukarki',
+    notLimited: 'Wszystkie drukarki',
+    reachShort: '{{count}} z {{total}} drukarek',
+    unsaved: 'Niezapisane zmiany',
+    pickGroup: 'Wybierz grupę, aby wybrać jej drukarki.',
+    memberCount: 'Członkowie: {{count}}',
+    editGroup: 'Edytuj grupę',
+    adminsSeeAll: 'Administratorzy zawsze widzą wszystkie drukarki.',
+    limit: 'Ogranicz członków do wybranych tutaj drukarek i lokalizacji',
+    limitHint: 'Wyłączone: ta grupa nie zawęża drukarek widocznych dla jej członków.',
+    reach: 'Członkowie mogą używać {{count}} z {{total}} drukarek.',
+    noneGranted: 'Nic nie wybrano: członkowie tej grupy nie zobaczą żadnej drukarki.',
+    noPrinters: 'Nie dodano jeszcze żadnych drukarek.',
+    searchPrinters: 'Szukaj nazwy, modelu, numeru seryjnego lub lokalizacji',
+    allLocations: 'Wszystkie lokalizacje',
+    noLocation: 'Brak lokalizacji',
+    allModels: 'Wszystkie modele',
+    accessFilter: 'Dostęp',
+    accessAll: 'Z dostępem i bez',
+    accessWith: 'Z dostępem',
+    accessWithout: 'Bez dostępu',
+    tickShown: 'Zaznacz wszystkie widoczne',
+    untickShown: 'Odznacz wszystkie widoczne',
+    emptyLocation: 'obecnie nie ma tu żadnej drukarki',
+    wholeLocation: 'Cała lokalizacja',
+    wholeLocationHint: 'Wszystkie drukarki w {{location}}, w tym drukarki dodane tam później',
+    noPrintersMatch: 'Brak pasujących drukarek.',
+    viaLocation: 'przez lokalizację',
+    alsoVisible: 'Oprócz wymienionych tu grup każda drukarka jest widoczna dla administratorów i dla użytkowników, którzy nie należą do żadnej ograniczonej grupy.',
+    openUsers: 'Użytkownicy spoza ograniczonych grup: {{names}}',
+    noOpenUsers: 'Każdy użytkownik oprócz administratorów należy do ograniczonej grupy.',
+    noLimitedGroups: 'Żadna grupa nie jest jeszcze ograniczona, więc każdy użytkownik widzi wszystkie drukarki. Ogranicz grupę w widoku Według grupy.',
+    noLimitedGroupReaches: 'Brak ograniczonej grupy',
+    showingOne: 'Wyświetlana jest jedna drukarka.',
+    showAll: 'Pokaż wszystkie drukarki',
+    viaLocationTitle: 'Przez lokalizację {{location}}. Zmień to w widoku Według grupy.',
+    removeGroup: 'Odbierz dostęp grupie {{group}}',
+    addGroup: 'Nadaj dostęp…',
+    changedGroups: 'Niezapisane zmiany: {{names}}',
+    discard: 'Odrzuć',
+    saved: 'Zapisano dostęp do drukarek',
+    whoHasAccess: 'Kto ma dostęp',
+    moveWarning: 'Przeniesienie tej drukarki do innej lokalizacji zmieni, kto może jej używać: {{groups}}.',
+  },
+
+  // Users management
+  users: {
+    title: 'Zarządzanie użytkownikami',
+    subtitle: 'Zarządzaj użytkownikami i ich dostępem do twojej instancji Bambuddy',
+    backToSettings: 'Powrót do ustawień',
+    createUser: 'Utwórz użytkownika',
+    noPermission: 'Nie masz uprawnień dostępu do tej strony.',
+    admin: 'Administrator',
+    noGroups: 'Brak grup',
+    active: 'Aktywny',
+    inactive: 'Nieaktywny',
+    edit: 'Edytuj',
+    delete: 'Usuń',
+    system: 'Systemowy',
+    noGroupsAvailable: 'Brak dostępnych grup',
+    table: {
+      username: 'Nazwa użytkownika',
+      groups: 'Grupy',
+      status: 'Status',
+      actions: 'Akcje',
+    },
+    toast: {
+      created: 'Użytkownik został utworzony',
+      updated: 'Użytkownik został zaktualizowany',
+      deleted: 'Użytkownik został usunięty',
+      fillRequired: 'Wypełnij wszystkie wymagane pola',
+      passwordsDoNotMatch: 'Hasła nie są zgodne',
+      passwordTooShort: 'Hasło musi mieć co najmniej 6 znaków',
+      ldapProvisioned: 'Utworzono użytkownika LDAP "{{username}}"',
+    },
+    modal: {
+      createUser: 'Utwórz użytkownika',
+      editUser: 'Edytuj użytkownika',
+      cancel: 'Anuluj',
+      creating: 'Tworzenie...',
+      saving: 'Zapisywanie...',
+      saveChanges: 'Zapisz zmiany',
+      advancedAuthSubtitle: 'z zaawansowanym uwierzytelnianiem',
+      // LDAP manual provisioning (#1298)
+      tabsAriaLabel: 'Źródło użytkownika',
+      localTab: 'Lokalny',
+      ldapTab: 'LDAP',
+      ldapSearchLabel: 'Szukaj w katalogu',
+      ldapSearchPlaceholder: 'Wpisz nazwę użytkownika, imię lub e-mail...',
+      ldapMinChars: 'Wpisz co najmniej 2 znaki, aby wyszukać',
+      ldapTypeToSearch: 'Zacznij pisać, aby przeszukać katalog LDAP',
+      ldapSearching: 'Przeszukiwanie katalogu...',
+      ldapNoResults: 'Brak pasujących użytkowników w katalogu',
+      ldapSearchError: 'Wyszukiwanie w katalogu nie powiodło się. Sprawdź stan serwera LDAP.',
+      ldapAlreadyProvisioned: 'Już utworzony',
+      ldapSelectedLabel: 'Wybrany',
+      ldapProvision: 'Utwórz użytkownika',
+      ldapProvisioning: 'Tworzenie...',
+      ldapErrorProvision: 'Tworzenie użytkownika nie powiodło się. Sprawdź stan serwera LDAP i spróbuj ponownie.',
+    },
+    form: {
+      username: 'Nazwa użytkownika',
+      usernamePlaceholder: 'Wpisz nazwę użytkownika',
+      email: 'E-mail',
+      emailPlaceholder: 'user@example.com',
+      password: 'Hasło',
+      passwordPlaceholder: 'Wpisz hasło',
+      confirmPassword: 'Potwierdź hasło',
+      confirmPasswordPlaceholder: 'Potwierdź hasło',
+      newPasswordPlaceholder: 'Wpisz nowe hasło',
+      confirmNewPasswordPlaceholder: 'Potwierdź nowe hasło',
+      leaveBlankToKeep: 'pozostaw puste, aby zachować obecne',
+      groups: 'Grupy',
+      optional: 'opcjonalne',
+      autoGeneratedPassword: 'Bezpieczne hasło zostanie wygenerowane automatycznie i wysłane do użytkownika e-mailem.',
+      passwordManagedByAdvancedAuth: 'Hasłem zarządza zaawansowane uwierzytelnianie. Użyj "Resetuj hasło", aby wysłać użytkownikowi e-mailem link do ustawienia nowego hasła.',
+      resetPassword: 'Resetuj hasło',
+      resettingPassword: 'Resetowanie hasła...',
+      twoFaTitle: 'Uwierzytelnianie dwuskładnikowe',
+      twoFaHint: 'Dla użytkownika, który utracił dostęp do aplikacji uwierzytelniającej: usuwa jego aplikację uwierzytelniającą, kody e-mail i kody zapasowe oraz wylogowuje go ze wszystkich urządzeń. Po zalogowaniu może ponownie skonfigurować 2FA.',
+      twoFaDisable: 'Wyłącz 2FA',
+      twoFaYourPassword: 'Twoje hasło',
+      twoFaRemoved: 'Usunięto uwierzytelnianie dwuskładnikowe dla {{username}}',
+      twoFaNoneToRemove: '{{username}} nie miał uwierzytelniania dwuskładnikowego do usunięcia',
+      twoFaPasswordNeeded: 'Twoje konto ma hasło. Wpisz je, aby potwierdzić.',
+    },
+    deleteModal: {
+      title: 'Usuń użytkownika',
+      message: 'Czy na pewno chcesz usunąć tego użytkownika? Tej operacji nie można cofnąć.',
+      confirm: 'Usuń użytkownika',
+    },
+  },
+
+  // Stream overlay
+  streamOverlay: {
+    branding: {
+      title: 'Branding',
+      hint: 'Jedno wspólne logo dla tej instalacji. PNG lub WebP, do 2 MiB i 4 milionów pikseli. Zastąpienie lub usunięcie go wpływa na nakładki, które go używają.',
+      upload: 'Prześlij logo',
+      logo: 'Własne logo',
+      from: 'Kolor początkowy',
+      to: 'Kolor końcowy',
+      reset: 'Resetuj kolory',
+      failed: 'Nie udało się zapisać logo. Sprawdź format i rozmiar obrazu.',
+    },
+    title: 'Nakładka strumienia',
+    invalidPrinterId: 'Nieprawidłowy identyfikator drukarki',
+    cameraStream: 'Strumień kamery',
+    progress: 'Postęp',
+    eta: 'Zakończenie',
+    printerIdle: 'Drukarka jest bezczynna',
+    printerOffline: 'Drukarka offline',
+    layer: 'Warstwa',
+    remaining: 'Pozostało',
+    builder: {
+      backgroundTransparency: 'Przezroczystość tła',
+      backgroundTransparencyHint: 'Wygasza tylko ciemne tła. Tekst, logo i kamera pozostają widoczne.',
+      layout: 'Układ',
+      landscape: 'Poziomy',
+      portrait: 'Pionowy',
+      both: 'Oba',
+      orientationUrl: 'URL ({{orientation}})',
+      orientationPreview: 'Podgląd ({{orientation}})',
+      sourceDimensions: 'Źródło przeglądarki: {{width}} × {{height}} px',
+      artwork: 'Grafika',
+      artworkClassic: 'Klasyczna',
+      artworkV2: 'Wersja 2',
+      createToken: 'Utwórz token nakładki',
+      showToken: 'Pokaż token',
+      hideToken: 'Ukryj token',
+      credentialHint: 'Utwórz token powyżej, wpisz istniejący token lub zaimportuj URL nakładki. Skopiuj URL przed wyjściem: tokeny są przechowywane tylko w pamięci i nie można ich odzyskać z zapisanego skrótu.',
+      importUrl: 'Istniejący URL nakładki',
+      importAction: 'Importuj URL',
+      importHint: 'Zaimportuj URL lokalnie, aby użyć ponownie jego tokenu i ustawień na tym serwerze. Ustawienia, których Bambuddy nie rozpoznaje, są ignorowane.',
+      rememberedHint: 'Twoje wybory są zapamiętywane w tej przeglądarce. Token nie jest.',
+      resetChoices: 'Resetuj wybory',
+      importError: 'Wpisz prawidłowy URL nakładki HTTP(S) z dodatnim numerem drukarki, co najwyżej jednym tokenem i bez nazwy użytkownika ani hasła.',
+      manualToken: 'Token ręczny',
+      title: 'Nakładka do streamingu',
+      description: 'Zbuduj URL nakładki do streamingu — pełnoekranowego widoku kamery z nałożonymi danymi wydruku na żywo, dla OBS, wyświetlacza ściennego lub dowolnego źródła przeglądarki. Wybierz potrzebne pola i skopiuj URL.',
+      printer: 'Drukarka',
+      size: 'Rozmiar tekstu',
+      sizeSmall: 'Mały',
+      sizeMedium: 'Średni',
+      sizeLarge: 'Duży',
+      fps: 'Liczba klatek',
+      fpsHint: 'Kamery A1 i P1 osiągają maksymalnie około 5 fps, niezależnie od ustawienia.',
+      tokenWarning: 'Ten URL zawiera token — każdy, kto może go odczytać, może oglądać strumień i zobaczyć nazwę pliku. Unieważnij token, aby odciąć dostęp.',
+      fields: 'Pola do wyświetlenia',
+      fieldPrinter: 'Nazwa drukarki',
+      fieldModel: 'Model drukarki',
+      fieldFilename: 'Nazwa pliku',
+      fieldStatus: 'Status',
+      fieldProgress: 'Pasek postępu',
+      fieldLayers: 'Liczba warstw',
+      fieldEta: 'Pozostały czas i zakończenie',
+      fieldCamera: 'Obraz z kamery',
+      chamberHint: 'Temperatura komory pojawia się tylko w modelach z prawdziwym czujnikiem komory — drukarki P1 i A1 zgłaszają bezsensowną wartość, więc jest tam pomijana.',
+      urlTitle: 'URL nakładki',
+      open: 'Otwórz',
+      showPreview: 'Pokaż podgląd',
+      hidePreview: 'Ukryj podgląd',
+      previewTitle: 'Podgląd nakładki',
+    },
+    status: {
+      printing: 'Drukowanie',
+      paused: 'Wstrzymano',
+      finished: 'Ukończono',
+      failed: 'Nieudany',
+      idle: 'Bezczynna',
+      unknown: 'Nieznany',
+    },
+  },
+
+  // Profiles
+  profiles: {
+    title: 'Profile',
+    subtitle: 'Zarządzaj profilami slicera i kalibracjami pressure advance',
+    tabs: {
+      bambuCloud: 'Bambu Cloud',
+      orcaCloud: 'Orca Cloud',
+      local: 'Profile lokalne',
+      kprofiles: 'Profile K',
+    },
+    orcaCloud: {
+      connectedAs: 'Połączono jako',
+      connectedShort: 'Połączono z Orca Cloud',
+      logout: 'Rozłącz',
+      noLogoutPermission: 'Nie masz uprawnień do rozłączenia',
+      noConnectPermission: 'Nie masz uprawnień do połączenia z Orca Cloud',
+      retry: 'Ponów',
+      connectButton: 'Połącz z Orca Cloud',
+      connect: {
+        title: 'Połącz z Orca Cloud',
+        description: 'Zaloguj się na swoje konto Orca Cloud, aby synchronizować profile slicera z Bambuddy.',
+      },
+      device: {
+        title: 'Zatwierdź Bambuddy w Orca Cloud',
+        instruction: 'Otwórz Orca Cloud i zatwierdź ten kod. Bambuddy połączy się automatycznie po zatwierdzeniu.',
+        codeLabel: 'Twój kod parowania',
+        openButton: 'Otwórz stronę zatwierdzania Orca Cloud',
+        manualHint: 'Lub przejdź do {{url}} i wpisz powyższy kod.',
+        waiting: 'Oczekiwanie na zatwierdzenie…',
+        cancel: 'Anuluj',
+      },
+      profiles: {
+        title: 'Twoje profile Orca Cloud ({{count}})',
+        refresh: 'Odśwież',
+        empty: 'Na Twoim koncie Orca Cloud nie ma jeszcze żadnych profili.',
+      },
+      toast: {
+        disconnected: 'Rozłączono z Orca Cloud',
+      },
+      errors: {
+        startFailed: 'Nie udało się rozpocząć parowania z Orca Cloud.',
+        denied: 'Parowanie zostało odrzucone w Orca Cloud.',
+        expired: 'Kod parowania wygasł. Kliknij Połącz, aby spróbować ponownie.',
+        pollFailed: 'Utracono połączenie podczas oczekiwania na zatwierdzenie. Spróbuj ponownie.',
+      },
+    },
+    localProfiles: {
+      title: 'Profile lokalne',
+      subtitle: 'Importuj profile slicera z OrcaSlicer i zarządzaj nimi',
+      import: 'Importuj profile',
+      importDesc: 'Upuść tutaj pliki .bbscfg, .bbsflmt, .orca_filament, .zip lub .json',
+      importing: 'Importowanie...',
+      search: 'Szukaj profili lokalnych...',
+      noPresets: 'Brak profili lokalnych',
+      noSearchResults: 'Żaden profil nie pasuje do wyszukiwania',
+      badge: 'Lokalny',
+      edit: 'Edytuj',
+      delete: 'Usuń',
+      cancel: 'Anuluj',
+      deleteConfirmTitle: 'Usuń profil',
+      deleteConfirm: 'Czy na pewno chcesz usunąć ten profil? Tej operacji nie można cofnąć.',
+      source: 'Źródło',
+      inheritsFrom: 'Dziedziczy',
+      filamentType: 'Typ',
+      vendor: 'Producent',
+      compatiblePrinters: 'Drukarki',
+      nozzleTemp: 'Temp. dyszy',
+      cost: 'Koszt',
+      density: 'Gęstość',
+      pressureAdvance: 'Pressure Advance',
+      filament: 'Filament',
+      process: 'Proces',
+      printer: 'Drukarka',
+      toast: {
+        importSuccess: 'Zaimportowane profile: {{count}}',
+        importSkipped: 'Pominięte profile (duplikaty): {{count}}',
+        importError: 'Błędy podczas importu: {{count}}',
+        deleted: 'Profil usunięty',
+        updated: 'Profil zaktualizowany',
+      },
+    },
+    connectedAs: 'Połączono jako',
+    signInExpiredTitle: 'Sesja Bambu Cloud wygasła',
+    signInExpiredBody: 'Bambu Lab nie akceptuje już zapisanego tokenu. Zaloguj się ponownie, aby przywrócić profile w chmurze, importy z MakerWorld i sprawdzanie firmware.',
+    logout: 'Wyloguj',
+    noLogoutPermission: 'Nie masz uprawnień do wylogowania',
+    failedToLoad: 'Nie udało się wczytać profili',
+    retry: 'Ponów',
+    time: {
+      justNow: 'Przed chwilą',
+      minsAgo: '{{count}} min temu',
+      hoursAgo: '{{count}} godz. temu',
+      daysAgo: '{{count}} d. temu',
+    },
+    toast: {
+      loggedOut: 'Wylogowano',
+    },
+    login: {
+      title: 'Połącz z Bambu Cloud',
+      subtitle: 'Synchronizuj profile slicera między urządzeniami',
+      email: 'E-mail',
+      password: 'Hasło',
+      region: 'Region',
+      regionGlobal: 'Globalny',
+      regionChina: 'Chiny',
+      verificationCode: 'Kod weryfikacyjny',
+      totpCode: 'Kod z aplikacji uwierzytelniającej',
+      checkEmail: 'Sprawdź skrzynkę e-mail ({{email}}) – wysłaliśmy 6-cyfrowy kod',
+      enterTotpHint: 'Wpisz 6-cyfrowy kod z aplikacji uwierzytelniającej',
+      accessToken: 'Token dostępu',
+      accessTokenHint: 'Wklej swój token dostępu Bambu Cloud. Konta z regionu Chiny muszą korzystać z tej metody (konto powiązane z telefonem — logowanie e-mailem niedostępne). Sposób pobrania tokenu z ciasteczek MakerWorld opisano w wiki.',
+      back: 'Wstecz',
+      loginButton: 'Zaloguj się',
+      verifyButton: 'Zweryfikuj',
+      setTokenButton: 'Ustaw token',
+      useToken: 'Użyj zamiast tego tokenu dostępu',
+      captchaTitle: 'Bambu Cloud wymaga CAPTCHA',
+      captchaBody: 'Bambu weryfikuje Twoją sieć, zanim zaakceptuje logowanie, a na tę weryfikację nie da się odpowiedzieć z Bambuddy. Problemem nie jest Twój e-mail ani hasło. Blokada jest powiązana z Twoim publicznym adresem IP i zwykle znika sama w ciągu kilku godzin — wielokrotne ponawianie prób ją wydłuża. Aby zalogować się teraz, użyj tokenu dostępu z sesji przeglądarki.',
+      useEmail: 'Zaloguj się zamiast tego e-mailem',
+      toast: {
+        loggedIn: 'Zalogowano pomyślnie',
+        codeSent: 'Kod weryfikacyjny wysłano na Twój e-mail',
+        enterTotp: 'Wpisz kod z aplikacji uwierzytelniającej',
+        tokenSet: 'Token ustawiony pomyślnie',
+      },
+    },
+    presets: {
+      myPreset: 'Mój profil (edytowalny)',
+      duplicate: 'Duplikuj',
+      editable: 'Edytowalny',
+      failedToLoadDetails: 'Nie udało się wczytać szczegółów profilu',
+      deleteConfirm: 'Usunąć ten profil?',
+      deleteWarning: 'Profil „{{name}}” zostanie trwale usunięty z Bambu Cloud. Tej operacji nie można cofnąć.',
+      noDuplicatePermission: 'Nie masz uprawnień do duplikowania profili',
+      noEditPermission: 'Nie masz uprawnień do edycji profili',
+      noDeletePermission: 'Nie masz uprawnień do usuwania profili',
+      types: {
+        filament: 'Profil filamentu',
+        printer: 'Profil drukarki',
+        process: 'Profil procesu',
+      },
+      toast: {
+        deleted: 'Profil usunięty',
+        created: 'Profil utworzony',
+        updated: 'Profil zaktualizowany',
+        duplicated: 'Profil zduplikowany',
+        fieldAdded: 'Dodano pole „{{key}}”',
+        exported: 'Profil wyeksportowany',
+      },
+      baseLabel: 'Bazowy: {{name}}',
+      currentLabel: 'Bieżący: {{name}}',
+      newPreset: 'Nowy profil',
+      editPreset: 'Edytuj profil',
+      duplicatePreset: 'Duplikuj profil',
+      createNewPreset: 'Utwórz nowy profil',
+      customizeSettings: 'Dostosuj ustawienia nowego profilu',
+      compareWithBase: 'Porównaj z profilem bazowym',
+      compare: 'Porównaj',
+      // CreatePresetModal - Basic Info
+      basePreset: 'Profil bazowy',
+      selectBasePreset: 'Wybierz profil bazowy...',
+      presetName: 'Nazwa profilu',
+      myCustomPreset: 'Mój własny profil',
+      inheritsFrom: 'Dziedziczy z',
+      dropJsonToImport: 'Upuść JSON, aby zaimportować',
+      // CreatePresetModal - Tabs
+      tabs: {
+        common: 'Podstawowe',
+        allFields: 'Wszystkie pola',
+      },
+      // CreatePresetModal - All Fields Tab
+      availableFields: 'Dostępne pola',
+      searchFieldsPlaceholder: 'Szukaj pól...',
+      noMatchingFields: 'Brak pasujących pól',
+      allFieldsAdded: 'Dodano wszystkie pola',
+      addCustomField: 'Dodaj własne pole',
+      yourOverrides: 'Twoje nadpisania',
+      noOverridesYet: 'Brak nadpisań',
+      clickFieldsToAdd: 'Kliknij pola po lewej, aby je dodać',
+      saveAsTemplate: 'Zapisz jako szablon',
+      jsonTip: 'Wskazówka: przeciągnij i upuść plik .json w dowolnym miejscu tego okna, aby zaimportować ustawienia',
+    },
+    cloudView: {
+      searchPlaceholder: 'Szukaj profili...',
+      templates: 'Szablony',
+      refresh: 'Odśwież',
+      newPreset: 'Nowy profil',
+      clearFilters: 'Wyczyść filtry',
+      // Compare mode
+      compareMode: 'Tryb porównania',
+      selectAnotherPreset: 'Wybierz inny profil typu {{type}}',
+      clickTwoPresets: 'Kliknij dwa profile tego samego typu, aby je porównać',
+      selectFirst: '1. Wybierz pierwszy',
+      selectSecond: '2. Wybierz drugi',
+      compareNow: 'Porównaj teraz',
+      // Status row
+      lastSynced: 'Ostatnia synchronizacja:',
+      showingCount: 'Wyświetlono {{showing}} z {{total}} profili',
+      noPresetsFound: 'Nie znaleziono profili',
+      // Column headers
+      columns: {
+        filament: 'Filament',
+        process: 'Proces',
+        printer: 'Drukarka',
+      },
+      noFilamentPresets: 'Brak profili filamentu',
+      noProcessPresets: 'Brak profili procesu',
+      noPrinterPresets: 'Brak profili drukarki',
+      // Filters
+      filters: {
+        type: 'Typ',
+        owner: 'Właściciel',
+        printer: 'Drukarka',
+        nozzle: 'Dysza',
+        filament: 'Filament',
+        layer: 'Warstwa',
+        all: 'Wszystkie',
+        myPresets: 'Moje profile',
+        builtIn: 'Wbudowane',
+        process: 'Proces',
+      },
+      // Permissions
+      noTemplatesPermission: 'Nie masz uprawnień do zarządzania szablonami',
+      noRefreshPermission: 'Nie masz uprawnień do odświeżania profili',
+      noCreatePermission: 'Nie masz uprawnień do tworzenia profili',
+    },
+    templates: {
+      title: 'Szybkie szablony',
+      noTemplates: 'Brak szablonów',
+      createFirst: 'Twórz szablony w edytorze profili',
+      typeFilter: 'Typ:',
+      deleteTitle: 'Usuń szablon',
+      deleteWarning: 'Tej operacji nie można cofnąć',
+      deleteConfirm: 'Czy na pewno chcesz usunąć „{{name}}”?',
+      namePlaceholder: 'Nazwa szablonu',
+      descriptionPlaceholder: 'Opis',
+      settingsJson: 'Ustawienia (JSON)',
+      fieldsCount: 'Pola: {{count}}',
+      shownInModals: 'Widoczny w oknach',
+      hiddenInModals: 'Ukryty w oknach',
+      apply: 'Zastosuj',
+      toast: {
+        deleted: 'Szablon usunięty',
+        updated: 'Szablon zaktualizowany',
+        created: 'Szablon utworzony',
+        applied: 'Szablon zastosowany',
+      },
+    },
+  },
+
+  // Support/Debug
+  support: {
+    debugLoggingActive: 'Logowanie debugowania jest aktywne',
+    manageLogs: 'Zarządzaj',
+    collectItem7: 'Łączność drukarek i wersje firmware',
+    collectItem8: 'Stan integracji (Spoolman, MQTT, HA)',
+    collectItem9: 'Interfejsy sieciowe (tylko podsieci)',
+    collectItem10: 'Wersje pakietów Python',
+    collectItem11: 'Kontrole stanu bazy danych',
+    collectItem12: 'Szczegóły środowiska Docker',
+    bundleGenerating: 'Generowanie pakietu...',
+    bundleStepConnection: 'Sprawdzanie łączności drukarek',
+    bundleStepVirtualPrinters: 'Sprawdzanie konfiguracji wirtualnych drukarek',
+    bundleStepLogScan: 'Skanowanie ostatnich logów pod kątem znanych problemów',
+    bundleStepBuild: 'Tworzenie pliku ZIP pakietu wsparcia',
+  },
+
+  // File manager
+  fileManager: {
+    combine: {
+      action: 'Połącz w 3MF',
+      tooltip: 'Połącz wybrane pliki STL w jeden 3MF, aby można je było pociąć na jednej płycie',
+      title: 'Połącz w 3MF',
+      description: 'Tworzy jeden plik 3MF ze wszystkimi poniższymi modelami, gotowy do cięcia na jednej płycie. Włącz automatyczne rozmieszczanie podczas cięcia, aby rozłożyć je na stole.',
+      nameLabel: 'Nazwa pliku',
+      defaultName: '{{name}} + {{count}} więcej',
+      model: 'Model',
+      copies: 'Kopie',
+      copiesFor: 'Kopie pliku {{filename}}',
+      total: 'Obiekty na płycie: {{count}}',
+      tooMany: 'Maksymalna liczba obiektów na płycie: {{max}}',
+      sliceNext: 'Otwórz slicer po zakończeniu',
+      submit: 'Połącz',
+      done: 'Utworzono {{filename}} (obiekty: {{count}})',
+    },
+    variants: {
+      badge: 'Wersje: {{count}}',
+      groupAction: 'Grupuj jako wersje',
+      groupTooltip: 'Oznacz te pliki jako to samo zadanie pocięte dla różnych drukarek',
+      grouped: 'Zgrupowano pliki jako wersje: {{count}}',
+      printAlternatives: 'Drukuj (alternatywy: {{count}})',
+    },
+    title: 'Menedżer plików',
+    subtitle: 'Organizuj pliki do druku i zarządzaj nimi',
+    uploadFiles: 'Prześlij pliki',
+    newFolder: 'Nowy folder',
+    folderName: 'Nazwa folderu',
+    folderNamePlaceholder: 'np. Części funkcjonalne',
+    renameFile: 'Zmień nazwę pliku',
+    renameFolder: 'Zmień nazwę folderu',
+    invalidFilenameChar: 'Znak „{{char}}” jest niedozwolony w nazwach plików do druku. Karta SD drukarki odrzuca: < > : " / \\ | ? *',
+    moveFiles: 'Przenieś pliki ({{count}})',
+    rootNoFolder: 'Katalog główny (bez folderu)',
+    moveFolder: 'Przenieś folder…',
+    moveFolderTo: 'Przenieś „{{name}}” do',
+    moveToRoot: 'Katalog główny',
+    moveFolderInvalidTarget: 'Folderu nie można przenieść do niego samego, jego podfolderów ani do folderu zewnętrznego',
+    current: 'bieżący',
+    linkFolder: 'Powiąż folder',
+    linkFolderDescription: 'Powiąż „{{name}}” z projektem lub archiwum, aby mieć do niego szybki dostęp.',
+    project: 'Projekt',
+    archive: 'Archiwum',
+    noProjectsFound: 'Nie znaleziono projektów',
+    noArchivesFound: 'Nie znaleziono archiwów',
+    unlink: 'Odłącz',
+    link: 'Powiąż',
+    dragDropFiles: 'Przeciągnij i upuść pliki tutaj',
+    dropFilesHere: 'Upuść pliki tutaj',
+    releaseToUpload: 'Puść, aby przesłać',
+    orClickToBrowse: 'lub kliknij, aby wybrać',
+    allFileTypesSupported: 'Obsługiwane są wszystkie typy plików. Pliki ZIP zostaną rozpakowane.',
+    zipFilesDetected: 'Wykryto pliki ZIP',
+    zipExtractOptions: 'Pliki ZIP zostaną rozpakowane. Wybierz, jak traktować strukturę folderów:',
+    preserveZipStructure: 'Zachowaj strukturę folderów z ZIP',
+    createFolderFromZip: 'Utwórz folder z nazwy pliku ZIP',
+    stlThumbnailGeneration: 'Generowanie miniatur STL',
+    zipMayContainStl: 'Pliki ZIP mogą zawierać pliki STL. Miniatury można wygenerować podczas rozpakowywania.',
+    thumbnailsCanBeGenerated: 'Dla plików STL można wygenerować miniatury. Przetwarzanie dużych modeli może potrwać dłużej.',
+    generateThumbnailsForStl: 'Generuj miniatury dla plików STL',
+    threemfDetected: 'Wykryto pliki 3MF',
+    threemfExtractionInfo: 'Model drukarki, materiał, kolor i ustawienia druku zostaną automatycznie odczytane z plików 3MF.',
+    willBeExtracted: 'Zostanie rozpakowany',
+    filesExtracted: 'Rozpakowane pliki: {{count}}',
+    uploadComplete: 'Przesyłanie zakończone: udane {{succeeded}}',
+    uploadFailed: 'Przesyłanie nie powiodło się',
+    zipFilesFailed: 'Nieudane pliki: {{count}}',
+    uploading: 'Przesyłanie...',
+    changeLink: 'Zmień powiązanie...',
+    linkTo: 'Powiąż z...',
+    linkToProjectOrArchive: 'Powiąż z projektem lub archiwum',
+    generateThumbnail: 'Generuj miniaturę',
+    generateThumbnails: 'Generuj miniatury',
+    generateThumbnailsForMissing: 'Generuj brakujące miniatury dla plików STL i PDF',
+    gridView: 'Widok siatki',
+    listView: 'Widok listy',
+    columnsView: 'Widok kolumn',
+    lowDiskSpaceWarning: 'Ostrzeżenie o małej ilości miejsca na dysku',
+    lowDiskSpaceDetails: 'Wolne tylko {{free}} z {{total}}. Próg ustawiono w ustawieniach na {{threshold}} GB.',
+    files: 'Pliki',
+    folders: 'Foldery',
+    size: 'Rozmiar',
+    free: 'Wolne',
+    allFiles: 'Wszystkie pliki',
+    allExternal: 'Zewnętrzne',
+    externalIsEmpty: 'Brak plików zewnętrznych',
+    externalEmptyDescription: 'Tutaj pojawią się pliki z powiązanych folderów zewnętrznych.',
+    wrap: 'Zawijaj',
+    enableTextWrapping: 'Włącz zawijanie tekstu',
+    disableTextWrapping: 'Wyłącz zawijanie tekstu',
+    collapse: 'Zwiń',
+    collapseFoldersByDefault: 'Domyślnie zwijaj foldery',
+    expandFoldersByDefault: 'Domyślnie rozwijaj foldery',
+    folderSort: 'Sortuj foldery',
+    folderSortByName: 'Według nazwy',
+    folderSortByActivity: 'Według ostatniej aktywności',
+    dragToResizeTooltip: 'Przeciągnij, aby zmienić rozmiar, kliknij dwukrotnie, aby zresetować',
+    searchFiles: 'Szukaj plików...',
+    searchSubfoldersHint: 'Łącznie z podfolderami',
+    readme: {
+      truncated: 'Skrócono',
+      show: 'Pokaż README',
+      hide: 'Ukryj README',
+      label: 'README',
+    },
+    tags: {
+      title: 'Tagi',
+      subtitle: 'Oznaczaj pliki do filtrowania przekrojowego — zabawki, bezpieczne dla dzieci, tylko PETG, cokolwiek.',
+      manage: 'Tagi',
+      manageTitle: 'Zarządzaj katalogiem tagów',
+      add: 'Nowy tag',
+      edit: 'Zmień nazwę tagu',
+      name: 'Nazwa',
+      fileCount: 'Pliki',
+      empty: 'Brak tagów. Utwórz pierwszy, aby zacząć oznaczać pliki.',
+      noMatches: 'Brak pasujących tagów.',
+      createPlaceholder: 'np. zabawki, dla-dzieci, petg',
+      createButton: 'Utwórz',
+      nameRequired: 'Nazwa jest wymagana.',
+      searchPlaceholder: 'Filtruj tagi...',
+      created: 'Tag utworzony.',
+      updated: 'Zmieniono nazwę tagu.',
+      deleted: 'Tag usunięty.',
+      saveFailed: 'Nie udało się zapisać tagu.',
+      deleteFailed: 'Nie udało się usunąć tagu.',
+      applyFailed: 'Nie udało się zastosować tagów.',
+      applyAdd: 'Dodaj tagi',
+      applyRemove: 'Usuń tagi',
+      applyAddSuccess: 'Dodano tagi ({{count}}) do plików ({{files}}).',
+      applyRemoveSuccess: 'Usunięto tagi ({{count}}) z plików ({{files}}).',
+      actionAdd: 'Dodaj do wybranych plików',
+      actionRemove: 'Usuń z wybranych plików',
+      tagAction: 'Taguj',
+      bulkTitle: 'Taguj wybrane pliki ({{count}})',
+      bulkTooltip: 'Dodaj lub usuń tagi na każdym wybranym pliku.',
+      noPermission: 'Nie masz uprawnień do tagowania plików.',
+      filterLabel: 'Filtrowanie według:',
+      clearAll: 'Wyczyść wszystko',
+      searchTags: 'Szukaj tagów',
+      noTagMatches: 'Brak pasujących tagów',
+      showAllTags: 'Pokaż wszystkie ({{count}})',
+      showFewerTags: 'Pokaż mniej',
+      confirmDelete: 'Usunąć tag „{{name}}”?',
+      confirmDeleteMessage: 'Tag zostanie usunięty z katalogu. Pliki zachowają pozostałe tagi.',
+      confirmDeleteInUseMessage: 'Ten tag jest przypisany do plików ({{count}}). Usunięcie zdejmie go z nich wszystkich; same pliki pozostaną nietknięte.',
+      editAria: 'Edytuj {{name}}',
+      deleteAria: 'Usuń {{name}}',
+    },
+    allTypes: 'Wszystkie typy',
+    prints: 'Wydruki',
+    ascending: 'Rosnąco',
+    descending: 'Malejąco',
+    showModified: 'Pokaż daty modyfikacji',
+    hideModified: 'Ukryj daty modyfikacji',
+    lastModified: 'Ostatnia modyfikacja',
+    lastActivity: 'Ostatnia aktywność',
+    resultsCount: '{{showing}} z {{total}} plików',
+    selectAll: 'Zaznacz wszystko',
+    deselectAll: 'Odznacz wszystko',
+    selected: 'Zaznaczone: {{count}}',
+    adding: 'Dodawanie...',
+    loadingFiles: 'Wczytywanie plików...',
+    folderIsEmpty: 'Folder jest pusty',
+    noFilesOutsideFolders: 'Brak plików poza folderami',
+    noFilesYet: 'Brak plików',
+    highlightedFileNotFound: 'Nie znaleziono pliku – mógł zostać usunięty lub nie masz do niego dostępu',
+    folderEmptyDescription: 'Prześlij pliki lub przenieś je do tego folderu, aby zacząć.',
+    noFilesDescription: 'Prześlij pliki, aby zacząć porządkować pliki związane z drukiem.',
+    noMatchingFiles: 'Brak pasujących plików',
+    noMatchingFilesDescription: 'Żaden plik nie pasuje do bieżącego wyszukiwania lub filtrów.',
+    clearFilters: 'Wyczyść filtry',
+    printedCount: 'Wydrukowano {{count}}x',
+    uploadedBy: 'Przesłane przez',
+    deleteFolder: 'Usuń folder',
+    deleteFile: 'Usuń plik',
+    deleteFilesCount: 'Usuń pliki ({{count}})',
+    deleteFolderConfirm: 'Czy na pewno chcesz usunąć ten folder? Wszystkie pliki w nim również zostaną usunięte.',
+    deleteFileConfirm: 'Czy na pewno chcesz usunąć ten plik?',
+    deleteFilesConfirm: 'Czy na pewno chcesz usunąć wybrane pliki ({{count}})? Tej operacji nie można cofnąć.',
+    deleting: 'Usuwanie...',
+    noPermissionRenameFolder: 'Nie masz uprawnień do zmiany nazw folderów',
+    noPermissionLinkFolder: 'Nie masz uprawnień do powiązywania folderów',
+    noPermissionDeleteFolder: 'Nie masz uprawnień do usuwania folderów',
+    onlyOwnFoldersDeletable: 'Możesz usuwać tylko własne foldery, gdy cała ich zawartość należy do Ciebie, lub puste foldery bez właściciela',
+    shareFolder: 'Udostępnij wszystkim',
+    unshareFolder: 'Zatrzymaj udostępnianie',
+    shareFolderHint: 'Udostępnione foldery są widoczne dla każdego użytkownika, który może dodawać do nich pliki i podfoldery',
+    sharedFolder: 'Udostępniony wszystkim',
+    folderNotWritable: 'Możesz dodawać tylko do własnych folderów i folderów udostępnionych wszystkim',
+    noPermissionPrint: 'Nie masz uprawnień do drukowania',
+    noPermissionAddToQueue: 'Nie masz uprawnień do dodawania do kolejki',
+    noPermissionSlice: 'Nie masz uprawnień do cięcia plików',
+    noPermissionDownload: 'Nie masz uprawnień do pobierania plików',
+    noPermissionPreview: 'Nie masz uprawnień do podglądu plików',
+    preview3d: 'Podgląd 3D',
+    // In-app document previews (#2976): PDF and spreadsheet files.
+    preview: {
+      open: 'Podgląd',
+      error: 'Nie można wyświetlić podglądu tego pliku.',
+      tooLarge: 'Plik jest za duży do podglądu ({{size}}).',
+      page: 'Strona {{current}} z {{total}}',
+      prevPage: 'Poprzednia strona',
+      nextPage: 'Następna strona',
+      zoomIn: 'Powiększ',
+      zoomOut: 'Pomniejsz',
+      resetZoom: 'Resetuj powiększenie',
+      fullscreen: 'Pełny ekran',
+      exitFullscreen: 'Zamknij pełny ekran',
+      emptySheet: 'Ten arkusz jest pusty',
+      truncatedRows: 'Wyświetlono pierwsze wiersze: {{shown}} z {{total}}',
+      truncatedCols: 'Wyświetlono pierwsze kolumny: {{shown}} z {{total}}',
+    },
+    details: {
+      title: 'Szczegóły pliku',
+      size: 'Rozmiar',
+      type: 'Typ',
+      printName: 'Nazwa wydruku',
+      printTime: 'Czas druku',
+      filament: 'Filament',
+      slicedFor: 'Pocięte dla',
+      source: 'Źródło',
+      created: 'Utworzono',
+      modified: 'Zmodyfikowano',
+      notes: 'Notatki',
+      notesPlaceholder: 'Ustawienia druku, wskazówki, co się sprawdziło...',
+      externalLink: 'Link zewnętrzny',
+      externalLinkPlaceholder: 'https://printables.com/model/...',
+      openLink: 'Otwórz link',
+      photos: 'Zdjęcia',
+      addPhoto: 'Dodaj zdjęcie',
+      noPhotos: 'Brak zdjęć',
+      deletePhoto: 'Usuń zdjęcie',
+      photoCount_one: '{{count}} zdjęcie',
+      photoCount_other: 'Zdjęcia: {{count}}',
+      hasNotes: 'Ma notatki',
+      save: 'Zapisz',
+      saved: 'Zapisano szczegóły pliku',
+      saveFailed: 'Nie udało się zapisać szczegółów pliku',
+      uploadFailed: 'Nie udało się przesłać zdjęcia',
+      deleteFailed: 'Nie udało się usunąć zdjęcia',
+    },
+    noPermissionRenameFile: 'Nie masz uprawnień do zmiany nazwy tego pliku',
+    noPermissionGenerateThumbnail: 'Nie masz uprawnień do generowania miniatur',
+    noPermissionDeleteFile: 'Nie masz uprawnień do usunięcia tego pliku',
+    noPermissionCreateFolder: 'Nie masz uprawnień do tworzenia folderów',
+    noPermissionUpload: 'Nie masz uprawnień do przesyłania plików',
+    noPermissionMoveFiles: 'Nie masz uprawnień do przenoszenia plików',
+    noPermissionMoveFolder: 'Nie masz uprawnień do przenoszenia folderów',
+    noPermissionDeleteFiles: 'Nie masz uprawnień do usuwania plików',
+    // External folder
+    linkExternal: 'Powiąż zewnętrzny',
+    linkExternalFolder: 'Powiąż folder zewnętrzny',
+    linkExternalFolderDescription: 'Zamontuj katalog hosta (NAS, USB, udział sieciowy) w Menedżerze plików. Pliki nie są kopiowane — dostęp do nich odbywa się bezpośrednio w oryginalnej ścieżce.',
+    externalFolderNamePlaceholder: 'np. Wydruki NAS',
+    externalPath: 'Ścieżka hosta',
+    externalPathHelp: 'Bezwzględna ścieżka do katalogu na hoście Docker. Musi być zamontowana (bind mount) w kontenerze.',
+    readOnly: 'Tylko do odczytu',
+    readOnlyHelp: 'blokuje przesyłanie i usuwanie',
+    showHiddenFiles: 'Pokaż ukryte pliki (dotfiles)',
+    externalFolder: 'Folder zewnętrzny',
+    scanFolder: 'Skanuj',
+    toast: {
+      folderCreated: 'Folder utworzony',
+      openInSlicerFailed: 'Nie udało się otworzyć w slicerze',
+      folderDeleted: 'Folder usunięty',
+      fileDeleted: 'Plik usunięty',
+      filesDeleted: 'Usunięte pliki: {{count}}',
+      filesMoved: 'Pliki przeniesione',
+      folderMoved: 'Folder przeniesiony',
+      folderLinked: 'Folder powiązany',
+      folderUnlinked: 'Folder odłączony',
+      externalFolderLinked: 'Folder zewnętrzny powiązany i przeskanowany',
+      folderScanned: 'Skanowanie zakończone: dodano {{added}}, usunięto {{removed}}',
+      addedToQueue: 'Dodane do kolejki pliki: {{count}}',
+      addedToQueuePartial: 'Dodane pliki: {{added}}, nieudane: {{failed}}',
+      failedToAddToQueue: 'Nie udało się dodać plików: {{error}}',
+      fileRenamed: 'Zmieniono nazwę pliku',
+      folderRenamed: 'Zmieniono nazwę folderu',
+      folderShared: 'Folder udostępniony wszystkim',
+      folderUnshared: 'Folder nie jest już udostępniany',
+      thumbnailsGenerated: 'Wygenerowane miniatury: {{count}}',
+      thumbnailsGeneratedPartial: 'Wygenerowane miniatury: {{succeeded}}, nieudane: {{failed}}',
+      noStlMissingThumbnails: 'Brak plików STL lub PDF bez miniatur',
+      failedToGenerateThumbnails: 'Nie udało się wygenerować miniatur: {{error}}',
+      thumbnailGenerated: 'Miniatura wygenerowana',
+      failedToGenerateThumbnail: 'Nie udało się wygenerować miniatury: {{error}}',
+    },
+  },
+
+  // Projects
+  projects: {
+    parentLabel: 'Projekt nadrzędny',
+    parentNone: 'Brak (projekt najwyższego poziomu)',
+    parentHint: 'Zagnieźdź ten projekt w innym, aby jego dane sumowały się w projekcie głównym',
+    partOf: 'Część projektu {{name}}',
+    subProjectCount: 'Podprojekty: {{count}}',
+    subProjectsOf: 'Podprojekty projektu {{name}}',
+    collapseSubProjects: 'Zwiń podprojekty',
+    expandSubProjects: 'Rozwiń podprojekty',
+    title: 'Projekty',
+    subtitle: 'Organizuj i śledź swoje projekty druku 3D',
+    newProject: 'Nowy projekt',
+    editProject: 'Edytuj projekt',
+    deleteProject: 'Usuń projekt',
+    projectName: 'Nazwa projektu',
+    description: 'Opis',
+    noProjects: 'Brak projektów',
+    noProjectsFiltered: 'Brak projektów o stanie: {{status}}',
+    noProjectsFilteredHelp: "Nie masz żadnych projektów o stanie: {{status}}. Projekty pojawią się tutaj, gdy zmieni się ich stan.",
+    createFirst: 'Utwórz pierwszy projekt, aby porządkować powiązane wydruki, śledzić postępy i zarządzać swoimi konstrukcjami.',
+    createFirstButton: 'Utwórz pierwszy projekt',
+    create: 'Utwórz',
+    files: 'Pliki',
+    prints: 'Wydruki',
+    plates: 'płyty',
+    parts: 'części',
+    lastModified: 'Ostatnia modyfikacja',
+    deleteConfirm: 'Czy na pewno chcesz usunąć ten projekt? Archiwa i pozycje kolejki zostaną odłączone, ale nie usunięte.',
+    addFiles: 'Dodaj pliki',
+    removeFile: 'Usuń plik',
+    viewDetails: 'Pokaż szczegóły',
+    // Modal fields
+    namePlaceholder: 'np. Budowa Voron 2.4',
+    descriptionPlaceholder: 'Opcjonalny opis...',
+    urlLabel: 'URL',
+    urlPlaceholder: 'https://makerworld.com/...',
+    urlInvalid: 'URL musi zaczynać się od http:// lub https://',
+    openExternalUrl: 'Otwórz URL projektu',
+    coverImageLabel: 'Zdjęcie okładki',
+    coverImageAlt: 'Zdjęcie okładki projektu',
+    coverImageUpload: 'Prześlij',
+    coverImageReplace: 'Zamień',
+    coverImageRemove: 'Usuń',
+    color: 'Kolor',
+    targetPlates: 'Docelowa liczba płyt',
+    targetPlatesPlaceholder: 'np. 25',
+    targetPlatesHelp: 'Liczba zadań druku',
+    targetParts: 'Docelowa liczba części',
+    targetPartsPlaceholder: 'np. 150',
+    targetPartsHelp: 'Łączna liczba potrzebnych obiektów',
+    targetSets: 'Kopie na plik',
+    targetSetsPlaceholder: 'np. 10',
+    targetSetsHelp: 'Ile razy należy wydrukować każdy plik do druku',
+    tagsLabel: 'Tagi (oddzielone przecinkami)',
+    tagsPlaceholder: 'np. voron, funkcjonalne, prezent',
+    dueDate: 'Termin',
+    priority: 'Priorytet',
+    priorityLow: 'Niski',
+    priorityNormal: 'Normalny',
+    priorityHigh: 'Wysoki',
+    priorityUrgent: 'Pilny',
+    // Status
+    statusActive: 'Aktywny',
+    statusCompleted: 'Ukończony',
+    statusArchived: 'Zarchiwizowany',
+    done: 'Gotowe',
+    completed: 'ukończone',
+    failed: 'nieudane',
+    inQueue: 'w kolejce',
+    noPrintsYet: 'Brak wydruków',
+    // Footer stats
+    printJobs: 'Zadania druku (płyty)',
+    partsPrinted: 'Wydrukowane części',
+    failedParts: 'Nieudane części',
+    // Actions
+    import: 'Importuj',
+    export: 'Eksportuj',
+    importProject: 'Importuj projekt',
+    exportAll: 'Eksportuj wszystkie projekty',
+    loading: 'Wczytywanie projektów...',
+    // Permissions
+    noEditPermission: 'Nie masz uprawnień do edycji projektów',
+    noDeletePermission: 'Nie masz uprawnień do usuwania projektów',
+    noCreatePermission: 'Nie masz uprawnień do tworzenia projektów',
+    noImportPermission: 'Nie masz uprawnień do importowania projektów',
+    noExportPermission: 'Nie masz uprawnień do eksportowania projektów',
+    // Toast
+    toast: {
+      created: 'Projekt utworzony',
+      updated: 'Projekt zaktualizowany',
+      deleted: 'Projekt usunięty',
+      imported: 'Projekt zaimportowany',
+      multipleImported: 'Zaimportowane projekty: {{count}}',
+      importFailed: 'Import nie powiódł się',
+      exported: 'Projekty wyeksportowane (tylko metadane)',
+    },
+  },
+
+  // Project detail page
+  projectDetail: {
+    notFound: 'Nie znaleziono projektu',
+    backToProjects: 'Powrót do projektów',
+    export: 'Eksportuj',
+    exportProject: 'Eksportuj projekt',
+    noExportPermission: 'Nie masz uprawnień do eksportowania projektów',
+    noEditPermission: 'Nie masz uprawnień do edytowania projektów',
+    partOf: 'Część:',
+    priorityLabel: 'Priorytet:',
+    noPrints: 'Brak wydruków w tym projekcie',
+    status: {
+      active: 'Aktywny',
+      completed: 'Ukończony',
+      archived: 'Zarchiwizowany',
+    },
+    priority: {
+      low: 'Niski',
+      normal: 'Normalny',
+      high: 'Wysoki',
+      urgent: 'Pilny',
+    },
+    dueDate: {
+      overdue: 'Po terminie',
+      today: 'Termin dzisiaj',
+      daysLeft: 'Pozostało dni: {{count}}',
+    },
+    progress: {
+      platesProgress: 'Postęp płyt',
+      partsProgress: 'Postęp części',
+      setsProgress: 'Kompletne zestawy',
+      sets: 'zestawy',
+      setsHint: 'Zestaw jest kompletny, gdy każdy plik do druku osiągnie tę liczbę',
+      printJobs: 'zadania druku',
+      parts: 'części',
+      percentComplete: 'Ukończono {{percent}}%',
+      remaining: 'Pozostało: {{count}}',
+    },
+    stats: {
+      printJobs: 'Zadania druku',
+      total: 'łącznie',
+      failed: 'Nieudane: {{count}}',
+      partsPrinted: 'Wydrukowane części: {{count}}',
+      printTime: 'Czas druku',
+      filamentUsed: 'Zużyty filament',
+    },
+    cost: {
+      title: 'Śledzenie kosztów',
+      filamentCost: 'Koszt filamentu',
+      energy: 'Energia',
+      totalCost: 'Szacowany koszt',
+      total: 'Łącznie',
+      includesBom: 'wraz z BOM',
+      wear: 'Zużycie drukarki',
+      budget: 'Budżet',
+      remaining: 'Pozostało',
+    },
+    subProjects: {
+      title: 'Podprojekty ({{count}})',
+      jobs: 'Zadania: {{count}}',
+    },
+    rollup: {
+      title: 'Wraz z podprojektami: {{count}}',
+      progress: 'Postęp ogólny',
+      percentComplete: 'Ukończono {{percent}}%',
+    },
+    notes: {
+      title: 'Notatki',
+      noEditPermission: 'Nie masz uprawnień do edytowania notatek',
+      placeholder: 'Dodaj notatki o tym projekcie...',
+      empty: 'Brak notatek. Kliknij Edytuj, aby je dodać.',
+    },
+    files: {
+      title: 'Pliki',
+      linkFolders: 'Połącz foldery z menedżera plików',
+      forQuickAccess: 'z tym projektem, aby mieć do nich szybki dostęp.',
+      fileCount: 'Pliki: {{count}}',
+      empty: 'Brak połączonych folderów. Przejdź do menedżera plików i połącz folder z tym projektem.',
+      printedCount: 'Wydrukowano razy: {{count}}',
+      progressTooltip: 'Ukończone wydruki: {{done}} z {{target}}',
+      noFiles: 'Brak plików w tym folderze.',
+    },
+    bom: {
+      title: 'Lista materiałów',
+      acquired: 'Pozyskano {{completed}}/{{total}}',
+      showAll: 'Pokaż wszystko',
+      hideDone: 'Ukryj gotowe',
+      addPart: 'Dodaj część',
+      noAddPermission: 'Nie masz uprawnień do dodawania części',
+      partNamePlaceholder: 'Nazwa części (np. śruby M3x8)',
+      partName: 'Nazwa części',
+      qty: 'Ilość',
+      price: 'Cena ({{currency}})',
+      sourcingUrlPlaceholder: 'URL źródła zakupu (opcjonalnie)',
+      remarksPlaceholder: 'Uwagi (opcjonalnie)',
+      deletePart: 'Usuń część',
+      deleteConfirm: 'Czy na pewno chcesz usunąć „{{name}}”?',
+      noUpdatePermission: 'Nie masz uprawnień do aktualizowania części',
+      noEditPermission: 'Nie masz uprawnień do edytowania części',
+      noDeletePermission: 'Nie masz uprawnień do usuwania części',
+      totalCost: 'Koszt łączny:',
+      empty: 'Brak części na liście materiałów. Dodaj elementy złączne, elektronikę lub inne komponenty, aby śledzić, co trzeba kupić.',
+    },
+    timeline: {
+      title: 'Oś czasu aktywności',
+      empty: 'Brak aktywności.',
+    },
+    template: {
+      saveAsTemplate: 'Zapisz jako szablon',
+      noCreatePermission: 'Nie masz uprawnień do tworzenia szablonów',
+    },
+    queue: {
+      title: 'Kolejka',
+      viewAll: 'Pokaż wszystko',
+      printing: 'Drukowane: {{count}}',
+      queued: 'W kolejce: {{count}}',
+    },
+    prints: {
+      title: 'Wydruki ({{count}})',
+    },
+    toast: {
+      projectUpdated: 'Zaktualizowano projekt',
+      partAdded: 'Dodano część',
+      partRemoved: 'Usunięto część',
+      exportFailed: 'Eksport nie powiódł się',
+      projectExported: 'Wyeksportowano projekt',
+      templateCreated: 'Utworzono szablon',
+    },
+  },
+
+  // System info
+  system: {
+    title: 'Informacje o systemie',
+    version: 'Wersja',
+    uptime: 'Czas działania',
+    cpuUsage: 'Użycie CPU',
+    memoryUsage: 'Użycie pamięci',
+    diskUsage: 'Użycie dysku',
+    networkInfo: 'Informacje o sieci',
+    logs: 'Logi',
+    debugMode: 'Tryb debugowania',
+    enableDebug: 'Włącz logowanie debugowania',
+    disableDebug: 'Wyłącz logowanie debugowania',
+    downloadLogs: 'Pobierz logi',
+    clearLogs: 'Wyczyść logi',
+    dockerInfo: 'Informacje o Docker',
+    containerName: 'Nazwa kontenera',
+    imageName: 'Nazwa obrazu',
+    platform: 'Platforma',
+    architecture: 'Architektura',
+  },
+
+  // Sponsor surface (System page)
+  sponsors: {
+    sectionTitle: 'Niezależny i finansowany przez społeczność',
+    tagline: 'Bambuddy jest darmowy i taki pozostanie, bo ludzie decydują się go wspierać. Bez VC, bez uzależnienia od chmury.',
+    viewSupporters: 'Zobacz wspierających',
+    toastPrints: "Ukończone wydruki z Bambuddy: {{count}}. Bambuddy pozostaje darmowy dzięki swoim wspierającym.",
+    toastCost: "Śledzisz w Bambuddy filament o wartości {{total}}. Zobacz, kto utrzymuje niezależność projektu.",
+    toastArchives: 'Wydruki zarchiwizowane w Bambuddy: {{count}}. Zobacz, kto utrzymuje jego niezależność.',
+    toastAnniversary: 'Rok z Bambuddy! Zobacz, kto utrzymuje niezależność projektu.',
+    toastVersionUpdate: 'Zaktualizowano do v{{version}}. Bambuddy pozostaje darmowy dzięki swoim wspierającym.',
+    toastBusiness: "Używasz Bambuddy z wieloma drukarkami (liczba: {{count}})? Istnieje plan wsparcia dla zespołów — priorytetowe poprawki, faktury i bezpośredni kontakt z opiekunem projektu.",
+    businessCta: 'Bambuddy dla firm',
+    businessTitle: 'Bambuddy dla firm',
+    businessTagline: "Liczba Twoich drukarek: {{count}}. Dla zespołów i farm wydruku dostępne są priorytetowe wsparcie, licencje komercyjne i faktury.",
+  },
+
+  // Library (K Profiles)
+  library: {
+    title: 'Biblioteka filamentów',
+    addFilament: 'Dodaj filament',
+    editFilament: 'Edytuj filament',
+    deleteFilament: 'Usuń filament',
+    vendor: 'Producent',
+    material: 'Materiał',
+    color: 'Kolor',
+    kFactor: 'Współczynnik K',
+    temperature: 'Temperatura',
+    noFilaments: 'Brak filamentów w bibliotece',
+    deleteConfirm: 'Czy na pewno chcesz usunąć ten filament?',
+    importFromPrinter: 'Importuj z drukarki',
+    exportToFile: 'Eksportuj do pliku',
+    // Slicer Pipelines run from the File Manager (#1425 PR B). The Run-with-pipeline
+    // modal is a two-step dialog: pick a pipeline, then either fire (eligibility ok)
+    // or confirm-and-fire (eligibility report shown). Lives in components/RunWithPipelineModal.tsx.
+    runWithPipeline: {
+      actionLabel: 'Uruchom z potokiem',
+      noPermission: 'Nie masz uprawnień do uruchamiania potoków',
+      modalTitle: 'Uruchom z potokiem',
+      confirmTitle: 'Potwierdź uruchomienie',
+      confirmIntro: 'Kontrola wstępna wykryła problemy z tym uruchomieniem',
+      sourceHint: 'Źródło',
+      pipelineHint: 'Potok',
+      targetHint: 'Cel',
+      pipelineListAria: 'Dostępne potoki',
+      runAnyway: 'Uruchom mimo to',
+      loading: 'Ładowanie…',
+      empty: 'Brak zapisanych potoków. Otwórz okno cięcia i kliknij „Zapisz jako potok”, aby go utworzyć.',
+      noTarget: 'Nie ustawiono drukarki docelowej',
+      noTargetMessage: 'Ten potok nie ma ustawionej drukarki docelowej. Otwórz go w ustawieniach, aby ją wybrać.',
+      // PR C — copies input + class-targeted pipelines.
+      copies: 'Kopie',
+      copiesHint: 'maks. {{n}}',
+      classTarget: 'Dowolna {{model}}',
+      toast: {
+        started: 'Uruchomiono potok',
+        failed: 'Nie udało się uruchomić',
+      },
+      issue: {
+        printerNotSet: 'Ten potok nie ma ustawionej drukarki docelowej.',
+        printerNotFound: 'Drukarka docelowa już nie istnieje.',
+        printerDisabled: 'Drukarka docelowa jest wyłączona.',
+        printerOffline: 'Drukarka docelowa jest offline.',
+        filamentType: 'Slot filamentu {{slot}}: oczekiwano {{expected}}, AMS ma {{actual}}',
+        filamentColor: 'Slot filamentu {{slot}}: inny kolor (oczekiwano {{expected}}, AMS ma {{actual}})',
+        amsSlotMissing: 'Slot AMS {{slot}} niedostępny w tej drukarce',
+        filamentUnverified: 'Slot filamentu {{slot}} pochodzi z profilu chmurowego / standardowego i nie mógł zostać zweryfikowany statycznie.',
+        // PR C — class targeting
+        noClassMatches: 'Żadna drukarka w tej instalacji nie pasuje do docelowej klasy modelu potoku ({{expected}}).',
+        classNotSet: 'Celem potoku jest klasa drukarek, ale nie wybrano modelu.',
+      },
+    },
+  },
+
+  // Slice (slicer-API integration via SliceModal)
+  slicerSettings: {
+    presetValuesOutdatedSidecar: "Wyświetlane są domyślne ustawienia slicera: Twój sidecar slicera jest starszy niż ta funkcja i nie potrafi podać wartości profilu. Zaktualizuj obraz sidecara, aby je zobaczyć. Wszystko, czego nie zmienisz, nadal pochodzi z profilu.",
+    presetValuesNotConfigured: "Wyświetlane są domyślne ustawienia slicera: nie skonfigurowano sidecara slicera, więc nie można odczytać wartości profilu. Wszystko, czego nie zmienisz, nadal pochodzi z profilu.",
+    presetValuesSidecarUnavailable: "Wyświetlane są domyślne ustawienia slicera: sidecar slicera nie odpowiedział, więc nie można odczytać wartości profilu. Wszystko, czego nie zmienisz, nadal pochodzi z profilu.",
+    presetValuesUnavailable: "Wyświetlane są domyślne ustawienia slicera: nie udało się odczytać wartości wybranego profilu. Wszystko, czego nie zmienisz, nadal pochodzi z profilu.",
+    filamentDefault: 'Domyślny',
+    fromFile: 'z pliku',
+    fromFileHint: 'Projektant zmienił to w pliku źródłowym. Wartość: {{value}}.',
+    fromFilePrinterCoupled: "drukarka projektanta",
+    fromFilePrinterCoupledHint: 'Dostrojone do drukarki, dla której zaprojektowano ten plik -- na Twojej może być błędne lub poza zakresem.',
+    fromFileOverridesPreset: 'zastępuje profil',
+    fromFileOverridesPresetHint:
+      'Plik ustawia tu {{value}}, a wybrany profil używa {{preset}}. Zaznacz tylko, jeśli plik ma mieć pierwszeństwo.',
+    useFromFile: "Użyj wartości z pliku źródłowego dla {{option}}",
+    otherFromFile: 'Inne ustawienia z tego pliku',
+    fromFileSummary: 'Liczba ustawień procesu zmienionych przez projektanta w tym pliku: {{count}}. Używane są tylko zaznaczone.',
+    fromFileUseAll: "Użyj ustawień projektanta",
+    fromFileUseAllHint: "Zaznacza ustawienia, które są przenośne między drukarkami. Te dostrojone do drukarki projektanta oraz te, które definiują wybrany profil, pozostają wyłączone.",
+    fromFileClear: 'Wyczyść ({{count}})',
+    loading: 'Ładowanie ustawień slicera…',
+    mode: {
+      simple: 'Prosty',
+      advanced: 'Zaawansowany',
+      expert: 'Ekspert',
+    },
+    searchPlaceholder: 'Szukaj ustawień',
+    resetAll: 'Resetuj ({{count}})',
+    resetOption: 'Przywróć domyślne',
+    noMatches: 'Żadne ustawienie nie pasuje do wyszukiwania.',
+  },
+  slice: {
+    filamentSlotUnset: 'nie ustawiono',
+    processSettingsEmbedded: 'Nieużywane, gdy włączona jest opcja „Użyj wbudowanych ustawień pliku” -- to ustawienia pliku sterują tym cięciem.',
+    processSettingsInactive: 'Nieaktywne',
+    presetsHidden: 'Ukryte: {{count}}',
+    showAllPresets: 'Pokaż wszystkie',
+    showFewerPresets: 'Pokaż mniej',
+    searchPresets: 'Szukaj profili...',
+    closeSearch: 'Zamknij wyszukiwanie',
+    noMatchingPresets: 'Nie znaleziono pasujących profili.',
+    processSettings: 'Ustawienia procesu',
+    processSettingsHint: "Dostosuj wybrany profil dla tego cięcia. Wszystko, czego nie ruszysz, pozostaje zgodne z profilem.",
+    processSettingsChanged: 'Zmienione: {{count}}',
+    processSettingsUnchanged: 'Domyślne profilu',
+    title: 'Pokrój model',
+    action: 'Pokrój',
+    actionAll: 'Pokrój wszystkie płyty ({{count}})',
+    actionAllTitle: 'Pokrój każdą płytę do jednego wielopłytowego wyniku (jedno archiwum). Wybór filamentu obejmuje każdy slot zdefiniowany w projekcie.',
+    allPlatesToggle: 'Pokrój wszystkie płyty ({{count}})',
+    slicing: 'Cięcie…',
+    printer: 'Profil drukarki',
+    process: 'Profil procesu',
+    filament: 'Profil filamentu',
+    filamentSlot: 'Filament {{index}} ({{type}})',
+    filamentColour: 'Kolor filamentu',
+    selectPreset: '— Wybierz profil —',
+    loadingPresets: 'Ładowanie profili…',
+    analyzingPlateFilaments: 'Analizowanie filamentów płyty…',
+    analyzingPlateFilamentsHint: 'Trwa cięcie podglądowe, aby ustalić, których slotów AMS używa ta płyta. Wynik jest zapamiętywany — ponowne otwarcie jest natychmiastowe.',
+    previewToast: 'Analizowanie {{name}} — {{elapsed}}',
+    previewWithProgress: 'Analizowanie {{name}} — {{stage}} ({{percent}}%) — {{elapsed}}',
+    notUsedByPlate: '— nieużywany przez tę płytę',
+    noPresetsForSlot: 'Brak dostępnych profili',
+    otherPrinters: 'Inne drukarki',
+    presetsLoadFailed: 'Nie udało się załadować profili. Otwórz Ustawienia → Profile, aby najpierw je zaimportować.',
+    refreshPresets: 'Odśwież',
+    refreshPresetsTitle: 'Odśwież profile — pobierz najnowsze listy z chmury i wbudowane (użyj po usunięciu profilu w Bambu Studio lub Bambu Handy)',
+    allPresetsRequired: 'Należy wybrać wszystkie profile',
+    useEmbedded: "Użyj wbudowanych ustawień pliku",
+    useEmbeddedHint: "Pokrój tak, jak przygotował to projektant (ściany, wypełnienie, filament), zamiast używać powyższych profili. Dostępne, ponieważ Twoja drukarka pasuje do drukarki z pliku.",
+    autoOrient: 'Automatyczna orientacja obiektów',
+    autoOrientHint: 'Pozwól slicerowi najpierw obrócić każdy obiekt na najlepszą do druku stronę. Zastępuje ułożenie modelu zapisane w pliku.',
+    autoArrange: 'Automatyczne rozmieszczenie na płycie',
+    autoArrangeHint: 'Pozwól slicerowi rozmieścić obiekty tak, aby na siebie nie nachodziły. Zastępuje układ zapisany w pliku.',
+    enqueuing: 'Wysyłanie zadania cięcia…',
+    queued: 'W kolejce…',
+    failed: 'Cięcie nie powiodło się. Sprawdź logi sidecara slicera.',
+    startedToast: 'Cięcie {{name}} w tle…',
+    queuedToast: 'W kolejce: {{name}} — {{elapsed}}',
+    runningToast: 'Cięcie {{name}} — {{elapsed}}',
+    runningWithProgress: '{{name}} — {{stage}} ({{percent}}%) — {{elapsed}}',
+    runningWithProgressMultiPlate: 'Płyta {{plateIndex}} z {{plateCount}} • {{name}} — {{stage}} ({{percent}}%) — {{elapsed}}',
+    completedToast: 'Pokrojono {{name}}',
+    externalWriteFallbackToast: 'Zapisano w wewnętrznej bibliotece: nie udało się zapisać do folderu zewnętrznego',
+    failedTitle: 'Cięcie nie powiodło się',
+    failedToast: 'Cięcie {{name}} nie powiodło się: {{detail}}',
+    tier: {
+      local: 'Zaimportowane',
+      cloud: 'Bambu Cloud',
+      orcaCloud: 'Orca Cloud',
+      standard: 'Standardowe',
+    },
+    cloud: {
+      notAuthenticated: 'Zaloguj się do Bambu Cloud (Ustawienia → Profile → Bambu Cloud), aby zobaczyć swoje profile chmurowe.',
+      expired: 'Sesja Bambu Cloud wygasła — zaloguj się ponownie, aby odświeżyć profile chmurowe.',
+      unreachable: 'Bambu Cloud jest teraz niedostępne. Profile lokalne i standardowe nadal działają.',
+    },
+    orcaCloud: {
+      notAuthenticated: 'Zaloguj się do Orca Cloud (Profile → Orca Cloud), aby zobaczyć swoje profile Orca.',
+      expired: 'Sesja Orca Cloud wygasła — zaloguj się ponownie, aby odświeżyć profile Orca.',
+      unreachable: 'Orca Cloud jest teraz niedostępne. Pozostałe profile nadal działają.',
+    },
+    bedType: {
+      label: 'Płyta robocza',
+      auto: 'Automatycznie (z profilu procesu)',
+      coolPlate: 'Cool Plate',
+      coolPlateSuperTack: 'Cool Plate SuperTack',
+      engineering: 'Engineering Plate',
+      highTemp: 'Smooth PEI Plate / High Temp Plate',
+      texturedPEI: 'Textured PEI Plate',
+    },
+    // Slicer Pipelines (#1425) — apply a saved bundle or save the current pick.
+    filters: {
+      onlyConnectedModels: 'Tylko drukarki online',
+      onlyConnectedModelsHint: 'Profile drukarek dla modeli, które są teraz online, dla każdej średnicy dyszy.',
+      onlyLoadedSpools: 'Tylko załadowane szpule',
+      onlyLoadedSpoolsHint: 'Profile filamentów szpul w drukarkach online wybranego modelu. Profil wybrany przez Ciebie pozostaje.',
+      noneOnline: 'Żadna drukarka nie jest online, więc wyświetlane są wszystkie profile.',
+      noneLoaded: 'Żadna załadowana szpula nie ma profilu dla tej drukarki, więc wyświetlane są wszystkie profile filamentów.',
+      notOnline: 'Nie online',
+      notLoaded: 'Niezaładowane',
+    },
+    loadedSpools: {
+      title: 'Załadowane szpule',
+      pick: 'Wybierz',
+      pickTitle: 'Wybierz szpulę załadowaną w podłączonej drukarce',
+      none: 'Żadna drukarka tego modelu nie jest online.',
+      nothingLoaded: 'Brak AMS i brak szpuli zewnętrznej.',
+      unknownSpool: 'Niezidentyfikowana szpula',
+      empty: 'Pusty',
+      noProfile: 'Brak profilu dla wybranej drukarki',
+      noProfileShort: 'Brak profilu dla tej drukarki',
+    },
+    pipelines: {
+      label: 'Potok',
+      applyAria: 'Zastosuj potok',
+      applyPrompt: 'Zastosuj potok…',
+      empty: 'Brak zapisanych potoków',
+      saveButton: 'Zapisz jako potok',
+      saveTitle: 'Zapisz bieżący wybór czterech pozycji jako potok wielokrotnego użytku',
+      namePlaceholder: 'Nazwa potoku',
+      nameAria: 'Nazwa nowego potoku',
+      toast: {
+        applied: 'Zastosowano „{{name}}”',
+        saved: 'Zapisano potok',
+        saveFailed: 'Zapis nie powiódł się',
+      },
+    },
+  },
+
+  // Spoolman
+  spoolman: {
+    title: 'Integracja ze Spoolman',
+    enabled: 'Spoolman włączony',
+    url: 'URL Spoolman',
+    connected: 'Połączono',
+    disconnected: 'Nie połączono',
+    testConnection: 'Testuj połączenie',
+    sync: 'Synchronizuj',
+    syncing: 'Synchronizowanie...',
+    lastSync: 'Ostatnia synchronizacja',
+    linkToSpoolman: 'Połącz ze Spoolman',
+    openInSpoolman: 'Otwórz w Spoolman',
+    unlinkSpool: 'Odłącz szpulę',
+    selectSpool: 'Wybierz szpulę',
+    noUnlinkedSpools: 'Brak dostępnych nieprzypisanych szpul',
+    linkSuccess: 'Przypisano szpulę',
+    linkFailed: 'Nie udało się przypisać szpuli',
+    unlinkSuccess: 'Usunięto przypisanie szpuli',
+    unlinkFailed: 'Nie udało się usunąć przypisania szpuli',
+    linkedSpool: 'Przypisana szpula',
+    spoolId: 'ID szpuli',
+    fillSourceLabel: '(Spoolman)',
+    weight: 'Waga',
+    remaining: 'Pozostało',
+    disableWeightSync: 'Wyłącz synchronizację szacowanej wagi z AMS',
+    disableWeightSyncDesc: "Nie aktualizuj pozostałej ilości na podstawie szacunków AMS. Użyj tej opcji, jeśli wolisz śledzenie zużycia w Spoolman od procentowych szacunków AMS. Nowe szpule nadal użyją szacunku AMS jako wagi początkowej.",
+    reportPartialUsage: 'Zgłaszaj częściowe zużycie dla nieudanych wydruków',
+    reportPartialUsageDesc: 'Gdy wydruk się nie powiedzie lub zostanie anulowany, zgłoś szacowaną ilość filamentu zużytego do tego momentu na podstawie postępu warstw.',
+  },
+
+  locations: {
+    title: 'Miejsca przechowywania',
+    subtitle: 'Zarządzaj półkami, szufladami i innymi fizycznymi miejscami przechowywania szpul',
+    add: 'Dodaj lokalizację',
+    addShort: 'Dodaj',
+    edit: 'Edytuj lokalizację',
+    name: 'Nazwa',
+    spools: 'Szpule',
+    sensors: 'Czujniki',
+    empty: 'Brak miejsc przechowywania. Utwórz pierwszą półkę lub szufladę.',
+    manage: 'Lokalizacje',
+    createPlaceholder: 'np. Półka A, Szuflada 1',
+    nameRequired: 'Nazwa lokalizacji jest wymagana',
+    created: 'Utworzono lokalizację',
+    updated: 'Zaktualizowano lokalizację',
+    deleted: 'Usunięto lokalizację',
+    saveFailed: 'Nie udało się zapisać lokalizacji',
+    deleteFailed: 'Nie udało się usunąć lokalizacji',
+    deleteBlocked: 'Przed usunięciem zabierz wszystkie szpule z tej lokalizacji',
+    confirmDelete: 'Usunąć „{{name}}”?',
+    confirmDeleteMessage: 'Ta lokalizacja zostanie usunięta z katalogu. Najpierw trzeba przenieść szpule.',
+    confirmDeleteMessageWithSensors:
+      'Ta lokalizacja zostanie usunięta z katalogu. Najpierw trzeba przenieść szpule. Podłączone czujniki również zostaną usunięte.',
+  },
+
+  // Inventory
+  inventory: {
+    title: 'Magazyn szpul',
+    subtitle: 'Zarządzaj swoimi szpulami',
+    addToInventory: 'Dodaj do magazynu',
+    addToInventoryPending: 'Dodawanie...',
+    addToInventorySuccess: 'Dodano szpulę do magazynu',
+    addToInventoryFailed: 'Nie udało się dodać szpuli do magazynu',
+    unknownSpoolTitle: 'Wykryto nowy filament',
+    unknownSpoolMessage: 'W lokalizacji {{location}} wykryto szpulę z nieznanym tagiem RFID. Dodać ją teraz do magazynu?',
+    unknownSpoolSlot: 'Slot',
+    bulk: {
+      selectAllVisible: 'Zaznacz wszystkie widoczne',
+      selectRow: 'Zaznacz wiersz',
+      selectGroup: 'Zaznacz grupę',
+      selectionCount: 'Zaznaczono: {{count}}',
+      edit: 'Edytuj',
+      printLabels: 'Drukuj etykiety',
+      resetUsage: 'Resetuj zużycie',
+      restore: 'Przywróć',
+      archive: 'Archiwizuj',
+      delete: 'Usuń',
+      clearSelection: 'Wyczyść zaznaczenie',
+      editTitle: 'Zbiorcza edycja szpul',
+      editSubtitle: 'Dotyczy zaznaczonych szpul ({{count}}). Aktualizowane są tylko zaznaczone pola.',
+      editHint: 'Wpisz coś w pole, aby oznaczyć je do aktualizacji — wysyłane są tylko zaznaczone wiersze. Puste pole pozostawia szpule bez zmian (czyszczenie pól jest możliwe tylko dla pojedynczej szpuli).',
+      useCustom: 'Użyj „{{value}}”',
+      toggleField: 'Przełącz aktualizację tego pola',
+      changeCount: 'Liczba pól do aktualizacji: {{count}}.',
+      applyPending: 'Stosowanie...',
+      applyButton: 'Zastosuj do szpul ({{count}})',
+      deleteTitle: 'Usuń zaznaczone szpule',
+      archiveTitle: 'Archiwizuj zaznaczone szpule',
+      restoreTitle: 'Przywróć zaznaczone szpule',
+      resetUsageTitle: 'Resetuj zużycie zaznaczonych szpul',
+      deleteMessage: 'Trwale usunąć szpule ({{count}})? Tej operacji nie można cofnąć.',
+      archiveMessage: 'Zarchiwizować szpule ({{count}})? Można je później przywrócić.',
+      restoreMessage: 'Przywrócić zarchiwizowane szpule ({{count}})?',
+      resetUsageMessage: 'Zresetować licznik „Łączne zużycie” dla szpul ({{count}})? Pozostała waga zostanie zachowana.',
+      updateSuccess: 'Zaktualizowane szpule: {{count}}',
+      updateFailed: 'Zbiorcza aktualizacja nie powiodła się',
+      updatePartial: 'Zaktualizowane szpule: {{ok}}, nieudane: {{failed}}',
+      updateAllFailed: 'Wszystkie aktualizacje szpul ({{count}}) nie powiodły się — zaznaczenie zachowano, aby można było ponowić',
+      resetPartial: 'Zresetowano licznik szpul: {{ok}}, nieudane: {{failed}}',
+      resetAllFailed: 'Nie zresetowano żadnego licznika: wszystkie ({{count}}) nie powiodły się',
+      deleteSuccess: 'Usunięte szpule: {{count}}',
+      deleteFailed: 'Zbiorcze usuwanie nie powiodło się',
+      deletePartial: 'Usunięte szpule: {{ok}}, nieudane: {{failed}}',
+      deleteAllFailed: 'Wszystkie usunięcia szpul ({{count}}) nie powiodły się — zaznaczenie zachowano, aby można było ponowić',
+      archiveSuccess: 'Zarchiwizowane szpule: {{count}}',
+      archiveFailed: 'Zbiorcza archiwizacja nie powiodła się',
+      archivePartial: 'Zarchiwizowane szpule: {{ok}}, nieudane: {{failed}}',
+      archiveAllFailed: 'Wszystkie archiwizacje szpul ({{count}}) nie powiodły się — zaznaczenie zachowano, aby można było ponowić',
+      restoreSuccess: 'Przywrócone szpule: {{count}}',
+      restoreFailed: 'Zbiorcze przywracanie nie powiodło się',
+      restorePartial: 'Przywrócone szpule: {{ok}}, nieudane: {{failed}}',
+      restoreAllFailed: 'Wszystkie przywrócenia szpul ({{count}}) nie powiodły się — zaznaczenie zachowano, aby można było ponowić',
+      invalidHex: 'Wpisz 6 znaków szesnastkowych (RRGGBB) lub 8 (RRGGBBAA). W przeciwnym razie pole nie zostanie zastosowane.',
+    },
+    spoolmanMixedContentTitle: 'Spoolman nie może się załadować przez HTTPS — przeglądarka blokuje treści mieszane',
+    spoolmanMixedContentBody: 'Bambuddy jest serwowany przez HTTPS (przez Twój reverse proxy), ale URL Spoolman nadal używa zwykłego HTTP. Przeglądarki ze względów bezpieczeństwa blokują treści mieszane, więc osadzony interfejs Spoolman nie może się wyświetlić. Aby to działało, Spoolman musi być dostępny przez HTTPS.',
+    spoolmanMixedContentFixReverseProxy: 'Umieść Spoolman za tym samym reverse proxy co Bambuddy (Traefik / Nginx / Caddy) z HTTPS, a następnie zmień URL Spoolman w ustawieniach na nowy adres HTTPS.',
+    spoolmanMixedContentFixOpenNewTab: 'Jako obejście otwórz Spoolman w nowej karcie przeglądarki przez HTTP — zasady treści mieszanych dotyczą tylko osadzonych ramek, więc osobna karta nadal działa.',
+    spoolmanOpenInNewTab: 'Otwórz Spoolman w nowej karcie',
+    labels: {
+      title: 'Drukuj etykiety szpul',
+      selectedCount: 'Zaznaczono: {{count}}',
+      pickSpools: 'Wybierz szpule, dla których chcesz wydrukować etykiety:',
+      monochrome: 'Monochromatycznie (drukarka czarno-biała)',
+      monochromeHint: 'Usuwa próbkę koloru i poszerza tekst',
+      startingPosition: 'Pozycja pierwszej etykiety',
+      startingPositionInvalid: 'Wpisz liczbę całkowitą od 1 do {{capacity}}.',
+      startingPositionFirst: 'Drukowanie zaczyna się od pozycji 1.',
+      startingPositionSkipped: 'Pozycje od 1 do {{lastPosition}} na pierwszym arkuszu pozostaną puste.',
+      searchPlaceholder: 'Szukaj po nazwie, producencie lub #ID',
+      filterByMaterial: 'Materiał:',
+      allMaterials: 'Wszystkie',
+      selectVisible: 'Zaznacz wszystkie widoczne ({{count}})',
+      deselectVisible: 'Odznacz widoczne',
+      clearAll: 'Wyczyść wszystko',
+      noSpoolsToShow: 'Brak szpul do wyświetlenia. Zmień filtr i spróbuj ponownie.',
+      noMatches: 'Żadna szpula nie pasuje do bieżącego wyszukiwania lub filtra.',
+      printOne: 'Drukuj etykietę dla tej szpuli',
+      printLabels: 'Drukuj etykiety…',
+      bulkTitle: 'Wybierz szpule do druku etykiet spośród obecnie wyświetlanych ({{count}})',
+      noSpoolsTitle: 'Brak szpul do oznaczenia',
+      error: 'Nie udało się wygenerować etykiet: {{msg}}',
+      template: 'Rozmiar etykiety',
+      preview: 'Podgląd',
+      previewOf: 'Podgląd #{{id}}',
+      previewNoSelection: 'Wybierz szpulę, aby zobaczyć jej etykietę.',
+      previewError: 'Nie udało się wyrenderować podglądu: {{msg}}',
+      previewAlt: 'Podgląd etykiety',
+      previewHint: 'Wiersze, które nie mieszczą się na etykiecie tego rozmiaru, są pomijane.',
+      content: 'Drukuj na etykiecie',
+      resetFields: 'Przywróć domyślne',
+      format: 'Wynik:',
+      dpi: 'Rozdzielczość',
+      pngHint: 'Dla oprogramowania drukarek etykiet, które przyjmuje obrazy. Dopasuj rozdzielczość drukarki; kilka etykiet trafia do pliku ZIP.',
+      createPdf: 'Utwórz PDF',
+      downloadPng: 'Pobierz PNG',
+      selectedTitle: 'Drukuj etykiety dla zaznaczonych szpul ({{count}})',
+      fields: {
+        brand: 'Producent',
+        material: 'Materiał i podtyp',
+        hex: 'Kod koloru',
+        name: 'Nazwa koloru lub filamentu',
+        location: 'Miejsce przechowywania',
+        materialNumber: 'Numer materiału',
+        temps: 'Temperatura dyszy',
+        weight: 'Waga netto',
+        note: 'Notatka',
+        added: 'Data dodania',
+        qr: 'Kod QR',
+        spoolId: 'ID szpuli',
+      },
+      sortBy: {
+        label: 'Sortuj:',
+        id: 'Według ID',
+        color: 'Według koloru',
+      },
+      templates: {
+        amsHolderSmall: {
+          label: 'Uchwyt AMS — mały (74 × 33 mm)',
+          hint: 'Jedna etykieta na stronę; pasuje do etykiety z modelu MakerWorld 752566 (AMS Filament Label Holder).',
+        },
+        amsHolderLarge: {
+          label: 'Uchwyt AMS — duży (75 × 55 mm)',
+          hint: 'Jedna etykieta na stronę; pasuje do wariantu AMS Filament Label Holder z wkładką z kartonu. Wystarczająco dużo miejsca na próbkę koloru, producenta, materiał, ID i kod QR.',
+        },
+        box40x30: {
+          label: 'Etykieta na pudełko (40 × 30 mm)',
+          hint: 'Jedna etykieta na stronę; popularny rozmiar rolki DK/Brother, dobry na etykiety woreczków z filamentem i pojemników.',
+        },
+        box: {
+          label: 'Etykieta na pudełko (62 × 29 mm)',
+          hint: 'Jedna etykieta na stronę; rozmiar dla małych etykiet Brother PT/QL i Dymo.',
+        },
+        averyL7160: {
+          label: 'Avery L7160 — arkusz A4 (38,1 × 63,5 mm × 21)',
+          hint: 'Arkusze europejskie; 21 etykiet na stronę A4.',
+        },
+        avery5160: {
+          label: 'Avery 5160 — arkusz US Letter (25,4 × 66,7 mm × 30)',
+          hint: 'Arkusze amerykańskie; 30 etykiet na stronę Letter.',
+        },
+      },
+    },
+    csv: {
+      importButton: 'Importuj CSV',
+      exportButton: 'Eksportuj CSV',
+      modalTitle: 'Importuj szpule z CSV',
+      selectFile: 'Wybierz plik CSV lub przeciągnij go tutaj',
+      dragHint: 'Nagłówek: material (wymagane), brand, subtype, color_name, rgba, …',
+      parsing: 'Odczytywanie pliku…',
+      previewError: 'Nie udało się odczytać pliku CSV',
+      validCount: 'Poprawne: {{count}}',
+      errorCount: 'Błędy: {{count}}',
+      skippedCount: 'Pominięte: {{count}}',
+      colRow: 'Wiersz',
+      colStatus: 'Status',
+      colColor: 'Kolor',
+      colorResolved: 'Kolor uzupełniony z katalogu',
+      colorCrossMaterial: 'Kolor pobrany z innego materiału — brak dokładnego dopasowania w katalogu',
+      duplicateExisting: 'Szpula z tym materiałem, producentem i kolorem już istnieje — i tak zostanie zaimportowana jako nowa szpula',
+      spoolmanHint: 'W trybie Spoolman użyj wbudowanego importu/eksportu CSV w Spoolman.',
+      importValidRows: 'Importuj poprawne wiersze ({{count}})',
+      noValidRows: 'Brak poprawnych wierszy',
+      importing: 'Importowanie…',
+      importSuccess: 'Zaimportowane szpule: {{count}}',
+      importError: 'Import nie powiódł się',
+      exportError: 'Eksport nie powiódł się',
+    },
+    addSpool: 'Dodaj szpulę',
+    editSpool: 'Edytuj szpulę',
+    copySpool: 'Kopiuj szpulę',
+    material: 'Materiał',
+    selectMaterial: 'Wybierz materiał...',
+    subtype: 'Podtyp',
+    brand: 'Producent',
+    searchBrand: 'Szukaj producenta...',
+    useCustomBrand: 'Użyj „{{brand}}”',
+    useCustomMaterial: 'Użyj własnego materiału: {{material}}',
+    suggestedOptions: 'Sugerowane',
+    allOptions: 'Wszystkie',
+    colorName: 'Nazwa koloru',
+    colorNamePlaceholder: 'Jade White, Fire Red...',
+    color: 'Kolor',
+    hexColor: 'Kolor hex',
+    pickColor: 'Wybierz własny kolor',
+    labelWeight: 'Waga nominalna',
+    coreWeight: 'Waga pustej szpuli',
+    searchSpoolWeight: 'Szukaj wagi szpuli...',
+    weightUsed: 'Zużyto',
+    currentWeight: 'Pozostała waga',
+    measuredWeight: 'Zmierzona waga',
+    spoolName: 'Szpula',
+    costPerKg: 'Koszt za kg',
+    costFromFilament: '(cena filamentu)',
+    storageLocation: 'Miejsce przechowywania',
+    temperature: 'Temperatura',
+    humidity: 'Wilgotność',
+    battery: 'Bateria',
+    storageLocationPlaceholder: 'np. Półka A, Szuflada 1',
+    openInInventory: 'Otwórz w magazynie',
+    measuredWeightError: 'Zmierzona waga musi mieścić się między {{min}} g a {{max}} g.',
+    slicerFilament: 'Filament w slicerze',
+    slicerFilamentName: 'Nazwa profilu slicera',
+    slicerPreset: 'Profil slicera',
+    searchPresets: 'Szukaj profili filamentu...',
+    selectedPreset: 'Wybrany',
+    noPresetsFound: 'Nie znaleziono profili',
+    tempOverrides: 'Nadpisania temperatur',
+    note: 'Notatka',
+    notePlaceholder: 'Dodatkowe uwagi o tej szpuli...',
+    // Per-spool category + low-stock threshold override (#729)
+    category: 'Kategoria',
+    categoryPlaceholder: 'np. Produkcja, Prototyp, Klient A',
+    categoryNone: 'Bez kategorii',
+    // #1400: storage-location filter chip — `storageLocation` label is
+    // already defined above for the spool-edit field, reused here for the
+    // dropdown header. `storageLocationNone` is new (the "no location set"
+    // group, mirrors `categoryNone`).
+    storageLocationNone: 'Brak lokalizacji',
+    lowStockThresholdOverride: 'Próg niskiego stanu (ta szpula)',
+    lowStockThresholdOverrideHelp: 'Pozostaw puste, aby użyć progu globalnego ({{global}}%).',
+    // Internal material / article number (#2870)
+    materialNumber: 'Nr materiału',
+    materialNumberPlaceholder: 'np. 15',
+    materialNumberHelp: 'Wewnętrzny numer zakupowy — wspólny dla wszystkich szpul tego produktu. Nowe szpule tego samego produktu go dziedziczą.',
+    lastDried: 'Ostatnie suszenie',
+    lastDriedNow: 'Teraz',
+    lastDriedHelp: 'Uzupełniane po zakończeniu suszenia w AMS trwającego co najmniej połowę zaplanowanego czasu. Ustaw tutaj dla szpuli suszonej gdzie indziej.',
+    materialNumberNone: 'Brak numeru materiału',
+    // Suppliers (#2988): the master list and the per-spool assignments.
+    profileDefaults: {
+      title: 'Domyślne profile',
+      description: 'To, z czym startują nowe szpule danego produktu: profil slicera, profile dla poszczególnych modeli drukarek i profile K. Zapisz je z karty Drukarki szpuli przyciskiem Zapisz jako domyślne; ponowny zapis je zastępuje.',
+      empty: 'Brak domyślnych profili. Skonfiguruj kartę Drukarki szpuli i zaznacz Zapisz jako domyślne.',
+      allColours: 'Wszystkie kolory',
+      colourOnly: 'Tylko {{colour}}',
+      colourOnlyNeedsColour: 'Tylko ten kolor: ta szpula nie ma nazwy koloru. Dodaj ją na karcie {{tab}}, aby zapisać domyślne tylko dla tego koloru.',
+      scope: 'Dotyczy',
+      saveAsDefault: 'Zapisz jako domyślne dla nowych szpul {{product}}',
+      saveNeedsMaterial: 'Zapisz jako domyślne (najpierw ustaw materiał)',
+      prefilled: 'Uzupełniono z domyślnych profili dla {{product}}',
+      saveFailed: 'Zapisano szpulę, ale nie udało się zapisać domyślnych profili',
+      apply: 'Zastosuj do istniejących szpul',
+      applyHelp: 'Uzupełnij to, czego aktywne szpule tego produktu jeszcze nie mają. Nic, co już mają, nie zostanie zmienione.',
+      applied_one: 'Uzupełniono {{count}} szpulę',
+      applied_other: 'Uzupełnione szpule: {{count}}',
+      applyFailed: 'Nie udało się zastosować domyślnych profili',
+      deleteTitle: 'Usuń domyślne profile',
+      deleteMessage: 'Usunąć domyślne profile dla {{product}}? Szpule, które już mają te profile, zachowają je.',
+      deleteFailed: 'Nie udało się usunąć domyślnych profili',
+    },
+    suppliers: {
+      label: 'Dostawcy',
+      none: 'Brak dostawcy',
+      addSupplier: 'Dodaj dostawcę…',
+      searchPlaceholder: 'Szukaj dostawców…',
+      noneLeft: 'Wszyscy dostawcy są już przypisani',
+      createNew: 'Utwórz „{{name}}”',
+      createFailed: 'Nie udało się utworzyć dostawcy',
+      purchaseSource: 'Kupiono tutaj',
+      purchaseSourceHelp: 'Oznacza, gdzie ta szpula została faktycznie kupiona; pozostałe wpisy to alternatywne źródła.',
+      articleNumberPlaceholder: 'Nr artykułu dostawcy',
+      pricePlaceholder: 'Cena ofertowa/kg',
+      priceHelp: 'Cena ofertowa u tego dostawcy, do porównywania źródeł — podstawą kosztu pozostaje koszt za kg samej szpuli.',
+      help: 'Gdzie można kupić ten produkt. Wyróżniony wpis to miejsce zakupu tej szpuli.',
+      saveFailed: 'Nie udało się zapisać przypisań dostawców',
+      title: 'Dostawcy',
+      description: 'Zarządzaj tym, gdzie kupujesz filament — to coś innego niż producent, czyli ten, kto go wyprodukował. Przypisuj dostawców do szpul w oknie szpuli; dostawcy, który jest nadal przypisany do szpul, nie można usunąć.',
+      search: 'Szukaj dostawców...',
+      addNew: 'Dodaj nowego dostawcę',
+      namePlaceholder: 'Nazwa (np. Filament24)',
+      websitePlaceholder: 'Strona / URL sklepu',
+      customerNumberPlaceholder: 'Nr klienta',
+      notePlaceholder: 'Notatka',
+      nameRequired: 'Nazwa jest wymagana',
+      duplicateName: 'Dostawca o tej nazwie już istnieje',
+      customerNumber: 'Nr klienta',
+      spools: 'Szpule',
+      noMatch: 'Żaden dostawca nie pasuje do wyszukiwania',
+      empty: 'Brak dostawców',
+      added: 'Dodano dostawcę',
+      addFailed: 'Nie udało się dodać dostawcy',
+      updated: 'Zaktualizowano dostawcę',
+      updateFailed: 'Nie udało się zaktualizować dostawcy',
+      deleted: 'Usunięto dostawcę',
+      deleteFailed: 'Nie udało się usunąć dostawcy',
+      deleteBlocked: 'Nie można usunąć: nadal przypisany do szpul (liczba: {{count}})',
+      loadFailed: 'Nie udało się załadować dostawców',
+      deleteTitle: 'Usuń dostawcę',
+      deleteConfirm: 'Usunąć „{{name}}”?',
+      deleteConfirmReferenced: '„{{name}}” jest przypisany do szpul (liczba: {{count}}). Usunięcie jest zablokowane, dopóki te przypisania nie zostaną usunięte.',
+    },
+    // RFID button rename (was "Delete Tag" — confusing because it sounds like a
+    // taxonomy delete; this clears the RFID tag/UUID off the spool record)
+    clearRfid: 'Wyczyść tag RFID',
+    rfidCleared: 'Wyczyszczono tag RFID',
+    archive: 'Archiwizuj',
+    restore: 'Przywróć',
+    noSpools: 'Brak szpul. Dodaj pierwszą szpulę, aby zacząć.',
+    noAvailableSpools: 'Brak dostępnych szpul. Dodaj szpulę do magazynu lub najpierw usuń przypisanie jednej z innego slotu.',
+    kProfiles: 'Profile K',
+    addKProfile: 'Dodaj profil K',
+    assignSpool: 'Przypisz szpulę',
+    unassignSpool: 'Usuń przypisanie',
+    assignSuccess: 'Przypisano szpulę i skonfigurowano slot AMS',
+    assignPendingInsert: 'Przypisano. Slot zostanie skonfigurowany po włożeniu szpuli.',
+    assignFailed: 'Nie udało się przypisać szpuli',
+    selectSpool: 'Wybierz szpulę do przypisania do tego slotu',
+    assigned: 'Przypisano',
+    assigning: 'Przypisywanie...',
+    searchSpools: 'Szukaj szpul...',
+    showAllSpools: 'Pokaż wszystkie szpule',
+    spoolmanSpools: 'Szpule Spoolman',
+    allMaterials: 'Wszystkie materiały',
+    filterByBrand: 'Filtruj według producenta...',
+    showArchived: 'Pokaż zarchiwizowane',
+    quickAdd: 'Szybkie dodawanie (zapas)',
+    quantity: 'Ilość',
+    stock: 'Zapas',
+    configured: 'Skonfigurowano',
+    spoolsCreated: 'Utworzone szpule: {{count}}',
+    spoolsPartiallyCreated: 'Utworzono szpule: {{created}} z {{total}} (część się nie powiodła)',
+    spoolCreated: 'Utworzono szpulę',
+    spoolUpdated: 'Zaktualizowano szpulę',
+    spoolDeleted: 'Usunięto szpulę',
+    deepLinkSpoolNotFound: 'Nie znaleziono szpuli',
+    deepLinkFetchFailed: 'Nie udało się załadować szpuli — spróbuj ponownie',
+    qrAssign: {
+      button: 'Przypisz kodem QR',
+      title: 'Wybierz cel przypisania',
+      description: 'Wybierz cel, a następnie zeskanuj kod QR szpuli, aby ją tam przypisać.',
+      tabAms: 'Slot AMS',
+      tabStorage: 'Magazyn',
+      printer: 'Drukarka',
+      selectSlot: 'Wybierz slot',
+      noSlots: 'Nie znaleziono slotów AMS dla tej drukarki',
+      storageLabel: 'Miejsce przechowywania',
+      storagePick: 'Wybierz lokalizację',
+      startScan: 'Ustaw cel i skanuj',
+      scanTitle: 'Zeskanuj kod QR szpuli',
+      scanInstruction: 'Skieruj kamerę na kod QR szpuli albo zrób zdjęcie, jeśli nie da się go zeskanować.',
+      scanningTarget: 'Cel: {{location}}',
+      back: 'Wstecz',
+      invalidQr: 'Ten kod QR nie jest etykietą szpuli.',
+      spoolmanLabel: 'To etykieta Spoolman, ale magazyn nie korzysta ze Spoolman.',
+      takePhoto: 'Zrób zdjęcie',
+      cameraNeedsHttps: 'Kamera na żywo wymaga otwarcia Bambuddy przez HTTPS. Zamiast tego zrób zdjęcie.',
+      cameraUnavailable: 'Nie udało się tu otworzyć żadnej kamery. Zamiast tego zrób zdjęcie.',
+      noQrInPhoto: 'Nie znaleziono kodu QR na zdjęciu — spróbuj ponownie.',
+      decoding: 'Odczytywanie…',
+      assignSuccess: 'Przypisano do {{location}}',
+      storageSuccess: 'Przeniesiono do {{location}}',
+      assignFailed: 'Nie udało się przypisać do {{location}}',
+    },
+    spoolArchived: 'Zarchiwizowano szpulę',
+    spoolRestored: 'Przywrócono szpulę',
+    kProfileSaveFailed: 'Nie udało się zapisać ustawień profilu K',
+    syncWeightSpoolNotFound: 'Nie znaleziono szpuli — mogła zostać usunięta',
+    syncWeightSpoolmanUnreachable: 'Spoolman jest niedostępny — spróbuj ponownie później',
+    syncWeightFailed: 'Nie udało się zsynchronizować wagi',
+    spoolmanUnreachable: 'Spoolman jest niedostępny — spróbuj ponownie później',
+    deleteSpoolNotFound: 'Nie znaleziono szpuli — mogła już zostać usunięta',
+    deleteFailed: 'Nie udało się usunąć szpuli',
+    archiveSpoolNotFound: 'Nie znaleziono szpuli — mogła już zostać usunięta',
+    archiveFailed: 'Nie udało się zarchiwizować szpuli',
+    restoreSpoolNotFound: 'Nie znaleziono szpuli — mogła już zostać usunięta',
+    restoreFailed: 'Nie udało się przywrócić szpuli',
+    saveFailed: 'Nie udało się zapisać zmian',
+    tagClearFailed: 'Nie udało się wyczyścić tagu',
+    deleteConfirm: 'Czy na pewno chcesz usunąć tę szpulę? Tej operacji nie można cofnąć.',
+    archiveConfirm: 'Czy na pewno chcesz zarchiwizować tę szpulę?',
+    advancedSettings: 'Ustawienia zaawansowane',
+    // Tabs
+    filamentInfoTab: 'Informacje o filamencie',
+    paProfileTab: 'Profil PA',
+    colorAndCostTab: 'Kolor i koszt',
+    printersTab: 'Drukarki',
+    filamentInfo: 'Filament',
+    additional: 'Dodatkowe',
+    // Cloud
+    loadingPresets: 'Ładowanie profili z chmury...',
+    cloudConnected: 'Połączono z chmurą',
+    cloudNotConnected: 'Brak połączenia z chmurą (używane są wartości domyślne)',
+    // Colors
+    recentColors: 'Ostatnie',
+    searchColors: 'Szukaj kolorów...',
+    searchResults: 'Wyniki wyszukiwania',
+    allColors: 'Wszystkie kolory',
+    commonColors: 'Popularne kolory',
+    showLess: 'Pokaż mniej',
+    showAll: 'Pokaż wszystkie',
+    noColorsFound: 'Żaden kolor nie pasuje do wyszukiwania',
+    noResults: 'Nie znaleziono dopasowań',
+    // Multi-color gradient + visual effect (#1154)
+    extraColorsLabel: 'Dodatkowe kolory',
+    extraColorsPlaceholder: 'EC984C,#6CD4BC,A66EB9,D87694',
+    extraColorsHint: 'Wklej od 2 do 8 kolorów hex oddzielonych przecinkami. Wyświetlane jako gradient.',
+    extraColorsInvalid: 'Pominięto nieprawidłowe wartości hex: {{tokens}}',
+    colorEffectLabel: 'Efekt',
+    colorEffect: {
+      none: 'Brak',
+      // Surface effects
+      sparkle: 'Brokat',
+      wood: 'Drewno',
+      marble: 'Marmur',
+      glow: 'Świecący',
+      matte: 'Mat',
+      // Sheen / finish variants
+      silk: 'Jedwabisty',
+      galaxy: 'Galaxy',
+      rainbow: 'Tęcza',
+      metal: 'Metaliczny',
+      translucent: 'Półprzezroczysty',
+      // Multi-color structural variants
+      gradient: 'Gradient',
+      dualColor: 'Dwukolorowy',
+      triColor: 'Trójkolorowy',
+      multicolor: 'Wielokolorowy',
+    },
+    // PA Profiles
+    selectMaterialFirst: 'Najpierw wybierz materiał na karcie Informacje o filamencie.',
+    noPrintersConfigured: 'Brak skonfigurowanych drukarek. Dodaj drukarki, aby używać profili PA.',
+    matchingFilter: 'Pasujące',
+    anyBrand: 'Dowolny producent',
+    anyVariant: 'Dowolny wariant',
+    autoSelect: 'Wybierz automatycznie',
+    matches: 'dopasowania',
+    match: 'dopasowanie',
+    noMatches: 'Brak dopasowań',
+    connected: 'Połączono',
+    offline: 'Offline',
+    printerOffline: 'Drukarka jest offline. Połącz się, aby zobaczyć profile kalibracji.',
+    noKProfilesMatch: 'Żaden profil K nie pasuje do wybranego filamentu.',
+    leftNozzle: 'Lewa dysza',
+    rightNozzle: 'Prawa dysza',
+    profilesSelected: 'wybrane profile kalibracji',
+    // Printers tab: per-model filament preset + per-hotend K profile
+    filamentPreset: 'Profil filamentu',
+    presetUseSpoolDefault: 'Użyj profilu szpuli',
+    presetInherited: 'odziedziczony',
+    presetOverride: 'nadpisanie',
+    presetNeedsModel: 'Ta drukarka nie zgłosiła jeszcze swojego modelu, więc nie może mieć własnego profilu.',
+    autoMatchPresets: 'Dopasuj automatycznie',
+    autoMatchPresetsHint: 'Znajdź wariant profilu tej szpuli, który wymienia każdy model',
+    kProfilesPerPrinter: 'Profile K',
+    kProfileNotSet: 'Nie ustawiono',
+    kProfileFlowMismatch: 'Ten profil zmierzono na dyszy {{profile}}, ale zamontowana jest dysza {{fitted}}, więc nie zostanie zastosowany',
+    nozzle: 'Dysza',
+    unknownModel: 'Nieznany model',
+    onePrinter: '1 drukarka',
+    nPrinters: 'Drukarki: {{n}}',
+    filamentPresetsLoadFailed: 'Nie udało się załadować profili tej szpuli dla poszczególnych modeli',
+    filamentPresetSaveFailed: 'Nie udało się zapisać profili dla poszczególnych modeli',
+    // Stats & enhanced table
+    totalInventory: 'Cały magazyn',
+    totalConsumed: 'Łączne zużycie',
+    byMaterial: 'Według materiału',
+    inPrinter: 'W drukarce',
+    lowStock: 'Niski stan',
+    sinceTracking: 'Od początku śledzenia',
+    resetConsumedCounter: 'Resetuj licznik',
+    resetConsumedCounterTooltip: 'Wyzeruj licznik zużytych gramów dla tej szpuli. Pozostała waga nie zostanie zmieniona.',
+    resetConsumedCounterConfirm: 'Zresetować licznik zużytych gramów tej szpuli do 0? Kolejne wydruki będą liczone ponownie od zera. Sama szpula, obliczanie pozostałej wagi i Twoje ustawienia nie zostaną zmienione.',
+    resetAllConsumedCounters: 'Resetuj wszystkie liczniki',
+    resetAllConsumedCountersTooltip: 'Wyzeruj licznik zużytych gramów na każdej szpuli. Pozostałe wagi nie zostaną zmienione.',
+    resetAllConsumedCountersConfirm: 'Zresetować licznik zużytych gramów do 0 na wszystkich szpulach ({{count}}, wraz z zarchiwizowanymi)? Wyczyści to statystykę „Łączne zużycie”, więc kolejne wydruki będą liczone od zera. Szpule i pozostałe wagi nie zostaną zmienione.',
+    consumedCounterReset: 'Zresetowano licznik',
+    allConsumedCountersReset: 'Zresetowano liczniki szpul: {{count}}',
+    resetConsumedCounterFailed: 'Nie udało się zresetować licznika',
+    loadedInAms: 'Załadowane w AMS/zewn.',
+    remaining: 'Pozostało',
+    weightCheck: 'Kontrola wagi',
+    lastWeighed: 'Ostatnie ważenie',
+    neverWeighed: 'Nigdy nie ważono',
+    search: 'Szukaj szpul...',
+    showing: 'Wyświetlanie',
+    to: 'do',
+    of: 'z',
+    show: 'Pokaż',
+    spools: 'szt.',
+    spool: 'szpula',
+    page: 'Strona',
+    noSpoolsMatch: 'Nie znaleziono wyników',
+    noSpoolsMatchDesc: 'Spróbuj zmienić wyszukiwanie lub filtry, aby znaleźć to, czego szukasz.',
+    spoolIdNotFound: 'Nie ma szpuli #{{id}}.',
+    spoolIdArchived: 'Szpula #{{id}} jest zarchiwizowana. Przywróć ją, aby ją przypisać.',
+    spoolIdInOtherSlot: 'Szpula #{{id}} jest już przypisana do innego slotu. Najpierw usuń tam przypisanie.',
+    active: 'Aktywne',
+    archived: 'Zarchiwizowane',
+    all: 'Wszystkie',
+    used: 'Używane',
+    new: 'Nowe',
+    clearFilters: 'Wyczyść filtry',
+    table: 'Tabela',
+    cards: 'Karty',
+    net: 'Netto',
+    // Grouping
+    groupSimilar: 'Grupuj',
+    groupedSpools: 'Identyczne szpule: {{count}}',
+    groupedRows: 'wiersze',
+    // Column config
+    columns: 'Kolumny',
+    configureColumns: 'Konfiguruj kolumny',
+    configureColumnsDesc: 'Przeciągnij, aby zmienić kolejność kolumn, lub użyj strzałek. Widoczność przełączasz ikoną oka.',
+    visible: 'widoczne',
+    reset: 'Resetuj',
+    cancel: 'Anuluj',
+    applyChanges: 'Zastosuj zmiany',
+    moveUp: 'Przenieś w górę',
+    moveDown: 'Przenieś w dół',
+    hideColumn: 'Ukryj kolumnę',
+    showColumn: 'Pokaż kolumnę',
+    // Tag linking
+    linkToSpool: 'Połącz ze szpulą',
+    tagLinked: 'Połączono tag ze szpulą',
+    tagLinkFailed: 'Nie udało się połączyć tagu',
+    tagAlreadyLinked: 'Tag jest już połączony ze szpulą #{{id}}',
+    unknownTag: 'Wykryto nieznany tag RFID',
+    // Usage history
+    usageHistory: 'Historia zużycia',
+    noUsageHistory: 'Brak zarejestrowanego zużycia',
+    printName: 'Nazwa wydruku',
+    weightConsumed: 'Zużyta waga',
+    clearHistory: 'Wyczyść',
+    historyCleared: 'Wyczyszczono historię zużycia',
+    fillSourceLabel: '(Mag.)',
+    lowStockThresholdError: 'Próg musi mieścić się między 0,1 a 99,9',
+    assignMismatchTitle: 'Niezgodność materiału',
+    assignMismatchMessage: 'Materiał wybranej szpuli „{{spoolMaterial}}” nie pasuje do materiału slotu „{{trayMaterial}}” w {{location}}. Przypisać mimo to?',
+    assignMismatchConfirm: 'Przypisz mimo to',
+    assignPartialMismatchMessage: 'Materiał szpuli „{{spoolMaterial}}” jest podobny, ale nie identyczny z „{{trayMaterial}}” w {{location}}. Czy chcesz kontynuować?',
+    assignProfileMismatchMessage: 'Profil szpuli „{{spoolProfile}}” nie pasuje do profilu slotu „{{trayProfile}}” w {{location}}. Czy chcesz kontynuować?',
+    assignReconfigureNote: 'Slot AMS zostanie ponownie skonfigurowany, aby używać profilu szpuli.',
+    // Spoolman filament catalog picker
+    spoolmanFilamentCatalog: 'Katalog filamentów Spoolman',
+    pickFromSpoolmanCatalog: 'Wybierz z katalogu Spoolman…',
+    spoolmanFilamentSelected: 'Wybrano filament z katalogu Spoolman',
+    spoolmanFilamentUnlinked: 'Wyczyszczono połączenie z katalogiem filamentów',
+    noSpoolmanFilaments: 'Nie znaleziono filamentów w katalogu Spoolman',
+    spoolmanFilamentColorSwatch: 'Kolor filamentu',
+    spoolmanCatalogLoadFailed: 'Nie udało się załadować katalogu filamentów Spoolman',
+  },
+
+  // Timelapse
+  timelapse: {
+    title: 'Timelapse',
+    create: 'Utwórz timelapse',
+    download: 'Pobierz',
+    delete: 'Usuń',
+    preview: 'Podgląd',
+    frameRate: 'Liczba klatek na sekundę',
+    quality: 'Jakość',
+    processing: 'Przetwarzanie...',
+    noTimelapses: 'Brak dostępnych timelapse\'ów',
+  },
+
+  // AMS
+  ams: {
+    title: 'AMS',
+    slot: 'Slot',
+    empty: 'Pusty',
+    emptySlot: 'Pusty slot',
+    slotEmpty: 'Pusty',
+    slotUnconfigured: '?',
+    emptySlotReset: 'Nie przypisano filamentu',
+    unknown: 'Nieznany',
+    humidity: 'Wilgotność',
+    temperature: 'Temperatura',
+    filamentType: 'Typ filamentu',
+    filamentColor: 'Kolor',
+    remaining: 'Pozostało',
+    history: 'Historia AMS',
+    noHistory: 'Brak dostępnej historii',
+    configureSlot: 'Konfiguruj slot',
+    externalSpool: 'Szpula zewnętrzna',
+    profile: 'Profil',
+    kFactor: 'Współczynnik K',
+    kFactorShort: 'K',
+    fill: 'Wypełnienie',
+    configure: 'Konfiguruj',
+    used: 'zużyto',
+    remainingUnit: 'pozostało',
+  },
+
+  // Print modal
+  printModal: {
+    variants: {
+      editNote: 'Te alternatywy ustawiono podczas dodawania zadania do kolejki. Aby je zmienić, anuluj zadanie i dodaj je ponownie.',
+      title: 'Alternatywne drukarki',
+      help: 'Jedno zadanie, jedno miejsce w kolejce. Plik zostanie wydrukowany na pierwszej pasującej drukarce, która się zwolni.',
+      unknownModel: 'Nieznany model',
+      plateFor: 'Płyta dla {{filename}}',
+      moveUp: 'Przenieś w górę',
+      moveDown: 'Przenieś w dół',
+      queued: 'Dodano do kolejki, alternatywy: {{count}}',
+    },
+    selectPrinter: 'Wybierz drukarkę',
+    selectPlate: 'Wybierz płytę',
+    filamentMapping: 'Mapowanie filamentów',
+    useArchiveMapping: 'Mapowanie',
+    useArchiveMappingTooltip: 'Wybierz każdy slot na podstawie mapowania AMS zapisanego z tym archiwum (ze slicera), zamiast dopasowywać po typie/kolorze.',
+    clickToChangeSlot: 'Kliknij, aby zmienić przypisanie slotu',
+    reRead: 'Odczytaj ponownie',
+    plateN: 'Płyta {{n}}',
+    plateFilamentsUnreadable: 'Nie udało się odczytać filamentów wybranej płyty, więc nie można jej zmapować. Odznacz ją, aby dodać pozostałe do kolejki.',
+    totalCost: 'Koszt całkowity:',
+    slotRemainingShort: ' - pozostało {{grams}}g',
+    printSettings: 'Ustawienia druku',
+    bedLeveling: 'Poziomowanie stołu',
+    flowCalibration: 'Kalibracja przepływu',
+    vibrationCalibration: 'Kalibracja drgań',
+    layerInspection: 'Inspekcja pierwszej warstwy',
+    timelapse: 'Timelapse',
+    cancel: 'Anuluj',
+    noPrintersAvailable: 'Brak dostępnych drukarek',
+    printerBusy: 'Drukarka jest zajęta',
+    printerOffline: 'Drukarka jest offline',
+    sameTypeDifferentColor: 'Ten sam typ, inny kolor',
+    filamentTypeNotLoaded: 'Typ filamentu nie jest załadowany',
+    statusReady: 'Gotowe',
+    statusColorMismatch: 'Niezgodny kolor',
+    statusTypeNotFound: 'Nie znaleziono typu',
+    requiredTooltip: 'Wymagane: {{name}} - {{color}}',
+    manuallySelected: 'Wybrano ręcznie',
+    autoMatched: 'Dopasowano automatycznie',
+    selectSlot: 'Wybierz slot',
+    exactColorMatch: 'Dokładne dopasowanie koloru',
+    slotForFilament: 'Slot drukarki dla {{name}}',
+    overrideForFilament: 'Zastąpienie filamentu dla {{name}}',
+    sameTypeDifferentColorDetail: 'Ten sam typ, inny kolor: wymagany {{required}}, w slocie jest {{loaded}}',
+    requiredTypeNotInPrinter: 'Nie znaleziono w drukarce wymaganego typu filamentu.',
+    whenToPrint: 'Kiedy drukować',
+    asap: 'Jak najszybciej',
+    queue: 'Kolejka',
+    schedule: 'Zaplanuj',
+    dateTime: 'Data i godzina',
+    invalidDateTime: 'Wprowadź prawidłową datę i godzinę',
+    openCalendar: 'Otwórz kalendarz',
+    requireManualStart: 'Wymagaj ręcznego uruchomienia',
+    awaitingReviewNote: 'Twój wydruk czeka na zatwierdzenie: rozpocznie się, gdy uruchomi go osoba zarządzająca kolejką.',
+    requirePreviousSuccess: 'Uruchom tylko, jeśli poprzedni wydruk się powiódł',
+    autoOffAfter: 'Wyłącz drukarkę po zakończeniu',
+    helpAsap: 'Wydruk zostanie dodany na początek kolejki i rozpocznie się, gdy tylko odpowiednia drukarka będzie bezczynna.',
+    helpSchedule: 'Wydruk rozpocznie się o zaplanowanej godzinie, jeśli drukarka będzie bezczynna. Jeśli będzie zajęta, poczeka, aż drukarka stanie się dostępna.',
+    helpQueue: 'Wydruk zostanie dodany na koniec kolejki.',
+    leftNozzle: 'L',
+    rightNozzle: 'P',
+    leftNozzleTooltip: 'Lewa dysza',
+    rightNozzleTooltip: 'Prawa dysza',
+    ftsSameInletHint: 'Wszystkie filamenty tego wydruku są na wejściu IN-{{inlet}} Filament Track Switch. Przełączanie między filamentami na tym samym wejściu jest wolniejsze — przenieś jeden do AMS na drugim wejściu, aby to przyspieszyć.',
+    rackPosition: 'Pozycja w stojaku',
+    rackPositionTooltip: 'Która dysza w stojaku drukuje ten filament. Pozycje są numerowane tak jak na drukarce.',
+    rackEmptyPosition: 'Ta pozycja w stojaku jest pusta',
+    rackWrongNozzle: 'Zawiera dyszę {{has}}; ten filament wymaga {{needs}}',
+    filamentOverride: 'Zastąpienie filamentu',
+    filamentOverrideHint: 'Opcjonalnie zastąp filamenty dla przypisania według modelu. Harmonogram będzie dopasowywał do wybranych filamentów zamiast oryginalnych wartości z 3MF.',
+    originalFilament: 'Oryginalny',
+    overrideWith: 'Zastąp przez',
+    resetToOriginal: 'Przywróć oryginalny',
+    insufficientFilamentTitle: 'Za mało filamentu',
+    waitingForAmsStatus: 'Oczekiwanie na stan AMS z {{printer}}…',
+    insufficientFilamentMessage: 'Niektóre przypisane szpule mają mniej filamentu, niż wymaga ten wydruk:',
+    insufficientFilamentLine: '{{printer}} - {{slot}}: wymagane {{required}}g, pozostało {{remaining}}g',
+    insufficientFilamentLinePooled: '{{printer}} - {{slot}}: wymagane {{required}}g, dostępne {{remaining}}g łącznie na pasujących szpulach (AMS Filament Backup)',
+    printAnyway: 'Drukuj mimo to',
+    forceColorMatch: 'Wymuś dopasowanie koloru',
+    staggerPrinterStarts: 'Rozłóż w czasie starty drukarek',
+    staggerGroupSize: 'Rozmiar grupy',
+    staggerInterval: 'Odstęp (min)',
+    staggerPreview: 'Drukarki: {{printers}} → grupy: {{groups}} po {{size}}, start co {{interval}} min',
+    staggerLastGroup: 'ostatnia grupa: {{count}}',
+    staggerTotal: 'łącznie: {{minutes}} min',
+    staggerToPrinters: 'Rozłóż na drukarki: {{count}}',
+    gcodeInjection: 'Wstrzyknij G-code automatycznego drukowania',
+    insufficientBudget: 'Niewystarczający budżet',
+    unlimitedNoBudget: 'Bez limitu – nie ustawiono limitu budżetu.',
+    noPrintableCostCenters: 'Brak aktywnego centrum kosztów dostępnego do drukowania. Poproś administratora o przyznanie dostępu do drukowania.',
+    askForOutcome: 'Zapytaj o wynik',
+    askForOutcomeTitle: 'Zapytaj po zakończeniu, jak wyszedł wydruk',
+  },
+
+  // Backup
+  backup: {
+    includesEncryptionKey: 'Lokalne kopie zapasowe zawierają plik klucza szyfrowania MFA (DATA_DIR/.mfa_encryption_key), dzięki czemu archiwum ZIP kopii jest kompletne. Traktuj ten ZIP jako poufny — każdy, kto ma ten plik, może odszyfrować przechowywane w nim sekrety klientów OIDC i sekrety TOTP.',
+    title: 'Kopia zapasowa i przywracanie',
+    createBackup: 'Utwórz kopię zapasową',
+    restoreBackup: 'Przywróć kopię zapasową',
+    restoreDescription: 'Zastąp wszystkie dane danymi z pliku kopii zapasowej',
+    downloadBackup: 'Pobierz kopię zapasową',
+    uploadBackup: 'Prześlij kopię zapasową',
+    lastBackup: 'Ostatnia kopia zapasowa',
+    autoBackup: 'Automatyczna kopia zapasowa',
+    backupNow: 'Utwórz kopię teraz',
+    restoreWarning: 'Uwaga: przywrócenie kopii zapasowej nadpisze wszystkie bieżące dane.',
+    includeArchives: 'Uwzględnij archiwa',
+    includeSettings: 'Uwzględnij ustawienia',
+    includeProfiles: 'Uwzględnij profile',
+    backupSuccess: 'Kopia zapasowa została utworzona',
+    restoreSuccess: 'Kopia zapasowa została przywrócona',
+    backupFailed: 'Tworzenie kopii zapasowej nie powiodło się',
+    restoreFailed: 'Przywracanie nie powiodło się',
+    restoreNote: 'Wirtualna drukarka zostanie zatrzymana na czas przywracania',
+
+    // GitHub Backup
+    githubBackup: 'Kopia zapasowa Git',
+    enabled: 'Włączone',
+    cloudLoginRequired: 'Wymagane logowanie do Bambu Cloud. Zaloguj się w Profile → Profile w chmurze, aby włączyć kopię zapasową w GitHub.',
+    cloudLoginRequiredShort: 'Wymagane logowanie do chmury',
+    githubDescription: 'Automatycznie synchronizuj swoje profile z prywatnym repozytorium GitHub jako kopię zapasową i historię wersji.',
+    repoIsPrivate: 'Repozytorium jest prywatne — można bezpiecznie tworzyć w nim kopie.',
+    repoIsPublicWarning: 'Repozytorium jest PUBLICZNE. Kopie zapasowe Bambuddy zawierają dane logowania MQTT, tokeny Home Assistant, tokeny Prometheus, Twój e-mail Bambu Cloud oraz kody dostępu drukarek w profilach K. Zapisywanie jest zablokowane, dopóki nie ustawisz repozytorium jako prywatnego w ustawieniach dostawcy.',
+    repoVisibilityUnknown: 'Nie udało się ustalić widoczności repozytorium. Bambuddy nie tworzy kopii w miejscach, których prywatność nie została potwierdzona; zapisywanie zostanie zablokowane.',
+    repositoryUrl: 'URL repozytorium',
+    repoUrlPlaceholderGitHub: 'https://github.com/username/repo-name',
+	repoUrlPlaceholderGitea: 'https://gitea.example.com/username/repo-name',
+    repoUrlPlaceholderForgejo: 'https://forgejo.example.com/username/repo-name',
+    repoUrlPlaceholderGitLab: 'https://gitlab.com/username/repo-name',
+    allowInsecureHttp: 'Zezwól na niezabezpieczone HTTP',
+    allowInsecureHttpHint: 'Włącz dla samodzielnie hostowanych instancji w sieciach prywatnych bez TLS',
+    personalAccessToken: 'Osobisty token dostępu',
+    tokenSaved: '(zapisano)',
+    enterNewToken: 'Wprowadź nowy token, aby go zaktualizować',
+    tokenHintGitHub: 'Token szczegółowy (fine-grained) z dostępem do odczytu i zapisu Contents lub token klasyczny z zakresem repo.',
+    tokenHintGitLab: 'Token z zakresem api lub z zakresami read_repository i write_repository jednocześnie.',
+    tokenHintGitea: 'Token z zakresem write:repository.',
+    tokenHintForgejo: 'Token z zakresem write:repository. Wystarczy token ograniczony do tego jednego repozytorium.',
+    branch: 'Gałąź',
+    provider: 'Dostawca Git',
+    providerGitHub: 'GitHub',
+    providerGitLab: 'GitLab',
+	providerGitea: 'Gitea',
+    providerForgejo: 'Forgejo',
+    manualOnly: 'Tylko ręcznie',
+    hourly: 'Co godzinę',
+    daily: 'Codziennie',
+    weekly: 'Co tydzień',
+    includeInBackup: 'Uwzględnij w kopii zapasowej',
+    kProfiles: 'Profile K',
+    kProfilesDescription: 'Kalibracja pressure advance z podłączonych drukarek',
+    noPrintersConnected: 'Brak podłączonych drukarek',
+    printersConnected: 'Podłączono {{connected}}/{{total}}',
+    cloudProfiles: 'Profile w chmurze',
+    cloudProfilesDescription: 'Profile filamentów, drukarek i procesów z Bambu Cloud i Orca Cloud',
+    cloudProfilesAccounts: 'Połączone konta — Bambu Cloud: {{bambu}}, Orca Cloud: {{orca}}',
+    appSettings: 'Ustawienia aplikacji',
+    appSettingsDescription: 'Konfiguracja Bambuddy (cała baza danych)',
+    spoolInventory: 'Magazyn szpul',
+    spoolInventoryDescription: 'Szpule filamentu, historia zużycia i śledzenie kosztów',
+    printArchives: 'Archiwa wydruków',
+    printArchivesDescription: 'Metadane historii wydruków (bez plików G-code/3MF)',
+    lastBackupAt: 'Ostatnia kopia:',
+    noBackupsYet: 'Brak kopii zapasowych',
+    next: 'Następna:',
+    startingBackup: 'Uruchamianie kopii zapasowej...',
+    test: 'Testuj',
+    enableBackup: 'Włącz kopię zapasową',
+    testConnection: 'Testuj połączenie',
+    enterRepoUrl: 'Wprowadź URL repozytorium',
+    enterRepoAndToken: 'Wprowadź URL repozytorium i token dostępu',
+    repoRequired: 'URL repozytorium jest wymagany',
+    tokenRequired: 'Token dostępu jest wymagany',
+    githubBackupEnabled: 'Kopia zapasowa GitHub włączona',
+    tokenUpdated: 'Token zaktualizowany',
+    settingsSaved: 'Ustawienia zapisane',
+    failedToSave: 'Nie udało się zapisać: {{message}}',
+    backupCompleteFiles: 'Kopia zapasowa ukończona - zaktualizowane pliki: {{count}}',
+    backupSkippedNoChanges: 'Pominięto kopię zapasową - brak zmian',
+    backupFailed2: 'Tworzenie kopii zapasowej nie powiodło się: {{message}}',
+    clearedLogs: 'Wyczyszczone wpisy dziennika: {{count}}',
+    clearHistoryConfirmTitle: 'Wyczyścić historię kopii zapasowych?',
+    clearHistoryConfirmMessage: 'Spowoduje to usunięcie wszystkich wpisów z historii kopii zapasowych. Same kopie zapasowe zostaną zachowane.',
+    failedToClearLogs: 'Nie udało się wyczyścić dziennika: {{message}}',
+
+    // Restore from Git backup (#2656)
+    restoreFromGit: {
+      button: 'Przywróć z Git',
+      title: 'Przywróć z kopii zapasowej Git',
+      subtitle: 'Wybierz commit i zdecyduj, co przywrócić',
+      commitLabel: 'Commit kopii zapasowej',
+      latestCommit: 'Najnowsza kopia (koniec gałęzi)',
+      categoriesLabel: 'Co przywrócić',
+      inspecting: 'Odczytywanie zawartości kopii zapasowej...',
+      itemCount: 'W kopii: {{count}}',
+      overwriteLabel: 'Nadpisz istniejące wpisy',
+      overwriteOn: 'Istniejące wpisy zostaną zaktualizowane z kopii zapasowej.',
+      overwriteOff: 'Dodawane są tylko brakujące wpisy; istniejące pozostają nietknięte.',
+      selectedCount: 'Wybrano: {{count}}',
+      restoring: 'Przywracanie...',
+      confirmTitle: 'Przywrócić z kopii zapasowej?',
+      confirmMessage: 'Wybrane kategorie zostaną przywrócone z tego commita. Brakujące wpisy zostaną dodane; istniejące pozostaną bez zmian.',
+      confirmMessageOverwrite: 'Wybrane kategorie zostaną przywrócone z tego commita, nadpisując wpisy, które już istnieją lokalnie. Tej operacji nie można cofnąć.',
+      kprofilesOverwriteCaveat: 'Wyjątkiem są profile K: zapis slotu zawsze zastępuje kalibrację na drukarce.',
+      tally: 'Przywrócono: {{restored}}, pominięto: {{skipped}}, nieudane: {{failed}}',
+      reloadHint: 'Przeładuj Bambuddy, aby przywrócone dane były widoczne wszędzie.',
+      partialHint: 'Kategorie wymienione powyżej zostały ukończone i zapisane na dysku. Brakujące nie zostały uruchomione.',
+      failed: 'Przywracanie nie powiodło się.',
+      loadFailed: 'Nie udało się odczytać repozytorium kopii zapasowej.',
+      // Preview caveats. The server sends detail_code + detail_params and the
+      // English detail as defaultValue, same contract as backup.pathCheck.
+      details: {
+        notPresent: 'Brak w tym commicie kopii zapasowej',
+        unreadableJson: 'Nieczytelny JSON: {{paths}}',
+        settingsNoPayload: 'Brak ustawień w danych',
+        settingsCredentialsWillSkip: 'Klucze przypominające dane logowania, które zostaną pominięte: {{count}}',
+        settingsCompanionWillSkip: 'Klucze przypominające dane logowania, które zostaną pominięte: {{count}}; zależne od nich przełączniki pozostaną wyłączone: {{companion}}',
+        settingsCompanionOnlyWillSkip: 'Przełączniki, które pozostaną wyłączone: {{companion}} - danych logowania wymaganych przez każdy z nich nie można przywrócić z kopii zapasowej',
+        settingsDestinationWillKeep: 'Ustawienia pozostawione bez zmian: {{destination}} - wysyłałyby gdzie indziej dane logowania przechowywane tutaj; dane logowania nigdy nie są przywracane',
+        settingsNotRestorableWillSkip: 'Ustawienia, które zostaną pominięte: {{count}} - wartości, których Ustawienia by nie przyjęły, lub klucze, których kopia zapasowa nie przywraca',
+        spoolsUsageCount: 'w tym wpisy zużycia: {{count}}',
+        archivesMetadataOnly: 'Tylko metadane - pliki 3MF i miniatury nie są częścią kopii zapasowej Git',
+        archivesRunsCount: 'w tym wydruki: {{count}} - tylko metadane, pliki 3MF i miniatury nie są częścią kopii zapasowej Git',
+        kprofilesPrinterCount: 'na drukarkach: {{count}}',
+      },
+      // Tally notes, same contract. noData is shared by all four categories:
+      // the category heading renders beside it, so naming the category again
+      // would be redundant.
+      notes: {
+        noData: 'Brak danych tego rodzaju w tej kopii zapasowej',
+        archivesPrinterMissing: 'Niektóre archiwa odwoływały się do drukarek, które już nie istnieją - powiązanie usunięto',
+        archivesProjectMissing: 'Niektóre archiwa odwoływały się do projektów, które już nie istnieją - powiązanie usunięto',
+        archivesNumbersDropped: 'Niektóre archiwa miały gramy, koszty, energię lub czasy druku, które nie są prawidłowymi liczbami - pozostawiono puste',
+        usageNumbersDropped: 'Niektóre wpisy zużycia miały wagi lub koszty, które nie są prawidłowymi liczbami - pozostawiono puste',
+        archivesOwnerCleared: 'Niektóre archiwa odwoływały się do użytkowników, którzy już nie istnieją - właściciel usunięty, więc są widoczne tylko dla użytkowników z uprawnieniem archives:read_all, dopóki administrator nie przypisze ich ponownie',
+        archivesOwnerUnmatched: 'Niektóre archiwa wskazują właściciela, którego ta instancja nie ma - właściciel usunięty zamiast zgadywania na podstawie identyfikatora użytkownika z kopii, więc są widoczne tylko dla użytkowników z uprawnieniem archives:read_all, dopóki administrator nie przypisze ich ponownie',
+        archivesOwnerUnknown: 'Niektóre archiwa przywrócono bez właściciela - ta kopia zapasowa go nie zawiera, więc są widoczne tylko dla użytkowników z uprawnieniem archives:read_all, dopóki administrator nie przypisze ich ponownie',
+        archivesUndeleted: 'Archiwa usunięte po utworzeniu kopii zapasowej są znowu widoczne - nadpisywanie było włączone',
+        archivesMetadataOnly: 'Przywrócone archiwa zawierają tylko metadane - pliki 3MF i miniatury nie są częścią kopii zapasowej Git',
+        archivesMergedFollowed: 'Archiwa scalone z innym nie są przywracane jako osobne wiersze - to, co na nie wskazywało, trafia do archiwum, z którym je scalono',
+        runsArchiveMissing: 'Niektóre wydruki pominięto - ich archiwum nie jest częścią tego przywracania',
+        runsNumbersDropped: 'Niektóre wydruki miały gramy, koszty, energię lub czasy trwania, które nie są prawidłowymi liczbami - pozostawiono puste',
+        runsPrinterMissing: 'Niektóre wydruki odwoływały się do drukarek, które już nie istnieją - powiązanie usunięto, nazwę drukarki zachowano',
+        spoolUsageUnresolved: 'Pominięte wpisy zużycia: {{count}} - ich szpuli nie ma na liście szpul tej kopii zapasowej, więc nie ma ich do czego przypisać.',
+        spoolUsageUnlinked: 'Wpisy zużycia przywrócone bez powiązania z historią wydruków: {{count}} - zaznacz Archiwa wydruków razem z Magazynem szpul, aby je zachować.',
+        spoolTagKept: 'Tagi szpul pozostawione bez zmian: {{count}} - kopia zapasowa wyczyściłaby tag zeskanowany od tego czasu lub przeniosłaby go na drugą szpulę.',
+        settingsCredentialsSkipped: 'Pominięte klucze przypominające dane logowania: {{count}} - wprowadź sekrety ręcznie',
+        settingsAuthSkipped: 'Pominięte ustawienia uwierzytelniania: {{count}} - zmień je w Ustawienia > Uwierzytelnianie, aby nadal działały kontrole blokady',
+        settingsCompanionSkipped: '{{keys}} pozostawiono wyłączone - danych logowania wymaganych przez każde z nich nie można przywrócić z kopii zapasowej, a ta instancja ich nie przechowuje, więc włączenie pozostawiłoby integrację bez uwierzytelnienia',
+        settingsDestinationKept: '{{keys}} pozostawiono bez zmian - ta instancja przechowuje dane logowania, które w przeciwnym razie zostałyby wysłane na adres z kopii zapasowej. Zmień je w Ustawieniach i wprowadź dane logowania ponownie.',
+        settingsTwoFactorSkipped: 'Pominięte ustawienia kodów logowania e-mail: {{count}} - każdy użytkownik włącza lub wyłącza kody e-mail na własnym koncie',
+        settingsInvalidSkipped: '{{keys}} pominięto - wartość w kopii zapasowej nie jest taka, którą przyjęłyby Ustawienia',
+        settingsUnknownSkipped: '{{keys}} pominięto - to nie są ustawienia przywracane z kopii (stan działania, sesje kont lub nieznane klucze)',
+        settingsAddressKept: '{{keys}} pozostawiono bez zmian - decydują, dokąd Bambuddy wysyła dane, e-maile lub kopie zapasowe; zmień je w Ustawieniach',
+        settingsMqttRelayFailed: 'Ustawienia MQTT przywrócono, ale nie udało się ponownie połączyć przekaźnika - uruchom ponownie Bambuddy',
+        kprofilesAlwaysOverwrite: 'Profile K zawsze nadpisują odpowiadający im slot na drukarce',
+        kprofilesAckUnreliable: 'Drukarka, która nie potwierdzi zapisu, i tak jest liczona jako przywrócona - sprawdź profile na drukarce',
+        kprofilesPrinterMissing: 'Brak drukarki o numerze seryjnym {{serial}} - pominięto',
+        kprofilesPrinterOffline: '{{printer}} ({{serial}}) nie jest połączona - pominięto',
+        kprofilesUnknownNozzle: 'Nieoczekiwana średnica dyszy {{nozzle}} dla {{serial}} - wysłano bez zmian',
+        kprofilesUnmatched: 'Profile dla {{nozzle}} bez odpowiednika na {{printer}}: {{count}} - dodano jako nowe profile',
+        kprofilesSendFailed: 'Nie udało się wysłać profili {{nozzle}} do {{printer}} ({{serial}})',
+        kprofilesReadFailed: '{{printer}} ({{serial}}) nie odpowiedziała na odczyt profili K dla {{nozzle}} - nie przywrócono',
+        kprofilesRefused: '{{printer}} ({{serial}}) odrzuciła profile {{nozzle}}: {{reason}}',
+        kprofilesStepFailed: 'Nie udało się ukończyć kroku profili K - {{reason}}. Wszystko, co przywrócono wcześniej, pozostaje zapisane.',
+      },
+    },
+
+    // History
+    history: 'Historia',
+    clear: 'Wyczyść',
+    date: 'Data',
+    status: 'Status',
+    trigger: 'Typ',
+    triggers: {
+      manual: 'Kopia zapasowa (ręczna)',
+      scheduled: 'Kopia zapasowa (zaplanowana)',
+      restore: 'Przywracanie',
+    },
+    commit: 'Commit',
+
+    // Local Backup
+    localBackup: 'Lokalna kopia zapasowa',
+    localBackupDescription: 'Utwórz pełną kopię zapasową danych Bambuddy, w tym bazy danych, archiwów, przesłanych plików i wszystkich pozostałych plików.',
+    downloadBackupLabel: 'Pobierz kopię zapasową',
+    completeBackupZip: 'Pełna kopia zapasowa: baza danych + wszystkie pliki (ZIP)',
+    download: 'Pobierz',
+    preparingBackup: 'Przygotowywanie kopii zapasowej...',
+    creatingArchive: 'Tworzenie archiwum kopii zapasowej... Przy dużych archiwach może to chwilę potrwać.',
+    downloadingFile: 'Pobieranie pliku kopii zapasowej...',
+    backupDownloaded: 'Kopia zapasowa została pobrana',
+    failedToCreateBackup: 'Nie udało się utworzyć kopii zapasowej: {{message}}',
+    restore: 'Przywróć',
+    restoreReplacesAll: 'Przywracanie zastępuje wszystkie dane.',
+    restoreReplacesAllDetail: 'Bieżąca baza danych i pliki zostaną całkowicie zastąpione. Po przywróceniu wymagane jest ponowne uruchomienie.',
+    restoreConfirmTitle: 'Przywróć kopię zapasową',
+    restoreConfirmMessage: 'Czy na pewno chcesz przywrócić dane z „{{filename}}”? Spowoduje to całkowite zastąpienie bieżącej bazy danych i wszystkich plików. Po przywróceniu aplikację trzeba będzie uruchomić ponownie.',
+    restoreConfirmButton: 'Przywróć kopię zapasową',
+    uploadingFile: 'Przesyłanie pliku kopii zapasowej...',
+    backupRestoredRestart: 'Kopia zapasowa przywrócona. Uruchom ponownie Bambuddy.',
+    failedToRestore: 'Nie udało się przywrócić kopii zapasowej. Sprawdź format pliku.',
+    reloadNow: 'Przeładuj teraz',
+    creatingBackup: 'Tworzenie kopii zapasowej',
+    restoringBackup: 'Przywracanie kopii zapasowej',
+    preparing: 'Przygotowywanie...',
+    processing: 'Przetwarzanie...',
+    doNotClosePage: 'Nie zamykaj tej strony ani z niej nie wychodź. Przy dużych kopiach zapasowych ta operacja może potrwać kilka minut.',
+
+    // Restore (GitHubBackupSettings)
+    restoring: 'Przywracanie...',
+
+    // Scheduled local backups (#884)
+    scheduledBackup: 'Zaplanowane kopie zapasowe',
+    scheduledBackupDescription: 'Automatycznie twórz migawki kopii zapasowych według harmonogramu. Katalog wyjściowy można zamontować na NAS lub zewnętrznym magazynie danych.',
+    frequency: 'Częstotliwość',
+    backupTime: 'Godzina',
+    retention: 'Przechowywanie',
+    retentionDescription: 'Liczba przechowywanych kopii zapasowych',
+    outputPath: 'Ścieżka wyjściowa',
+    outputPathPlaceholder: 'Domyślnie: {{path}}',
+    outputPathDescription: 'Pozostaw puste, aby użyć domyślnej lokalizacji',
+    runNow: 'Uruchom teraz',
+    backupFiles: 'Pliki kopii zapasowych',
+    noScheduledBackups: 'Brak kopii zapasowych',
+    deleteBackup: 'Usuń',
+    deleteBackupConfirm: 'Usunąć ten plik kopii zapasowej?',
+    backupRunning: 'Trwa tworzenie kopii zapasowej...',
+    scheduledBackupComplete: 'Kopia zapasowa została utworzona',
+    scheduledBackupFailed: 'Tworzenie kopii zapasowej nie powiodło się',
+    nextBackup: 'Następna kopia zapasowa',
+    backupSize: 'Rozmiar',
+    localTimeHint: 'Czas lokalny ({{tz}})',
+    defaultPathLabel: 'Domyślnie:',
+    // Backup output-path probe (#2544)
+    pathCheck: {
+      title: 'Bambuddy nie może zapisywać w tym katalogu',
+      howToFix: 'Jak to naprawić:',
+      sandboxed: 'Usługa Bambuddy nie może zapisywać w {{path}}. Jej jednostka systemd działa z ProtectSystem=strict, co sprawia, że każdy katalog poza katalogami instalacji, danych i dzienników jest dla usługi tylko do odczytu - nawet taki, w którym możesz zapisywać z własnej powłoki.',
+      read_only: '{{path}} znajduje się w systemie plików tylko do odczytu.',
+      permission_denied: 'Bambuddy nie ma uprawnień do zapisu w {{path}}. Sprawdź właściciela i uprawnienia katalogu.',
+      no_space: 'System plików zawierający {{path}} jest pełny.',
+      not_a_directory: '{{path}} istnieje, ale nie jest katalogiem.',
+      missing: '{{path}} nie istnieje i nie można go utworzyć.',
+      error: 'Bambuddy nie może zapisywać w {{path}}.',
+      ephemeralTitle: 'Te kopie zapasowe nie przetrwają ponownego uruchomienia kontenera',
+      container_ephemeral: '{{path}} znajduje się wewnątrz kontenera Bambuddy, a nie na hoście. Zapisane tam kopie zapasowe zostaną utracone po ponownym utworzeniu kontenera. Zamontuj katalog z hosta:',
+    },
+  },
+
+  // Timelapse editor
+  timelapseEditor: {
+    processing: 'Przetwarzanie…',
+    processingPercent: 'Przetwarzanie… {{percent}}%',
+    failed: 'Przetwarzanie nie powiodło się',
+    cancelled: 'Przetwarzanie anulowane',
+  },
+  // Tags
+  tags: {
+    title: 'Tagi',
+    addTag: 'Dodaj tag',
+    editTag: 'Edytuj tag',
+    deleteTag: 'Usuń tag',
+    tagName: 'Nazwa tagu',
+    tagColor: 'Kolor tagu',
+    noTags: 'Brak tagów',
+    deleteConfirm: 'Czy na pewno chcesz usunąć ten tag?',
+    manageTags: 'Zarządzaj tagami',
+  },
+
+  // Upload modal (archives)
+  uploadModal: {
+    title: 'Prześlij pliki 3MF',
+    dragDrop: 'Przeciągnij i upuść tutaj pliki .3mf',
+    or: 'lub',
+    browseFiles: 'Przeglądaj pliki',
+    extractionInfo: 'Model drukarki zostanie automatycznie odczytany z metadanych pliku 3MF.',
+    uploaded: 'przesłano',
+    failed: 'nieudane',
+    uploading: 'Przesyłanie...',
+    upload: 'Prześlij',
+    uploadFailed: 'Przesyłanie nie powiodło się',
+  },
+
+  // Post-print outcome confirmation dialog (#1898)
+  archivePage: {
+    loadFailed: 'Nie udało się wczytać archiwum.',
+    retry: 'Spróbuj ponownie',
+    printedBeforeLog: 'Wydrukowano, zanim Bambuddy zaczęło rejestrować każdy wydruk: {{status}}.',
+    notFound: 'To archiwum nie istnieje lub nie masz do niego dostępu.',
+    layers: 'Warstwy',
+    edit: 'Edytuj',
+    preview: 'Podgląd 3D',
+    download: 'Pobierz',
+    downloadFailed: 'Pobieranie nie powiodło się',
+    video: 'Film timelapse',
+    allPhotos: 'Wszystkie zdjęcia ({{count}})',
+    photos: 'Zdjęcia ({{count}})',
+    delete: 'Usuń',
+    plates: 'Płyty',
+    printsTitle: 'Historia wydruków',
+    noPrints: 'Ten plik nie został jeszcze wydrukowany.',
+    changeOutcome: 'Zmień wynik',
+    setOutcome: 'Ustaw wynik',
+    noPrinter: 'Drukarka usunięta',
+    printNote: 'Notatka do tego wydruku',
+    notePlaceholder: 'Co było szczególnego w tym wydruku?',
+    noteSaved: 'Notatka zapisana',
+    noteFailed: 'Nie udało się zapisać notatki',
+    editNote: 'Edytuj notatkę',
+    addNote: 'Dodaj notatkę',
+    withEstimate: '{{value}} (szac. {{estimate}})',
+    slicedFor: 'pocięto dla {{model}}',
+    project: 'Projekt:',
+    estimate: 'Szacunek: {{value}}',
+    print: 'Drukuj',
+    slice: 'Potnij',
+    more: 'Więcej działań',
+    fileTitle: 'Plik',
+    layerHeight: 'Wysokość warstwy',
+    nozzle: 'Dysza',
+    bedType: 'Typ płyty roboczej',
+    slicedForLabel: 'Pocięto dla',
+    size: 'Rozmiar',
+    archived: 'Zarchiwizowano',
+    source: 'Źródło',
+    tags: 'Tagi',
+    plateEstimate: 'Szacunek {{value}}',
+    lastVsEstimate: 'Ostatni wydruk a szacunek: {{value}}',
+    printThisPlate: 'Drukuj tę płytę',
+    showPlatePrints: 'Pokaż jej wydruki',
+    allPlates: 'Wszystkie płyty',
+    noPrintsOfPlate: 'Brak jeszcze wydruków tej płyty.',
+    colDate: 'Data',
+    colPlate: 'Płyta',
+    colPrinter: 'Drukarka',
+    colResult: 'Wynik',
+    colTime: 'Czas a szac. płyty',
+    colGrams: 'Gramy',
+    colCost: 'Koszt',
+    colFilament: 'Filament',
+    timeVsEstimate: '{{value}} wobec {{estimate}} ({{delta}})',
+    timeOf: '{{value}} z {{estimate}}',
+    startedEnded: 'Rozpoczęto / zakończono',
+    energy: 'Energia',
+    failureReason: 'Przyczyna niepowodzenia',
+    startedByLabel: 'Uruchomił(a)',
+    reprintThis: 'Wydrukuj ponownie',
+    platesCount: 'Płyty: {{count}}',
+    printsCount: 'Wydruki: {{count}}',
+    goodCount: 'Udane: {{count}}',
+    failedCount: 'Nieudane: {{count}}',
+    close: 'Zamknij',
+  },
+
+  confirmOutcome: {
+    title: 'Jak wyszedł Twój wydruk?',
+    good: 'Dobry',
+    reject: 'Odrzuć',
+    later: 'Zapytaj później',
+    noPhoto: 'Brak zdjęcia gotowego wydruku',
+    savedGood: 'Oznaczono jako dobry element',
+    savedReject: 'Oznaczono jako odrzucony',
+    saveFailed: 'Nie udało się zapisać oceny',
+    rejectReason: 'Powód odrzucenia (opcjonalnie)',
+    noReason: 'Bez powodu',
+    saveReject: 'Zapisz',
+    rejectAndReprint: 'Drukuj ponownie',
+    alreadyGood: 'Już potwierdzono jako dobry element.',
+    alreadyRejected: 'Już oznaczono jako odrzucony.',
+    cardPrompt: 'Jak wyszedł?',
+    sources: {
+      dialog: 'Zapisano w aplikacji.',
+      link: 'Zapisano za pomocą linku jednym kliknięciem.',
+      plateClear: 'Zapisano po opróżnieniu płyty roboczej.',
+      printerCard: 'Zapisano z karty drukarki.',
+      api: 'Zapisano przez API.',
+      reaction: 'Zapisano reakcją na czacie.',
+    },
+  },
+  // Edit archive modal
+  // Edit Archive Modal
+  editArchive: {
+    title: 'Edytuj archiwum',
+    name: 'Nazwa',
+    namePlaceholder: 'Nazwa wydruku',
+    printer: 'Drukarka',
+    noPrinter: 'Brak drukarki',
+    project: 'Projekt',
+    noProject: 'Brak projektu',
+    itemsPrinted: 'Wydrukowane elementy',
+    itemsPrintedHelp: 'Liczba elementów wyprodukowanych w tym zadaniu druku. Wpisz 0, jeśli cała płyta była zepsuta.',
+    filamentUsed: 'Zużyty filament (g)',
+    filamentUsedPlaceholder: 'np. 46.16',
+    filamentUsedHelp: 'Ustaw to ręcznie, gdy wydruk został zarchiwizowany bez pliku 3MF, aby nadal wliczał się do sum filamentu.',
+    filamentUsedLocked: 'Tę wartość mogą zmieniać tylko użytkownicy, którzy mogą edytować wszystkie archiwa: na jej podstawie naliczane są kolejne wydruki tego archiwum.',
+    statusHelp: 'Nieudane i Przerwane liczą się w statystykach jako niepowodzenia. Anulowane liczy się jako zatrzymane i nie obniża wskaźnika powodzenia.',
+    notes: 'Notatki',
+    notesPlaceholder: 'Dodaj notatki o tym wydruku...',
+    externalLink: 'Link zewnętrzny',
+    externalLinkPlaceholder: 'https://printables.com/model/...',
+    externalLinkHelp: 'Link do Printables, Thingiverse lub innego źródła',
+    tags: 'Tagi',
+    tagsPlaceholder: 'Dodaj tagi...',
+    addMoreTags: 'Dodaj więcej tagów...',
+    matchingTags: 'Pasujące do „{{query}}”',
+    existingTags: 'Istniejące tagi',
+    clickToAdd: '(kliknij, aby dodać)',
+    status: 'Status',
+    userVerdict: 'Ocena wyniku',
+    verdicts: {
+      none: 'Nie ustawiono',
+      good: 'Dobry element',
+      reject: 'Odrzucony',
+    },
+    failureReason: 'Przyczyna niepowodzenia',
+    selectReason: 'Wybierz przyczynę...',
+    photos: 'Zdjęcia wydrukowanego rezultatu',
+    photosHelp: 'Kliknij +, aby dodać zdjęcia wydrukowanego rezultatu',
+    printResult: 'Rezultat wydruku',
+    saving: 'Zapisywanie...',
+    // Failure reasons
+    failureReasons: {
+      adhesionFailure: 'Słaba przyczepność',
+      spaghettiDetached: 'Spaghetti / Oderwanie',
+      layerShift: 'Przesunięcie warstw',
+      cloggedNozzle: 'Zatkana dysza',
+      filamentRunout: 'Skończył się filament',
+      warping: 'Odkształcenie (warping)',
+      stringing: 'Nitkowanie (stringing)',
+      underExtrusion: 'Niedoekstrudowanie',
+      powerFailure: 'Awaria zasilania',
+      userCancelled: 'Anulowane przez użytkownika',
+      noStatusUpdate: 'Nie otrzymano aktualizacji stanu',
+      killSwitch: 'Zatrzymano wyłącznikiem awaryjnym drukarki',
+      other: 'Inne',
+    },
+    // Archive statuses
+    statuses: {
+      completed: 'Ukończono',
+      failed: 'Nieudany',
+      aborted: 'Przerwano',
+      cancelled: 'Anulowano',
+      archived: 'Zarchiwizowano',
+      printing: 'Drukowanie',
+    },
+  },
+
+  // K-Profiles
+  kProfiles: {
+    title: 'Profile K',
+    noPrintersConfigured: 'Brak skonfigurowanych drukarek',
+    addPrinterInSettings: 'Dodaj drukarkę w Ustawieniach, aby zarządzać profilami K',
+    noActivePrinters: 'Brak aktywnych drukarek',
+    enablePrinterConnection: 'Włącz połączenie z drukarką, aby zobaczyć jej profile K',
+    loadingProfiles: 'Wczytywanie profili K...',
+    printerOffline: 'Drukarka offline',
+    printerOfflineDesc: 'Wybrana drukarka nie jest połączona. Włącz ją, aby zobaczyć profile K.',
+    readFailed: 'Nie udało się odczytać profili K',
+    noAnswerDesc: 'Drukarka nie odpowiedziała na żądanie profili K. Jej profile mogą nadal istnieć: spróbuj ponownie.',
+    noMatchingProfiles: 'Brak pasujących profili',
+    noMatchingProfilesDesc: 'Żaden profil nie pasuje do kryteriów wyszukiwania',
+    noKProfiles: 'Brak profili K',
+    noKProfilesDesc: 'Nie znaleziono profili pressure advance dla dyszy {{diameter}}mm',
+    createFirstProfile: 'Utwórz pierwszy profil',
+    // Controls
+    printer: 'Drukarka',
+    nozzle: 'Dysza',
+    refresh: 'Odśwież',
+    addProfile: 'Dodaj profil',
+    export: 'Eksportuj',
+    import: 'Importuj',
+    select: 'Zaznacz',
+    selectAll: 'Zaznacz wszystko',
+    delete: 'Usuń',
+    // Filters
+    searchPlaceholder: 'Szukaj po nazwie lub filamencie...',
+    allExtruders: 'Wszystkie ekstrudery',
+    leftOnly: 'Tylko lewy',
+    rightOnly: 'Tylko prawy',
+    allFlow: 'Każdy przepływ',
+    hfOnly: 'Tylko HF',
+    sOnly: 'Tylko S',
+    sortName: 'Sortuj: nazwa',
+    sortKValue: 'Sortuj: wartość K',
+    sortFilament: 'Sortuj: filament',
+    // Dual extruder labels
+    leftExtruder: 'Lewy ekstruder',
+    rightExtruder: 'Prawy ekstruder',
+    // Modal
+    modal: {
+      addTitle: 'Dodaj profil K',
+      editTitle: 'Edytuj profil K',
+      profileName: 'Nazwa profilu',
+      profileNamePlaceholder: 'Mój profil PLA',
+      kValue: 'Wartość K',
+      kValuePlaceholder: '0.020',
+      kValueHelp: 'Typowy zakres: 0.01 - 0.06 dla PLA, 0.02 - 0.10 dla PETG',
+      filament: 'Filament',
+      selectFilament: 'Wybierz filament...',
+      source: {
+        local: 'Zaimportowany',
+        orcaCloud: 'Orca Cloud',
+        bambuCloud: 'Bambu Cloud',
+        builtin: 'Wbudowany',
+      },
+      noFilamentsHelp: 'Brak dostępnych filamentów. Zaloguj się do Bambu Cloud lub zaimportuj profile w Profile → Profile lokalne.',
+      searchFilaments: 'Szukaj filamentów...',
+      noFilamentMatches: 'Żaden filament nie pasuje do wyszukiwania',
+      flowType: 'Typ przepływu',
+      highFlow: 'Wysoki przepływ',
+      standard: 'Standardowy',
+      nozzleSize: 'Rozmiar dyszy',
+      extruder: 'Ekstruder',
+      extruders: 'Ekstrudery',
+      left: 'Lewy',
+      right: 'Prawy',
+      notes: 'Notatki (przechowywane lokalnie)',
+      notesPlaceholder: 'Dodaj notatki o tym profilu...',
+      notesHelp: 'Notatki są zapisywane w Bambuddy, a nie na drukarce',
+      syncing: 'Synchronizacja z drukarką...',
+      savingExtruder: 'Zapisywanie do ekstrudera {{current}}/{{total}}...',
+      pleaseWait: 'Proszę czekać',
+    },
+    // Delete confirmation
+    deleteConfirm: {
+      title: 'Usuń profil',
+      cannotUndo: 'Tej operacji nie można cofnąć',
+      message: 'Czy na pewno chcesz usunąć „{{name}}” z drukarki?',
+    },
+    // Bulk delete
+    bulkDelete: {
+      title: 'Usuń profile',
+      cannotUndo: 'Tej operacji nie można cofnąć',
+      message: 'Czy na pewno chcesz usunąć z drukarki zaznaczone profile (liczba: {{count}})?',
+    },
+    // Toast
+    toast: {
+      profileSaved: 'Profil K zapisany',
+      writeUnconfirmed: 'Wysłano do drukarki, ale nie potwierdziła. Sprawdź listę po jej odświeżeniu.',
+      writesUnconfirmed: 'Drukarka nie potwierdziła części z nich (liczba: {{count}}). Sprawdź listę po jej odświeżeniu.',
+      profilesSaved: 'Profil K zapisany w ekstruderach: {{count}}',
+      selectAtLeastOneExtruder: 'Wybierz co najmniej jeden ekstruder',
+      selectFilament: 'Najpierw wybierz filament',
+      filamentNotResolvable: 'Brak identyfikatora filamentu Bambu dla {{name}} — drukarka nie może zapisać dla niego profilu',
+      profileDeleted: 'Profil K usunięty',
+      profilesDeleted: 'Usunięte profile: {{count}}',
+      exportedProfiles: 'Wyeksportowane profile: {{count}}',
+      importedProfiles: 'Zaimportowano profile: {{count}} z {{total}}',
+      noProfilesToExport: 'Brak profili do eksportu',
+      invalidFileFormat: 'Nieprawidłowy format pliku',
+      failedToParseImport: 'Nie udało się przetworzyć pliku importu',
+      failedToSaveBatch: 'Nie udało się zapisać profili K',
+      noteSaved: 'Notatka zapisana',
+      failedToSaveNote: 'Nie udało się zapisać notatki',
+    },
+    // Permissions
+    permission: {
+      noRead: 'Nie masz uprawnień do odświeżania profili',
+      noCreate: 'Nie masz uprawnień do dodawania profili',
+      noUpdate: 'Nie masz uprawnień do aktualizowania profili K',
+      noDelete: 'Nie masz uprawnień do usuwania profili K',
+      noExport: 'Nie masz uprawnień do eksportowania profili',
+      noImport: 'Nie masz uprawnień do importowania profili',
+    },
+  },
+
+  // Virtual Printer
+  virtualPrinter: {
+    model: {
+      title: 'Model drukarki',
+      description: 'Wybierz model drukarki do emulacji.',
+    },
+    accessCode: {
+      title: 'Kod dostępu',
+      isSet: 'Kod dostępu jest ustawiony',
+      notSet: 'Brak kodu dostępu — wymagany do włączenia',
+      placeholder: 'Wpisz 8-znakowy kod',
+      placeholderChange: 'Wpisz nowy kod, aby zmienić',
+      charCount: '({{count}}/8)',
+      inheritedFromTarget: 'Odziedziczony z drukarki docelowej',
+      derivedFromTargetHint: 'Używa kodu dostępu drukarki docelowej. Mostek przekazuje uwierzytelnianie slicera do prawdziwej drukarki, więc kody muszą być zgodne — aby zmienić tę wartość, edytuj kod dostępu drukarki.',
+      reveal: 'Pokaż kod dostępu',
+      hide: 'Ukryj kod dostępu',
+    },
+    targetPrinter: {
+      title: 'Drukarka docelowa',
+      placeholder: 'Wybierz drukarkę...',
+    },
+    remoteInterface: {
+      title: 'Wymuszenie interfejsu sieciowego',
+      optional: 'Opcjonalne — użyj, jeśli automatycznie wykryty adres IP jest błędny (np. wiele kart sieciowych, Docker, VPN)',
+      placeholder: 'Wykryj automatycznie (domyślnie)...',
+    },
+    mode: {
+      title: 'Tryb',
+      archive: 'Archiwum',
+      archiveDesc: 'Archiwizuj pliki od razu',
+      review: 'Przegląd',
+      reviewDesc: 'Przejrzyj przed archiwizacją',
+      queue: 'Kolejka',
+      queueDesc: 'Archiwizuj i dodaj do kolejki',
+      proxy: 'Proxy',
+      proxyDesc: 'Przekazuj do prawdziwej drukarki',
+    },
+    autoDispatch: {
+      title: 'Automatyczne wysyłanie',
+      description: 'Automatycznie uruchamiaj wydruki po dodaniu do kolejki. Gdy wyłączone, wydruki czekają na ręczne wysłanie.',
+    },
+    queueForceColorMatch: {
+      title: 'Wymuś zgodność koloru',
+      description: 'Odmawiaj wysłania na drukarkę, która nie ma załadowanego dokładnie tego typu i koloru filamentu. Domyślnie wyłączone — bez tej opcji kolejka dopasowuje tylko model i może wybrać drukarkę z załadowanym niewłaściwym kolorem.',
+    },
+    saveAmsMapping: {
+      title: 'Zapisz mapowanie AMS',
+      description: 'Zapisuj w archiwum wybór slotu AMS dokonany przez slicer (z polecenia MQTT project_file), aby późniejszy ponowny wydruk użył dokładnie tej samej fizycznej szpuli zamiast wyznaczać ją ponownie na podstawie typu/koloru z pliku. Domyślnie wyłączone.',
+    },
+    gcodeInjection: {
+      title: 'Wstrzykiwanie G-code',
+      description: 'Stosuj do zadań z tej wirtualnej drukarki fragmenty G-code dla poszczególnych modeli skonfigurowane w Ustawieniach. Domyślnie wyłączone.',
+    },
+    tailscaleDisabled: {
+      title: 'Integracja z Tailscale',
+      description: 'Włącz, aby oznaczyć tę wirtualną drukarkę jako udostępnioną przez Tailscale. Wyświetla adres Tailscale hosta, aby wiadomo było, jaki adres IP wkleić do slicera. Krok importu CA pozostaje bez zmian — ten przełącznik nie wpływa na certyfikaty.',
+    },
+    setupRequired: {
+      title: 'Wymagana konfiguracja',
+      description: 'Funkcja wirtualnej drukarki wymaga dodatkowej konfiguracji systemu, zanim zacznie działać. Obejmuje to przekierowanie portów, reguły zapory i ustawienia zależne od platformy.',
+      readGuide: 'Przed włączeniem przeczytaj instrukcję konfiguracji',
+    },
+    archiveNameSource: {
+      title: 'Źródło nazwy archiwum',
+      description: 'Wybierz, jak nazywane są nowe archiwa, gdy pliki przychodzą przez wirtualną drukarkę. „Metadane” używa tytułu osadzonego przez slicer w pliku 3MF (domyślnie). „Nazwa pliku” używa nazwy pliku wysłanej przez Bambu Studio przez FTP. Uwaga: Bambu Studio zastępuje nazwę wpisaną w oknie „wyślij do drukarki” polem Title z pliku 3MF, jeśli jest ono obecne, więc oba tryby często dają ten sam ciąg znaków.',
+      metadata: 'Metadane',
+      filename: 'Nazwa pliku',
+    },
+    caCert: {
+      title: 'Certyfikat slicera',
+      description: 'Wirtualne drukarki używają certyfikatu TLS podpisanego przez CA Bambuddy. Zaimportuj jednorazowo ten certyfikat CA do magazynu zaufanych certyfikatów slicera, aby akceptował połączenie — nie musisz kopiować go z wiersza poleceń.',
+      copy: 'Kopiuj',
+      copied: 'Skopiowano',
+      download: 'Pobierz',
+      fingerprint: 'SHA-256',
+    },
+    howItWorks: {
+      title: 'Jak to działa',
+      step1: 'W tej samej sieci LAN wirtualne drukarki pojawiają się w slicerze (Bambu Studio / OrcaSlicer) automatycznie dzięki wykrywaniu. Z innych sieci dodaj je ręcznie, podając adres IP i kod dostępu.',
+      step2: 'W trybach Archiwum, Przegląd i Kolejka użyj przycisku „Wyślij” w slicerze, aby przesłać pliki 3MF do Bambuddy. Slicer pokaże „Print success” — plik zostaje zapisany, a nie wydrukowany.',
+      step3: 'W trybie Proxy wirtualna drukarka przekazuje cały ruch do prawdziwej drukarki — wydruki startują od razu, jak przy bezpośrednim połączeniu.',
+    },
+    toast: {
+      updated: 'Zaktualizowano ustawienia wirtualnej drukarki',
+      failedToUpdate: 'Nie udało się zaktualizować ustawień',
+      copyFailed: 'Nie udało się skopiować — spróbuj zaznaczyć tekst ręcznie',
+      accessCodeRequired: 'Najpierw ustaw kod dostępu',
+      targetPrinterRequired: 'Najpierw wybierz drukarkę docelową',
+      bindIpRequired: 'Najpierw ustaw adres IP powiązania',
+      accessCodeEmpty: 'Kod dostępu nie może być pusty',
+      accessCodeLength: 'Kod dostępu musi mieć dokładnie 8 znaków',
+      targetCodeChangedRebind: 'Kod dostępu odpowiada teraz nowej drukarce docelowej. Dodaj to urządzenie ponownie w slicerze, aby pobrać nowy kod.',
+      created: 'Utworzono wirtualną drukarkę',
+      failedToCreate: 'Nie udało się utworzyć wirtualnej drukarki',
+      deleted: 'Usunięto wirtualną drukarkę',
+      failedToDelete: 'Nie udało się usunąć wirtualnej drukarki',
+    },
+    list: {
+      title: 'Wirtualne drukarki',
+      add: 'Dodaj',
+      addFirst: 'Dodaj wirtualną drukarkę',
+      empty: 'Brak skonfigurowanych wirtualnych drukarek. Dodaj jedną, aby zacząć.',
+    },
+    bindIp: {
+      title: 'Interfejs powiązania',
+      placeholder: 'Wybierz interfejs...',
+      hint: 'Interfejs sieciowy, z którym ma się powiązać ta wirtualna drukarka. Musi być unikalny dla każdej drukarki.',
+    },
+    proxy: {
+      accessCodeHint: 'W trybie proxy użyj w slicerze kodu dostępu drukarki docelowej. Połączenie jest przekazywane przezroczyście do prawdziwej drukarki.',
+    },
+    addDialog: {
+      title: 'Dodaj wirtualną drukarkę',
+      name: 'Nazwa',
+      hint: 'Kod dostępu, drukarkę docelową i inne ustawienia możesz skonfigurować po utworzeniu.',
+      create: 'Utwórz',
+    },
+    deleteConfirm: {
+      title: 'Usuń wirtualną drukarkę',
+      message: 'Czy na pewno chcesz usunąć „{{name}}”? Spowoduje to zatrzymanie wszystkich usług tej drukarki.',
+    },
+  },
+
+  // Model Viewer
+  modelViewer: {
+    stepConverting: 'Konwertowanie modelu STEP… {{seconds}} s',
+    stepSlowHint: 'Duże pliki STEP mogą wymagać minuty lub dłużej.',
+    openInSlicer: 'Otwórz w slicerze',
+    openInSlicerWith: 'Otwórz w {{slicer}}',
+    moreSlicerOptions: 'Więcej opcji slicera',
+    openInSlicerFailed: 'Nie udało się otworzyć w slicerze',
+    tabs: {
+      model: 'Model 3D',
+    },
+    notAvailable: 'niedostępne',
+    plates: 'Płyty',
+    allPlates: 'Wszystkie płyty',
+    plateNumber: 'Płyta {{number}}',
+    plateCount: '{{count}} płyta',
+    plateCount_other: 'Płyty: {{count}}',
+    objectCount: '{{count}} obiekt',
+    objectCount_other: 'Obiekty: {{count}}',
+    filamentCount: '{{count}} filament',
+    filamentCount_other: 'Filamenty: {{count}}',
+    eta: 'Pozostało ok. {{minutes}} min',
+    noPreview: 'Brak podglądu dla tego pliku',
+    pagination: {
+      pageOf: 'Strona {{current}} z {{total}}',
+      prev: 'Poprz.',
+      next: 'Dalej',
+    },
+    errors: {
+      failedToLoad: 'Nie udało się wczytać pliku',
+      noMeshes: 'Nie znaleziono siatek w pliku 3MF',
+      unsupportedFormat: 'Nieobsługiwany format pliku',
+    },
+  },
+
+  // Maintenance type descriptions (built-in)
+  maintenanceDescriptions: {
+    lubricateCarbonRods: 'Nasmaruj pręty węglowe, aby zapewnić płynny ruch',
+    lubricateRails: 'Nasmaruj prowadnice liniowe, aby zapewnić płynny ruch',
+    cleanNozzle: 'Wyczyść hotend i dyszę, aby zapobiec zatkaniu',
+    checkBelts: 'Sprawdź naciąg pasków dla dokładnych wydruków',
+    cleanBuildPlate: 'Wyczyść płytę roboczą dla lepszej przyczepności',
+    checkExtruder: 'Sprawdź zużycie kół zębatych ekstrudera',
+    checkCooling: 'Upewnij się, że wentylatory chłodzące działają prawidłowo',
+    generalInspection: 'Ogólny przegląd drukarki',
+    cleanCarbonRods: 'Wyczyść pręty węglowe, aby zmniejszyć tarcie',
+    lubricateSteelRods: 'Nasmaruj pręty stalowe, aby zapewnić płynny ruch',
+    cleanSteelRods: 'Wyczyść pręty stalowe, aby zmniejszyć tarcie',
+    cleanLinearRails: 'Przetrzyj prowadnice liniowe z kurzu i zanieczyszczeń',
+    checkPtfeTube: 'Sprawdź rurkę PTFE pod kątem zużycia lub uszkodzeń',
+    replaceHepaFilter: 'Wymień filtr HEPA dla jakości powietrza',
+    replaceCarbonFilter: 'Wymień filtr z węglem aktywnym',
+    lubricateLeftNozzleRail: 'Nasmaruj prowadnicę lewej dyszy (seria H2)',
+  },
+
+  // Smart Plugs
+  haSensors: {
+    label: 'Czujniki',
+    unavailable: 'Niedostępny',
+    blocksPrints: '{{entity}} — wstrzymuje wydruki podczas alarmu',
+    states: {
+      open: 'Otwarte',
+      closed: 'Zamknięte',
+      unlocked: 'Odblokowane',
+      locked: 'Zablokowane',
+      detected: 'Wykryto',
+      clear: 'Brak',
+      wet: 'Mokro',
+      dry: 'Sucho',
+      problem: 'Problem',
+      ok: 'OK',
+      running: 'Działa',
+      stopped: 'Zatrzymano',
+      on: 'Wł.',
+      off: 'Wył.',
+    },
+    sectionTitle: 'Czujniki Home Assistant (drukarki)',
+    add: 'Dodaj czujnik',
+    addTitle: 'Dodaj czujnik Home Assistant',
+    editTitle: 'Edytuj czujnik Home Assistant',
+    empty: 'Brak czujników. Powiąż kontaktron drzwi lub termometr z Home Assistant, aby wyświetlić go na karcie drukarki.',
+    unknownPrinter: 'Nieznana drukarka',
+    badgeBlocks: 'Wstrzymuje wydruki',
+    badgeNotifies: 'Powiadamia',
+    badgeHidden: 'Ukryty na karcie',
+    printer: 'Drukarka',
+    entity: 'Encja',
+    searchPlaceholder: 'Szukaj encji...',
+    noEntities: 'Brak pasujących encji',
+    name: 'Nazwa wyświetlana',
+    alertWhen: 'Alarm, gdy',
+    alertNever: 'Nigdy — tylko wyświetlanie',
+    alertAbove: 'Powyżej',
+    alertBelow: 'Poniżej',
+    alertHint: 'Stan alarmu wyróżnia czujnik na karcie drukarki i włącza poniższe opcje.',
+    showOnCard: 'Pokaż na karcie drukarki',
+    notifyOnAlert: 'Wyślij powiadomienie, gdy zacznie się alarm',
+    blockPrint: 'Wstrzymuj wydruki z kolejki podczas alarmu',
+    blockPrintHint: 'Zadania pozostają w kolejce i startują same, gdy czujnik wróci do normy. Ignorowane, gdy Home Assistant jest nieosiągalny.',
+    toast: {
+      created: 'Dodano czujnik',
+      updated: 'Zapisano czujnik',
+      deleted: 'Usunięto czujnik',
+    },
+    error: {
+      pickEntity: 'Wybierz encję Home Assistant',
+      nameRequired: 'Wpisz nazwę wyświetlaną',
+      printerRequired: 'Wybierz drukarkę',
+      alertRequired: 'Najpierw ustaw warunek alarmu',
+    },
+  },
+  locationHaSensors: {
+    sectionTitle: 'Czujniki Home Assistant (lokalizacje przechowywania)',
+    sectionDescription:
+      'Powiąż czujniki temperatury, wilgotności lub baterii z Home Assistant z lokalizacjami przechowywania, aby wyświetlać bieżące odczyty na karcie filamentu i w tabeli. W każdej lokalizacji dozwolony jest tylko jeden czujnik danej kategorii.',
+    add: 'Dodaj czujnik',
+    addTitle: 'Dodaj czujnik Home Assistant',
+    editTitle: 'Edytuj czujnik Home Assistant',
+    empty: 'Brak czujników. Powiąż czujnik temperatury lub wilgotności z Home Assistant, aby wyświetlić go na karcie filamentu.',
+    unknownLocation: 'Nieznana lokalizacja',
+    location: 'Lokalizacja przechowywania',
+    showOnCard: 'Pokaż na karcie filamentu',
+    overwriteConfirm: {
+      title: 'Zastąpić istniejący czujnik?',
+      messageTemperature: '„{{location}}” ma już powiązany czujnik temperatury: {{name}}. Kontynuacja spowoduje jego zastąpienie.',
+      messageHumidity: '„{{location}}” ma już powiązany czujnik wilgotności: {{name}}. Kontynuacja spowoduje jego zastąpienie.',
+      messageBattery: '„{{location}}” ma już powiązany czujnik baterii: {{name}}. Kontynuacja spowoduje jego zastąpienie.',
+    },
+    autoAdd: {
+      confirmTitle: 'Dodać też pozostałe czujniki?',
+      confirmMessage: 'Bambuddy znalazł też inne czujniki dla tej lokalizacji. Wybierz, które również dodać.',
+      added: 'Dodano również: {{names}}',
+      noneFound: 'Nie znaleziono pasujących czujników temperatury, wilgotności ani baterii dla tej lokalizacji.',
+      onlyThisOne: 'Tylko ten',
+    },
+    options: {
+      buttonLabel: 'Opcje czujników',
+      title: 'Opcje czujników lokalizacji',
+      description: 'Te wartości są używane, gdy czujnik temperatury, wilgotności lub baterii zostaje powiązany automatycznie razem z pierwszym czujnikiem lokalizacji.',
+      generalSettings: 'Ustawienia ogólne',
+      pollInterval: 'Interwał aktualizacji (sekundy)',
+      pollIntervalHint: 'Jak często Bambuddy odpytuje Home Assistant i odświeża wartości czujników na ekranie. Minimum 60 sekund.',
+      colorizeValues: 'Koloruj wartości czujników względem progów alarmowych',
+      aboveColor: 'Kolor powyżej progu',
+      belowColor: 'Kolor poniżej progu',
+      optimalColor: 'Kolor wartości optymalnej',
+      colors: {
+        red: 'Czerwony',
+        orange: 'Pomarańczowy',
+        yellow: 'Żółty',
+        green: 'Zielony',
+        blue: 'Niebieski',
+        purple: 'Fioletowy',
+        pink: 'Różowy',
+      },
+      saved: 'Zapisano opcje',
+      saveFailed: 'Nie udało się zapisać opcji',
+      reset: 'Resetuj',
+      resetConfirm: {
+        title: 'Zresetować wszystkie istniejące czujniki lokalizacji?',
+        message:
+          'Spowoduje to nadpisanie progów alarmowych, powiadomień i widoczności na karcie każdego istniejącego czujnika temperatury, wilgotności i baterii w lokalizacjach przechowywania wartościami skonfigurowanymi powyżej oraz przywrócenie nazwy każdego czujnika do przyjaznej nazwy z Home Assistant — czujniki drukarek nie są objęte. Tej operacji nie można cofnąć. W zależności od liczby czujników może to chwilę potrwać.',
+      },
+      resetDone: 'Zastosowano do czujników lokalizacji (liczba: {{count}})',
+      resetFailed: 'Nie udało się zresetować czujników lokalizacji',
+    },
+    deleteAllConfirm: {
+      title: 'Usunąć wszystkie czujniki?',
+      message: 'Spowoduje to usunięcie wszystkich czujników powiązanych z „{{location}}” (liczba: {{count}}). Tej operacji nie można cofnąć.',
+    },
+    currentlyBound: 'Obecnie powiązany: {{entity}}',
+    error: {
+      locationRequired: 'Wybierz lokalizację przechowywania',
+    },
+    toast: {
+      created: 'Dodano czujnik',
+      updated: 'Zapisano czujnik',
+      deleted: 'Usunięto czujnik',
+    },
+  },
+  smartPlugs: {
+    offline: 'Offline',
+    admin: 'Administracja',
+    openPlugAdminPage: 'Otwórz stronę administracyjną gniazdka',
+    deleteSmartPlug: 'Usuń inteligentne gniazdko',
+    turnOnSmartPlug: 'Włącz inteligentne gniazdko',
+    turnOffSmartPlug: 'Wyłącz inteligentne gniazdko',
+    turnOn: 'Włącz',
+    turnOff: 'Wyłącz',
+    addSmartPlug: {
+      scanningNetwork: 'Skanowanie sieci...',
+      chooseEntity: 'Wybierz encję...',
+      connectionFailed: 'Połączenie nieudane',
+      searchEntities: 'Szukaj encji...',
+      searchPowerSensors: 'Szukaj czujników mocy...',
+      searchEnergySensors: 'Szukaj czujników energii...',
+      placeholders: {
+        plugName: 'Gniazdko w salonie',
+        mqttStateOnValue: 'ON, true, 1',
+        mqttSameAsPower: 'Taki sam jak temat mocy lub inny',
+      },
+    },
+    // SmartPlugCard
+    linkedTo: 'Powiązane z:',
+    monitorOnly: 'Tylko monitorowanie',
+    alerts: 'Alarmy',
+    scheduleOn: 'Wł. {{time}}',
+    scheduleOff: 'Wył. {{time}}',
+    on: 'Wł.',
+    off: 'Wył.',
+    power: 'Moc',
+    kwhToday: 'kWh dzisiaj',
+    settings: 'Ustawienia',
+    automationSettings: 'Ustawienia automatyzacji',
+    showInSwitchbar: 'Pokaż na pasku przełączników',
+    quickAccessSidebar: 'Szybki dostęp z paska bocznego',
+    enabled: 'Włączone',
+    enableAutomation: 'Włącz automatyzację dla tego gniazdka',
+    autoOn: 'Auto wł.',
+    autoOnDescription: 'Włącz po rozpoczęciu wydruku',
+    autoOff: 'Auto wył.',
+    autoOffDescription: 'Wyłącz po ukończeniu wydruku (jednorazowo)',
+    autoOffPersistent: 'Pozostaw włączone',
+    autoOffPersistentDescription: 'Pozostań włączone między wydrukami zamiast jednorazowo',
+    controlsPrinterPower: 'Zasila drukarkę',
+    controlsPrinterPowerDescription: 'Wyłącz, jeśli to gniazdko zasila tylko akcesorium (wentylator filtra, oświetlenie). W przeciwnym razie wyłączenie gniazdka oznacza drukarkę jako offline.',
+    autoOffAfterDrying: 'Auto wył. po suszeniu',
+    autoOffAfterDryingDescription: 'Wyłącz po zakończeniu suszenia w AMS',
+    delayAfterDryingMinutes: 'Opóźnienie po suszeniu (minuty)',
+    turnOffDelayMode: 'Tryb opóźnienia wyłączenia',
+    time: 'Czas',
+    temp: 'Temp.',
+    delayMinutes: 'Opóźnienie (minuty)',
+    tempThreshold: 'Próg temperatury (°C)',
+    tempThresholdDescription: 'Wyłącza, gdy dysza ostygnie poniżej tej temperatury',
+    edit: 'Edytuj',
+    deleteConfirm: 'Czy na pewno chcesz usunąć „{{name}}”? Tej operacji nie można cofnąć.',
+    turnOnConfirm: 'Czy na pewno chcesz włączyć „{{name}}”?',
+    turnOffConfirm: 'Czy na pewno chcesz wyłączyć „{{name}}”? Spowoduje to odcięcie zasilania podłączonego urządzenia.',
+    failedToTurn: 'Nie udało się przełączyć ({{action}}) „{{name}}”',
+    unknown: 'Nieznany',
+    // AddSmartPlugModal
+    addTitle: 'Dodaj inteligentne gniazdko',
+    editTitle: 'Edytuj inteligentne gniazdko',
+    stopScanning: 'Zatrzymaj skanowanie',
+    discoverTasmota: 'Wykryj urządzenia Tasmota',
+    foundDevices: 'Znalezione urządzenia: {{count}} — kliknij, aby wybrać:',
+    noDevicesFound: 'Nie znaleziono urządzeń Tasmota w sieci',
+    haNotConfigured: 'Home Assistant nie jest skonfigurowany. Skonfiguruj go w',
+    haSettingsPath: 'Ustawienia → Sieć → Home Assistant',
+    selectEntity: 'Wybierz encję *',
+    ipAddress: 'Adres IP *',
+    nameLabel: 'Nazwa *',
+    username: 'Nazwa użytkownika',
+    password: 'Hasło',
+    authHint: 'Pozostaw puste, jeśli urządzenie Tasmota nie wymaga uwierzytelniania',
+    linkToPrinter: 'Powiąż z drukarką',
+    noPrinter: 'Brak drukarki (tylko sterowanie ręczne)',
+    linkingDescription: 'Powiązanie umożliwia automatyczne włączanie/wyłączanie przy rozpoczęciu/ukończeniu wydruku',
+    powerAlerts: 'Alarmy mocy',
+    alertAbove: 'Alarm powyżej (W)',
+    alertBelow: 'Alarm poniżej (W)',
+    alertDescription: 'Otrzymuj powiadomienie, gdy pobór mocy przekroczy te progi. Pozostaw puste, aby wyłączyć dany kierunek.',
+    dailySchedule: 'Harmonogram dzienny',
+    turnOnAt: 'Włącz o',
+    turnOffAt: 'Wyłącz o',
+    scheduleDescription: 'Codziennie automatycznie włączaj/wyłączaj gniazdko o tych godzinach. Pozostaw puste, aby pominąć daną akcję.',
+    showOnPrinterCard: 'Pokaż na karcie drukarki',
+    displayOnPrinterCard: 'Wyświetl przycisk na karcie drukarki',
+    connectedResult: 'Połączono!',
+    deviceLabel: 'Urządzenie: {{name}} - ',
+    stateLabel: 'Stan: {{state}}',
+    test: 'Testuj',
+    delete: 'Usuń',
+    save: 'Zapisz',
+    add: 'Dodaj',
+    cancel: 'Anuluj',
+    failedToStartScan: 'Nie udało się rozpocząć skanowania',
+    nameRequired: 'Nazwa jest wymagana',
+    entityRequired: 'Encja jest wymagana dla gniazdek Home Assistant',
+    mqttTopicRequired: 'Należy skonfigurować co najmniej jeden temat MQTT do monitorowania mocy, energii lub stanu',
+    loadingEntities: 'Wczytywanie encji...',
+    loading: 'Wczytywanie...',
+    failedToLoadEntities: 'Nie udało się wczytać encji: {{error}}',
+    noEntitiesMatching: 'Nie znaleziono encji pasujących do „{{search}}”',
+    noEntitiesAvailable: 'Brak dostępnych encji',
+    searchingEntities: 'Przeszukiwanie wszystkich encji (znaleziono: {{count}})',
+    showingEntities: 'Wyświetlane: switch, light, input_boolean (dostępne: {{count}})',
+    energyMonitoringOptional: 'Monitorowanie energii (opcjonalne)',
+    energyMonitoringHint: 'Wyszukaj i wybierz czujniki dostarczające dane o mocy/energii.',
+    powerSensorW: 'Czujnik mocy (W)',
+    energyTodayKwh: 'Energia dzisiaj (kWh)',
+    totalEnergyKwh: 'Energia łącznie (kWh)',
+    noMatchingSensors: 'Brak pasujących czujników',
+    none: 'Brak',
+    mqttNotConfigured: 'Broker MQTT nie jest skonfigurowany. Ustaw adres brokera w',
+    mqttSettingsPath: 'Ustawienia → Sieć → Publikowanie MQTT',
+    mqttNotConfiguredSuffix: '(nie musisz włączać publikowania, wystarczy uzupełnić dane brokera).',
+    mqttMonitorOnlyDescription: 'Gniazdka MQTT odbierają dane o mocy/energii przez subskrypcję MQTT. Sterowanie włączaniem/wyłączaniem jest niedostępne — użyj brokera MQTT lub systemu automatyki domowej.',
+    powerMonitoring: 'Monitorowanie mocy',
+    energyMonitoring: 'Monitorowanie energii',
+    stateMonitoring: 'Monitorowanie stanu',
+    optional: 'opcjonalne',
+    topic: 'Temat',
+    jsonPath: 'Ścieżka JSON',
+    multiplier: 'Mnożnik',
+    onValue: 'Wartość ON',
+    mqttPowerHint: 'Ścieżka JSON wyodrębnia wartość z ładunku JSON (np. „power_l1”). Pozostaw puste, jeśli temat publikuje surowe wartości liczbowe.\nUżyj mnożnika 0.001 dla mW→W, 1000 dla kW→W.',
+    mqttEnergyHint: 'Ścieżka JSON wyodrębnia wartość z ładunku JSON. Pozostaw puste dla surowych wartości.\nUżyj mnożnika 0.001 dla Wh→kWh, 1000 dla MWh→kWh.',
+    mqttStateHint: 'Ścieżka JSON wyodrębnia wartość z ładunku JSON. Pozostaw puste dla surowych wartości.\nWartość ON: dokładny ciąg oznaczający „ON”. Pozostaw puste, aby wykrywać automatycznie (ON, true, 1).',
+    // REST smart plug
+    restControl: 'Sterowanie',
+    restOnUrl: 'URL włączenia',
+    restOffUrl: 'URL wyłączenia',
+    restOnBody: 'Treść żądania ON',
+    restOffBody: 'Treść żądania OFF',
+    restMethod: 'Metoda HTTP',
+    restHeaders: 'Własne nagłówki (JSON)',
+    restStatusUrl: 'URL stanu',
+    restStatusPath: 'Ścieżka JSON stanu',
+    restStatusOnValue: 'Wartość ON',
+    restPowerUrl: 'URL mocy',
+    restPowerPath: 'Ścieżka JSON mocy',
+    restPowerMultiplier: 'Mnożnik mocy',
+    restEnergyUrl: 'URL energii',
+    restEnergyPath: 'Ścieżka JSON energii (dzisiaj)',
+    restEnergyTotalPath: 'Ścieżka JSON energii (łącznie)',
+    restEnergyTotalMultiplier: 'Mnożnik licznika łącznego',
+    restEnergyTotalPathHint: 'np. aenergy.total',
+    restEnergyTotalHint:
+      'Wiele gniazdek — w tym każde Shelly — podaje tylko licznik łączny, który nigdy się nie zeruje. Należy go wpisać tutaj, a nie w polu powyżej: odczytany jako dzisiejsze zużycie nigdy nie zerowałby się o północy, a pola Wczoraj i Łącznie pozostałyby puste. Bambuddy wylicza z niego wartości Dzisiaj i Wczoraj, co wymaga dnia lub dwóch odczytów. Shelly podaje watogodziny, więc użyj mnożnika 0.001.',
+    restEnergyMultiplier: 'Mnożnik energii',
+    restUrlRequired: 'Dla gniazdek REST wymagany jest co najmniej jeden URL (ON lub OFF)',
+    restHeadersHint: 'np. {"Authorization": "Bearer your-token"}',
+    restBodyHint: 'np. ON, {"state": "on"}',
+    restStatusHint: 'URL odpytywany o bieżący stan',
+    restPathHint: 'np. state lub data.power.status',
+    restPowerUrlHint: 'Osobny URL dla danych o mocy (jeśli pusty, używany jest URL stanu)',
+    restEnergyUrlHint: 'Osobny URL dla danych o energii (jeśli pusty, używany jest URL stanu)',
+    restEnergyHint: 'Każda wartość może używać własnego URL lub URL stanu. Użyj mnożników do konwersji jednostek (np. 0.001, aby przeliczyć Wh na kWh).',
+    testConnection: 'Testuj połączenie',
+    connectionSuccess: 'Połączenie udane',
+    noSwitchesInSwitchbar: 'Brak przełączników na pasku',
+    enableSwitchbarHint: 'Włącz „Pokaż na pasku przełączników” w Ustawienia > Inteligentne gniazdka',
+  },
+
+  // Notifications
+  notifications: {
+    notifyLockScreenWidgets: 'Widżety ekranu blokady (iOS)',
+    notifyLockScreenWidgetsHelp: 'Widżety otrzymują tylko aktywne drukarki poza trybem konserwacji. Notify! pozwala łącznie na 10 widżetów na urządzenie. Dodaj widżet Notify! w opcji Dostosuj ekran blokady w iOS i wybierz drukarkę. Pokazuje stan, postęp i problemy bez odliczania na żywo. iOS odświeża go mniej więcej co 15 minut lub rzadziej.',
+    notifyPhotoUnavailable: 'Odbiorcy przeglądarkowi i grupowi obsługują tylko powiadomienia tekstowe; załączniki ze zdjęciami są niedostępne.',
+    notifyShowStage: 'Pokaż etap wydruku',
+    notifyTimeSensitive: 'Pilne alerty o problemach',
+    notifyTimeSensitiveHelp: 'Oznaczaj nieudane lub zatrzymane wydruki oraz problemy drukarki lub AI jako pilne (Time Sensitive). Pozostałe powiadomienia push pozostają zwykłe.',
+    notifyPrivacy: 'Ukryj nazwę pliku na kafelku',
+    notifyPrivacyHelp: 'Ukrywa nazwy plików tylko w Live Activity. Tekst push nadal korzysta z szablonów powiadomień.',
+    notifyStyle: 'Styl postępu',
+    notifyStyleBar: 'Pasek postępu',
+    notifyStyleSegments: 'Segmenty',
+    notifyStyleNone: 'Bez wskaźnika postępu',
+    notifyDashboardUrl: 'URL pulpitu (opcjonalnie)',
+    notifySymbol: 'Symbol (opcjonalnie)',
+    notifyTint: 'Odcień (opcjonalnie)',
+    notifyAppearance: 'Wygląd Live Activity',
+    notifyMetrics: 'Metryki',
+    notifyMetricsHelp: 'Domyślnie wyświetlany jest licznik czasu. Opcjonalne metryki zastępują wiersz z nazwą pliku.',
+    notifyDeviceId: 'ID urządzenia lub grupy',
+    notifyToken: 'Token Notify!',
+    notifyIconUrl: 'URL ikony (opcjonalnie)',
+    notifyGroupType: 'Wątek powiadomień (opcjonalnie)',
+    notifyGroupTypeHelp: 'Pozostaw puste, aby grupować powiadomienia push według drukarki. Własna wartość grupuje je w tym samym wątku.',
+    notifyLiveActivities: 'Live Activities (iOS)',
+    notifyLiveActivitiesHelp: 'Śledź wydruki na ekranie blokady iOS i w Dynamic Island. Użyj ID urządzenia iOS; dla powiadomień grupowych dodaj osobnego dostawcę.',
+    notifyLifecycleHelp: 'Live Activities automatycznie śledzą każdy wydruk. Poniższe przełączniki zdarzeń sterują tylko alertami push. Godziny ciszy blokują nowe aktywności; istniejące nadal się aktualizują i kończą. Dzienne podsumowania nie opóźniają aktywności.',
+    notifyIosFeaturesUnavailable: 'Live Activities i widżety ekranu blokady wymagają ID urządzenia iOS. ID grup, przeglądarek i macOS obsługują tylko powiadomienia push.',
+    notifyTestHelp: 'Test wysyła powiadomienie push. Live Activity startuje, gdy rozpoczyna się wydruk.',
+    // Provider types
+    providerTypes: {
+      notify: 'Notify!',
+      callmebot: 'CallMeBot/WhatsApp',
+      ntfy: 'ntfy',
+      pushover: 'Pushover',
+      telegram: 'Telegram',
+      email: 'E-mail',
+      discord: 'Discord',
+      webhook: 'Webhook',
+      homeassistant: 'Home Assistant',
+      bark: 'Bark',
+      gotify: 'Gotify',
+    },
+    // Provider descriptions
+    providerDescriptions: {
+      notify: 'Powiadomienia push i Live Activities na iOS przez Notify!',
+      email: 'Powiadomienia e-mail przez SMTP',
+      telegram: 'Powiadomienia przez bota Telegram',
+      discord: 'Wysyłanie na kanał Discord przez webhook',
+      ntfy: 'Darmowe powiadomienia push z możliwością własnego hostingu',
+      pushover: 'Proste, niezawodne powiadomienia push',
+      callmebot: 'Darmowe powiadomienia WhatsApp przez CallMeBot',
+      webhook: 'Ogólne żądanie HTTP POST na dowolny URL',
+      homeassistant: 'Trwałe powiadomienia na pulpicie Home Assistant',
+      bark: 'Powiadomienia push na iOS przez Bark (z możliwością własnego hostingu)',
+      gotify: 'Powiadomienia push przez własny serwer Gotify',
+    },
+    // NotificationProviderCard
+    lastSuccess: 'Ostatnio: {{date}}',
+    error: 'Błąd',
+    printer: 'Drukarka:',
+    allPrinters: 'Wszystkie drukarki',
+    sendTestNotification: 'Wyślij powiadomienie testowe',
+    eventSettings: 'Ustawienia zdarzeń',
+    enabled: 'Włączone',
+    sendFromProvider: 'Wysyłaj powiadomienia od tego dostawcy',
+    // Event categories
+    printEvents: 'Zdarzenia wydruku',
+    printerStatus: 'Stan drukarki',
+    amsAlarms: 'Alarmy AMS',
+    amsHtAlarms: 'Alarmy AMS-HT',
+    printQueue: 'Kolejka druku',
+    // Event tags (badges)
+    start: 'Start',
+    plateCheck: 'Kontrola płyty',
+    complete: 'Ukończono',
+    failed: 'Nieudany',
+    stopped: 'Zatrzymano',
+    progress: 'Postęp',
+    offline: 'Offline',
+    lowFilament: 'Mało filamentu',
+    maintenance: 'Konserwacja',
+    amsHumidity: 'Wilgotność AMS',
+    amsTemp: 'Temp. AMS',
+    amsDryingSuspended: 'Suszenie wstrzymane',
+    amsHtHumidity: 'Wilgotność AMS-HT',
+    amsHtTemp: 'Temp. AMS-HT',
+    bedCooled: 'Stół ostygł',
+    firstLayer: 'Pierwsza warstwa',
+    quiet: 'Cisza',
+    digest: 'Podsumowanie {{time}}',
+    noPhoto: 'Bez zdjęcia',
+    // Event labels (expanded settings)
+    printStarted: 'Rozpoczęto wydruk',
+    plateNotEmpty: 'Płyta nie jest pusta',
+    plateNotEmptyDescription: 'Wykryto obiekty przed wydrukiem',
+    plateClearRequired: 'Wymagane opróżnienie płyty',
+    plateClearRequiredDescription: 'Wydruk zakończony, kolejka czeka na potwierdzenie opróżnienia płyty',
+    printConfirmRequest: 'Potwierdzenie wyniku',
+    printConfirmRequestDescription: 'Poproś o ocenę dobry/odrzucony za pomocą linków jednym dotknięciem, gdy ukończy się wydruk z włączoną tą opcją',
+    plateClear: 'Płyta pusta',
+    printCompleted: 'Ukończono wydruk',
+    bedCooledLabel: 'Stół ostygł',
+    bedCooledDescription: 'Stół ostygł poniżej progu po wydruku',
+    firstLayerCompleteLabel: 'Pierwsza warstwa ukończona',
+    firstLayerCompleteDescription: 'Powiadom ze zdjęciem, gdy pierwsza warstwa się zakończy',
+    pauseUpcomingLabel: 'Zbliża się pauza',
+    pauseUpcomingDescription: 'Uprzedzenie przed pauzą dodaną w slicerze',
+    pauseUpcomingBadge: 'Pauza',
+    connectedApps: 'Połączone aplikacje',
+    appMessages: 'Wiadomości z połączonych aplikacji',
+    appMessagesDescription: 'Dostarczaj wiadomości wysyłane przez inne aplikacje za pośrednictwem Bambuddy, np. Bambuddy Orders',
+    appMessagesBadge: 'Aplikacje',
+    missingSpoolAssignmentLabel: 'Brak przypisania szpuli',
+    billingChargeFailedLabel: 'Nieudane naliczenie kosztów',
+    billingChargeFailedDescription: 'Powiadom, gdy nie udało się zapisać kosztów wydruku',
+    missingSpoolAssignmentDescription: 'Powiadom, gdy wydruk się rozpoczyna, a wymagane sloty nie mają przypisanej szpuli',
+    printFailed: 'Wydruk nieudany',
+    printStopped: 'Wydruk zatrzymany',
+    progressMilestones: 'Etapy postępu',
+    progressMilestonesDescription: 'Powiadamiaj przy 25%, 50%, 75%',
+    printerOffline: 'Drukarka offline',
+    printerError: 'Błąd drukarki',
+    aiFailureDetection: 'Wykrywanie błędów przez AI',
+    aiFailureDetectionDescription: 'Powiadom, gdy AI Obico wykryje możliwy błąd wydruku',
+    lowFilamentLabel: 'Mało filamentu',
+    maintenanceDue: 'Wymagana konserwacja',
+    maintenanceDueDescription: 'Powiadom, gdy potrzebna jest konserwacja',
+    amsHumidityHigh: 'Wysoka wilgotność AMS',
+    amsHumidityHighDescription: 'Wilgotność zwykłego AMS przekracza próg',
+    amsTemperatureHigh: 'Wysoka temperatura AMS',
+    amsTemperatureHighDescription: 'Temperatura zwykłego AMS przekracza próg',
+    amsDryingSuspendedTitle: 'Automatyczne suszenie wstrzymane',
+    amsDryingSuspendedDescription: 'Automatyczne suszenie zrezygnowało z jednostki AMS, ponieważ wilgotność nigdy nie spadła poniżej progu',
+    amsHtHumidityHigh: 'Wysoka wilgotność AMS-HT',
+    amsHtHumidityHighDescription: 'Wilgotność AMS-HT przekracza próg',
+    amsHtTemperatureHigh: 'Wysoka temperatura AMS-HT',
+    amsHtTemperatureHighDescription: 'Temperatura AMS-HT przekracza próg',
+    // Inventory stock alert events
+    inventoryAlerts: 'Alerty magazynowe',
+    stockReorderAlert: 'Alert ponownego zamówienia',
+    stockReorderAlertDescription: 'SKU osiągnął punkt ponownego zamówienia',
+    stockBreakAlert: 'Alert braku zapasu',
+    stockBreakAlertDescription: 'Zapas wyczerpie się przed dostawą uzupełnienia',
+    // Queue events
+    jobAdded: 'Dodano zadanie',
+    jobAddedDescription: 'Zadanie dodane do kolejki',
+    jobAssigned: 'Przypisano zadanie',
+    jobAssignedDescription: 'Zadanie oparte na modelu przypisane do drukarki',
+    jobStarted: 'Rozpoczęto zadanie',
+    jobStartedDescription: 'Zadanie z kolejki rozpoczęło drukowanie',
+    jobWaiting: 'Zadanie oczekuje',
+    jobWaitingDescription: 'Zadanie czeka na filament lub drukarkę',
+    jobSkipped: 'Pominięto zadanie',
+    jobSkippedDescription: 'Zadanie pominięte (poprzednie nieudane)',
+    jobFailed: 'Zadanie nieudane',
+    jobFailedDescription: 'Nie udało się uruchomić zadania',
+    queueComplete: 'Kolejka ukończona',
+    queueCompleteDescription: 'Wszystkie zadania z kolejki zakończone',
+    // Quiet hours
+    quietHours: 'Godziny ciszy',
+    noNotificationsDuring: 'Brak powiadomień w tych godzinach',
+    editProviderToChangeQuietHours: 'Edytuj dostawcę, aby zmienić godziny ciszy',
+    // Daily digest
+    dailyDigest: 'Dzienne podsumowanie',
+    batchNotifications: 'Zbieraj powiadomienia w jedno dzienne podsumowanie',
+    sendAt: 'Wysyłka o {{time}}',
+    editProviderToChangeDigestTime: 'Edytuj dostawcę, aby zmienić godzinę podsumowania',
+    // Actions
+    edit: 'Edytuj',
+    deleteProvider: 'Usuń dostawcę powiadomień',
+    deleteConfirm: 'Czy na pewno chcesz usunąć „{{name}}”? Tej operacji nie można cofnąć.',
+    delete: 'Usuń',
+    // AddNotificationModal
+    addTitle: 'Dodaj dostawcę powiadomień',
+    editTitle: 'Edytuj dostawcę powiadomień',
+    nameLabel: 'Nazwa *',
+    namePlaceholder: 'Moje powiadomienia',
+    providerTypeLabel: 'Typ dostawcy *',
+    configuration: 'Konfiguracja',
+    testConfiguration: 'Testuj konfigurację',
+    printerFilter: 'Filtr drukarek',
+    onlyFromPrinter: 'Wysyłaj powiadomienia tylko o zdarzeniach z tej drukarki',
+    attachPhotoLabel: 'Dołącz zdjęcie',
+    attachPhotoDescription: 'Dołączaj do powiadomień zdjęcie z kamery, jeśli zostało wykonane dla zdarzenia',
+    quietHoursDnd: 'Godziny ciszy (Nie przeszkadzać)',
+    quietStart: 'Początek',
+    quietEnd: 'Koniec',
+    dailyDigestLabel: 'Dzienne podsumowanie',
+    sendDigestAt: 'Wysyłaj podsumowanie o',
+    digestCollected: 'Zdarzenia będą zbierane i wysyłane jako jedno podsumowanie o tej godzinie',
+    notificationEvents: 'Zdarzenia powiadomień',
+    progressPercent: '(25%, 50%, 75%)',
+    bedCooledAfterPrint: '(po ukończeniu wydruku)',
+    haSensorAlert: 'Alarm czujnika drukarki',
+    haSensorAlertDescription: '(powiązany czujnik Home Assistant wymaga uwagi)',
+    locationHaSensorAlert: 'Alarm czujnika lokalizacji przechowywania',
+    locationHaSensorAlertDescription: '(czujnik Home Assistant powiązany z lokalizacją przechowywania wymaga uwagi)',
+    // Per-event ntfy priority (#990)
+    eventPriority: {
+      sectionTitle: 'Priorytet ntfy',
+      helpNtfy: 'Wybierz priorytet dla każdego włączonego zdarzenia. ntfy używa ich do eskalacji alertów (dźwięk, widoczność, zachowanie push). Poziomy nieustawione tutaj używają domyślnej wartości serwera ntfy.',
+      sectionTitleGotify: 'Priorytet Gotify',
+      helpGotify: 'Wybierz priorytet dla każdego włączonego zdarzenia. Bambuddy wysyła do Gotify wartości Min., Niski, Domyślny, Wysoki i Pilny jako 0, 2, 5, 8 i 10. W aplikacji Gotify na Androida poziom Domyślny i wyższe odtwarzają dźwięk, a Wysoki i Pilny wyświetlają wyskakujące okienko.',
+      min: 'Min.',
+      low: 'Niski',
+      default: 'Domyślny',
+      high: 'Wysoki',
+      urgent: 'Pilny',
+    },
+    cancel: 'Anuluj',
+    save: 'Zapisz',
+    add: 'Dodaj',
+    nameRequired: 'Nazwa jest wymagana',
+    fieldRequired: 'Pole {{field}} jest wymagane',
+    haDataInvalid: 'Pole Data musi być prawidłowym obiektem JSON, np. {"priority": "high", "ttl": 0}',
+    haServiceHelp: 'Opcjonalne — domyślnie trwałe powiadomienie w interfejsie Home Assistant. Ustaw usługę notify (np. notify.mobile_app_myphone), aby otrzymywać powiadomienia push na telefonie; automatycznie dołączają one zdjęcie z kamery, gdy jest dostępne, a zewnętrzny URL jest ustawiony w Ustawienia → Sieć.',
+    // Config field labels
+    phoneNumber: 'Numer telefonu',
+    apiKey: 'Klucz API',
+    serverUrl: 'URL serwera',
+    topic: 'Temat',
+    authToken: 'Token uwierzytelniania',
+    userKey: 'Klucz użytkownika',
+    appToken: 'Token aplikacji',
+    priority: 'Priorytet',
+    pushoverRetry: 'Ponawianie alarmowe (s)',
+    pushoverExpire: 'Wygaśnięcie alarmowe (s)',
+    botToken: 'Token bota',
+    chatId: 'ID czatu',
+    telegramThreadId: 'ID tematu forum',
+    telegramThreadIdHelp: 'Opcjonalne. Publikuje w jednym temacie grupy forum — to ostatnia liczba w linku do tematu (t.me/c/.../25). Pozostaw puste dla tematu General.',
+    telegramThreadIdInvalid: 'ID tematu forum musi być liczbą.',
+    telegramVerdictMode: 'Ocena wyniku przez',
+    telegramVerdictModeButtons: 'Przyciski w wiadomości (link)',
+    telegramVerdictModeReactions: 'Reakcja (👍 / 👎)',
+    telegramVerdictModeBoth: 'Przyciski i reakcja',
+    telegramVerdictModeHelp: 'Sposób odpowiedzi na prośbę o ocenę wyniku. Reakcje nie wymagają połączeń przychodzących ani zewnętrznego URL — Bambuddy odpytuje o nie bota. Do reakcji używaj bota, z którego korzysta tylko Bambuddy: inna aplikacja odpytująca tego samego bota (np. Home Assistant) przestaje otrzymywać swoje wiadomości i tak pozostaje nawet po powrocie do przycisków. W grupie bot musi być administratorem, aby widzieć reakcje.',
+    telegramVerdictBadgeReactions: 'Reakcje',
+    telegramVerdictBadgeBoth: 'Przyciski + reakcje',
+    smtpServer: 'Serwer SMTP',
+    smtpPort: 'Port SMTP',
+    security: 'Zabezpieczenia',
+    authentication: 'Uwierzytelnianie',
+    username: 'Nazwa użytkownika',
+    password: 'Hasło',
+    fromEmail: 'E-mail nadawcy',
+    toEmail: 'E-mail odbiorcy',
+    webhookUrl: 'URL webhooka',
+    payloadFormat: 'Format ładunku',
+    authorization: 'Autoryzacja',
+    titleFieldName: 'Nazwa pola tytułu',
+    messageFieldName: 'Nazwa pola wiadomości',
+    // NotificationTemplateEditor
+    editTemplate: 'Edytuj szablon: {{name}}',
+    titleLabel: 'Tytuł',
+    bodyLabel: 'Treść',
+    titlePlaceholder: 'Tytuł powiadomienia...',
+    bodyPlaceholder: 'Treść powiadomienia...',
+    availableVariables: 'Dostępne zmienne',
+    clickToInsert: 'Kliknij, aby wstawić w miejscu kursora w treści',
+    livePreview: 'Podgląd na żywo',
+    hide: 'Ukryj',
+    show: 'Pokaż',
+    loadingPreview: 'Wczytywanie podglądu...',
+    enterTemplateContent: 'Wpisz treść szablonu, aby zobaczyć podgląd',
+    titlePreview: 'Tytuł:',
+    bodyPreview: 'Treść:',
+    photoPreview: 'Zdjęcie:',
+    photoPreviewNote: 'Tylko przykład — dostawcy obsługujący załączniki (ntfy, Pushover, Telegram, Discord, Home Assistant, Bark, webhook Slack) automatycznie dołączają zdjęcie z kamery, jeśli zostało wykonane, niezależnie od treści powyżej.',
+    photoPreviewNoteWithEmail: 'Tylko przykład — dołączane automatycznie u obsługiwanych dostawców (ntfy, Pushover, Telegram, Discord, Home Assistant, Bark, webhook Slack), jeśli wykonano zdjęcie. W przypadku e-maila dodaj {finish_photo_url} do treści powyżej, aby wstawić je w treści wiadomości.',
+    photoPreviewNoteEmailOnly: 'Tylko przykład — to zawsze jest e-mail. Dodaj {finish_photo_url} do treści powyżej, aby wstawić zdjęcie w treści wiadomości; bez tego wysyłany jest tylko tekst.',
+    resetToDefault: 'Przywróć domyślne',
+    titleRequired: 'Tytuł jest wymagany',
+    bodyRequired: 'Treść jest wymagana',
+    // NotificationLogViewer
+    notificationLog: 'Dziennik powiadomień',
+    showFailedOnly: 'Tylko nieudane',
+    last24Hours: 'Ostatnie 24 godziny',
+    last7Days: 'Ostatnie 7 dni',
+    last30Days: 'Ostatnie 30 dni',
+    last90Days: 'Ostatnie 90 dni',
+    justNow: 'Przed chwilą',
+    noFailedNotifications: 'Brak nieudanych powiadomień',
+    noNotificationsLogged: 'Brak zapisanych powiadomień',
+    unknownProvider: 'Nieznany dostawca',
+    logTitle: 'Tytuł',
+    logMessage: 'Wiadomość',
+    logError: 'Błąd',
+    logProvider: 'Dostawca: {{type}}',
+    logTime: 'Czas: {{time}}',
+    refresh: 'Odśwież',
+    clearOld: 'Wyczyść stare',
+    statsSummary: 'Ostatnie dni ({{days}}):',
+    statsNotifications: 'powiadomienia',
+    statsSent: 'Wysłane: {{count}}',
+    statsFailed: 'Nieudane: {{count}}',
+    // Event type labels (for log viewer)
+    eventTypes: {
+      print_start: 'Rozpoczęto wydruk',
+      print_complete: 'Ukończono wydruk',
+      print_failed: 'Wydruk nieudany',
+      print_stopped: 'Wydruk zatrzymany',
+      print_progress: 'Postęp',
+      printer_offline: 'Drukarka offline',
+      printer_error: 'Błąd drukarki',
+      filament_low: 'Mało filamentu',
+      maintenance_due: 'Wymagana konserwacja',
+      test: 'Test',
+    },
+    // User email notification preferences
+    userEmail: {
+      title: 'Powiadomienia',
+      emailNotifications: 'Powiadomienia e-mail',
+      emailNotificationsDesc: 'Otrzymuj powiadomienia e-mail o własnych zadaniach druku. Wiadomości są wysyłane z użyciem systemowych ustawień SMTP skonfigurowanych w zaawansowanym uwierzytelnianiu.',
+      sendingTo: 'Powiadomienia będą wysyłane na adres',
+      noEmailWarning: 'Twoje konto nie ma adresu e-mail. Skontaktuj się z administratorem, aby go dodać.',
+      printJobNotifications: 'Powiadomienia o zadaniach druku',
+      printJobNotificationsDesc: 'Wybierz, które zdarzenia wyzwalają powiadomienia e-mail o zadaniach druku, które zlecasz.',
+      printJobStarts: 'Rozpoczęcie zadania druku',
+      printJobStartsDesc: 'Otrzymuj powiadomienie, gdy rozpocznie się Twoje zadanie druku.',
+      printJobFinishes: 'Zakończenie zadania druku',
+      printJobFinishesDesc: 'Otrzymuj powiadomienie, gdy Twoje zadanie druku zakończy się pomyślnie.',
+      printErrors: 'Błędy wydruku',
+      printErrorsDesc: 'Otrzymuj powiadomienie, gdy Twoje zadanie druku się nie powiedzie lub napotka błąd.',
+      printJobStops: 'Zatrzymanie zadania druku',
+      printJobStopsDesc: 'Otrzymuj powiadomienie, gdy Twoje zadanie druku zostanie anulowane lub zatrzymane.',
+      saveSuccess: 'Zapisano preferencje powiadomień.',
+      saveError: 'Nie udało się zapisać preferencji powiadomień.',
+    },
+  },
+
+  // Rich Text Editor
+  richTextEditor: {
+    bold: 'Pogrubienie',
+    italic: 'Kursywa',
+    underline: 'Podkreślenie',
+    bulletList: 'Lista punktowana',
+    numberedList: 'Lista numerowana',
+    alignLeft: 'Wyrównaj do lewej',
+    alignCenter: 'Wyśrodkuj',
+    alignRight: 'Wyrównaj do prawej',
+    addLink: 'Dodaj link',
+    removeLink: 'Usuń link',
+  },
+
+  // External Links
+  externalLinks: {
+    title: 'Linki na pasku bocznym',
+    sidebarLayout: 'Pasek boczny',
+    sidebarLayoutDescription: 'Pokaż lub ukryj wbudowane strony, dodaj linki zewnętrzne i przeciągaj elementy, aby zmienić kolejność nawigacji na pasku bocznym.',
+    systemPages: 'Strony Bambuddy',
+    externalLinks: 'Linki zewnętrzne',
+    visibleInSidebar: 'Widoczne na pasku bocznym',
+    hiddenFromSidebar: 'Ukryte na pasku bocznym',
+    requiredInSidebar: 'Wymagane na pasku bocznym',
+    hidePage: 'Ukryj stronę',
+    showPage: 'Pokaż stronę',
+    settingsCannotBeHidden: 'Ustawień nie można ukryć',
+    noLinksConfigured: 'Brak skonfigurowanych linków zewnętrznych',
+    deleteLink: 'Usuń link',
+    removeCustomIcon: 'Usuń własną ikonę',
+    openInNewTab: 'Otwórz w nowej karcie',
+    placeholders: {
+      linkName: 'Mój link',
+    },
+  },
+
+  // Keyboard Shortcuts Modal
+  keyboardShortcuts: {
+    title: 'Skróty klawiszowe',
+    navigation: 'Nawigacja',
+    archivesSection: 'Archiwa',
+    kProfilesSection: 'Profile K',
+    generalSection: 'Ogólne',
+    shortcuts: {
+      goToPrinters: 'Przejdź do drukarek',
+      goToArchives: 'Przejdź do archiwów',
+      goToQueue: 'Przejdź do kolejki',
+      goToStats: 'Przejdź do statystyk',
+      goToProfiles: 'Przejdź do profili w chmurze',
+      goToSettings: 'Przejdź do ustawień',
+      focusSearch: 'Przejdź do wyszukiwania',
+      openUploadModal: 'Otwórz okno przesyłania',
+      clearSelection: 'Wyczyść zaznaczenie / opuść pole',
+      contextMenu: 'Menu kontekstowe na kartach',
+      refreshProfiles: 'Odśwież profile',
+      newProfile: 'Nowy profil',
+      exitSelectionMode: 'Zakończ tryb zaznaczania',
+      showHelp: 'Pokaż tę pomoc',
+    },
+    footer: 'Naciśnij Esc lub kliknij poza oknem, aby zamknąć',
+  },
+
+  // Notification Log
+  notificationLog: {
+    title: 'Dziennik powiadomień',
+    events: {
+      printStarted: 'Wydruk rozpoczęty',
+      printComplete: 'Wydruk ukończony',
+      printFailed: 'Wydruk nieudany',
+      printStopped: 'Wydruk zatrzymany',
+      progress: 'Postęp',
+      printerOffline: 'Drukarka offline',
+      printerError: 'Błąd drukarki',
+      lowFilament: 'Mało filamentu',
+      maintenanceDue: 'Wymagana konserwacja',
+      test: 'Test',
+    },
+    timeAgo: {
+      justNow: 'Przed chwilą',
+      minutesAgo: '{{minutes}} min temu',
+      hoursAgo: '{{hours}} godz. temu',
+    },
+  },
+
+  // Restore/Backup Modal
+  restoreBackup: {
+    title: 'Przywróć kopię zapasową',
+    restoring: 'Przywracanie...',
+    restoreComplete: 'Przywracanie zakończone',
+    restoreFailed: 'Przywracanie nieudane',
+    importSettings: 'Importuj ustawienia z pliku kopii zapasowej',
+    pleaseWait: 'Poczekaj, trwa przywracanie danych',
+    clickToSelect: 'Kliknij, aby wybrać plik kopii zapasowej (.json lub .zip)',
+    howDuplicateHandling: 'Jak obsługiwane są duplikaty:',
+    categories: {
+      printers: 'Drukarki',
+      smartPlugs: 'Inteligentne gniazdka',
+      notificationProviders: 'Dostawcy powiadomień',
+      filaments: 'Filamenty',
+      archives: 'Archiwa',
+      pendingUploads: 'Oczekujące przesłania',
+      settingsTemplates: 'Ustawienia i szablony',
+    },
+    matchingInfo: {
+      printers: 'dopasowanie po numerze seryjnym',
+      smartPlugs: 'dopasowanie po adresie IP',
+      notificationProviders: 'dopasowanie po nazwie',
+      filaments: 'dopasowanie po nazwie + typie + producencie',
+      archives: 'dopasowanie po skrócie zawartości',
+      pendingUploads: 'dopasowanie po nazwie pliku',
+      settingsTemplates: 'zawsze nadpisywane',
+    },
+    replaceExisting: 'Zastąp istniejące dane',
+    keepExisting: 'Zachowaj istniejące dane',
+    replaceDescription: 'Nadpisz istniejące elementy danymi z kopii zapasowej',
+    keepDescription: 'Przywróć tylko elementy, które jeszcze nie istnieją',
+    caution: 'Uwaga:',
+    cautionText: 'Nadpisanie zastąpi bieżącą konfigurację danymi z kopii zapasowej. Ze względów bezpieczeństwa kody dostępu drukarek nigdy nie są nadpisywane.',
+    itemsRestored: 'Przywrócone elementy',
+    itemsSkipped: 'Pominięte elementy',
+    restored: 'Przywrócono',
+    skipped: 'Pominięto (już istnieją)',
+    filesLabel: 'Pliki (3MF, miniatury itp.)',
+    newApiKeysGenerated: 'Wygenerowano nowe klucze API',
+    newApiKeysWarning: 'Te klucze są wyświetlane tylko raz. Skopiuj je teraz!',
+    processingBackup: 'Przetwarzanie pliku kopii zapasowej...',
+    noDataFound: 'W pliku kopii zapasowej nie znaleziono danych do przywrócenia.',
+    failedToRestore: 'Nie udało się przywrócić kopii zapasowej. Sprawdź format pliku.',
+  },
+
+  // Backup Export Modal
+  backupExport: {
+    title: 'Eksportuj kopię zapasową',
+    selectData: 'Wybierz dane do uwzględnienia',
+    selectAll: 'Zaznacz wszystko',
+    selectNone: 'Odznacz wszystko',
+    categoryDescriptions: {
+      settings: 'Język, motyw, preferencje aktualizacji',
+      notifications: 'ntfy, Pushover, Discord itp.',
+      templates: 'Własne szablony wiadomości',
+      smartPlugs: 'Konfiguracje gniazdek Tasmota',
+      externalLinks: 'Linki na pasku bocznym do usług zewnętrznych',
+      printers: 'Informacje o drukarkach (bez kodów dostępu)',
+      plateDetection: 'Obrazy referencyjne pustej płyty',
+      filaments: 'Typy i koszty filamentów',
+      maintenance: 'Własne harmonogramy konserwacji',
+      archives: 'Wszystkie dane wydruków + pliki (3MF, miniatury, zdjęcia)',
+      projects: 'Projekty, pozycje BOM i załączniki',
+      pendingUploads: 'Przesłania z wirtualnej drukarki oczekujące na przegląd',
+      apiKeys: 'Klucze API webhooków (przy imporcie generowane są nowe)',
+    },
+    requiresPrinters: 'Wymaga zaznaczenia drukarek',
+    zipFileWarning: 'Zostanie utworzony plik ZIP.',
+    zipFileDescription: 'Zawiera wszystkie pliki 3MF, miniatury, timelapse\'y i zdjęcia. Może to chwilę potrwać, a plik może być duży.',
+    includeAccessCodes: 'Dołącz kody dostępu',
+    includeAccessCodesDescription: 'Do przeniesienia na inny komputer',
+    includeAccessCodesWarning: 'Kody dostępu zostaną zapisane jako zwykły tekst. Przechowuj ten plik kopii zapasowej w bezpiecznym miejscu!',
+    categoriesSelected: 'Wybrane kategorie: {{selectedCount}}',
+  },
+
+  // Pending Uploads Panel
+  pendingUploads: {
+    placeholders: {
+      notes: 'Dodaj notatki o tym wydruku...',
+    },
+    discardUpload: 'Odrzuć przesłanie',
+    archiveAllUploads: 'Zarchiwizuj wszystkie przesłania',
+    discardAllUploads: 'Odrzuć wszystkie przesłania',
+    archive: 'Zarchiwizuj',
+    timeAgo: {
+      justNow: 'Przed chwilą',
+      minutesAgo: '{{minutes}} min temu',
+      hoursAgo: '{{hours}} godz. temu',
+      daysAgo: '{{days}} d temu',
+    },
+  },
+
+  // API Browser
+  apiBrowser: {
+    placeholders: {
+      requestBody: 'Treść żądania JSON...',
+      searchEndpoints: 'Szukaj endpointów...',
+    },
+  },
+
+  // Configure AMS Slot Modal
+  configureAmsSlot: {
+    title: 'Konfiguruj slot AMS',
+    slotConfigured: 'Slot skonfigurowany!',
+    configuringSlot: 'Konfigurowanie slotu:',
+    slotLabel: '{{ams}} slot {{slot}}',
+    searchPresets: 'Szukaj profili...',
+    colorPlaceholder: 'Nazwa koloru lub hex (np. brown, FF8800)',
+    clearCustomColor: 'Wyczyść własny kolor',
+    noCloudPresets: 'Brak profili w chmurze. Zaloguj się do Bambu Cloud, aby je zsynchronizować.',
+    noPresetsAvailable: 'Brak dostępnych profili. Zaloguj się do Bambu Cloud lub zaimportuj profile lokalne.',
+    noMatchingPresets: 'Nie znaleziono pasujących profili.',
+    custom: 'Własne',
+    builtin: 'Wbudowane',
+    orcaCloud: 'Orca Cloud',
+    bambuCloud: 'Bambu Cloud',
+    settingsSentToPrinter: 'Ustawienia wysłane do drukarki',
+    filamentProfile: 'Profil filamentu',
+    kProfileLabel: 'Profil K (pressure advance)',
+    filteringFor: 'Filtrowanie dla: {{material}}',
+    noKProfile: 'Brak profilu K (użyj domyślnego 0.020)',
+    noMatchingKProfiles: 'Nie znaleziono pasujących profili K. Zostanie użyte domyślne K=0.020.',
+    kProfilesUnread: 'Drukarka nie odpowiedziała, więc nie udało się odczytać jej profili K. Zostanie użyte domyślne K=0.020.',
+    otherKProfiles: 'Inne profile K na tej drukarce',
+    selectFilamentFirst: 'Najpierw wybierz profil filamentu',
+    kFromCalibration: 'K={{value}} z kalibracji drukarki',
+    customColorLabel: 'Własny kolor (opcjonalnie)',
+    presetColors: 'Kolory {{name}}:',
+    showLessColors: 'Pokaż mniej kolorów',
+    showMoreColors: 'Pokaż więcej kolorów',
+    clear: 'Wyczyść',
+    hexLabel: 'Hex: #{{hex}}',
+    resetting: 'Resetowanie...',
+    resetSlot: 'Resetuj slot',
+    resetConfirmTitle: 'Zresetować slot?',
+    resetConfirmMessage: 'Spowoduje to wyczyszczenie ustawienia filamentu tego slotu na drukarce.',
+    resetBlockedPrinting: 'Niedostępne podczas drukowania',
+    cancel: 'Anuluj',
+    configuring: 'Konfigurowanie...',
+    configureSlot: 'Konfiguruj slot',
+    kValueUnsent: 'Filament został ustawiony, ale nie udało się wysłać wartości K do drukarki.',
+    // Why an Orca profile went into the slot as the generic for its material (#3216)
+    orcaFallback: {
+      no_filament_id: 'Ten profil Orca nie ma własnego ID filamentu, więc OrcaSlicer będzie widział ten slot jako Generic {{material}}.',
+      lookup_failed: 'Nie udało się odczytać ID filamentu tego profilu z Orca Cloud, więc OrcaSlicer będzie widział ten slot jako Generic {{material}}. Spróbuj ponownie za chwilę.',
+      no_permission: 'Nie masz dostępu do Orca Cloud, więc nie udało się odczytać ID filamentu tego profilu. OrcaSlicer będzie widział ten slot jako Generic {{material}}.',
+    },
+  },
+
+  // Git Backup Settings
+  githubBackup: {
+    title: 'Kopia zapasowa Git',
+    history: 'Historia',
+    downloadBackup: 'Pobierz kopię zapasową',
+    restoreBackup: 'Przywróć kopię zapasową',
+    noBackupsYet: 'Brak kopii zapasowych',
+  },
+
+  // Email Settings
+  emailSettings: {
+    placeholders: {
+      fromName: 'BamBuddy',
+    },
+  },
+
+  // Tag Management Modal
+  tagManagement: {
+    searchTags: 'Szukaj tagów...',
+    renameTag: 'Zmień nazwę tagu',
+    deleteTag: 'Usuń tag',
+  },
+
+  // Notification Template Editor
+  notificationTemplates: {
+    placeholders: {
+      title: 'Tytuł powiadomienia...',
+      body: 'Treść powiadomienia...',
+    },
+  },
+
+  // Batch Tag Modal
+  batchTag: {
+    placeholders: {
+      newTag: 'Wpisz nowy tag...',
+    },
+  },
+
+  // Photo Gallery Modal
+  photoGallery: {
+    deletePhoto: 'Usuń zdjęcie',
+  },
+
+  // Filament Hover Card
+  filamentHoverCard: {
+    copySpoolUuid: 'Kopiuj UUID szpuli',
+  },
+
+  // K Profiles View
+  kProfilesView: {
+    hasNote: 'Ma notatkę',
+    copyProfile: 'Kopiuj profil',
+  },
+
+  // Layout/Navigation
+  layout: {
+    openMenu: 'Otwórz menu',
+    noPermissionSystemInfo: 'Nie masz uprawnień do wyświetlania informacji o systemie',
+  },
+
+  // Dashboard
+  dashboard: {
+    dragToReorder: 'Przeciągnij, aby zmienić kolejność',
+    hideWidget: 'Ukryj widżet',
+  },
+
+  // Notification Provider Card
+  notificationProviderCard: {
+    deleteNotificationProvider: 'Usuń dostawcę powiadomień',
+  },
+
+  // File Manager Modal
+  fileManagerModal: {
+    closeFileManager: 'Zamknij menedżer plików',
+    sortFiles: 'Sortuj pliki',
+    goToParentFolder: 'Przejdź do folderu nadrzędnego',
+    threeView: 'Widok 3D',
+  },
+
+  // Embedded Camera Viewer
+  embeddedCameraViewer: {
+    refreshStream: 'Odśwież strumień',
+    close: 'Zamknij',
+    zoomOut: 'Pomniejsz',
+    resetZoom: 'Resetuj powiększenie',
+    zoomIn: 'Powiększ',
+    dragToResize: 'Przeciągnij, aby zmienić rozmiar',
+  },
+
+  // Timelapse Viewer
+  timelapseViewer: {
+    speed: 'Prędkość:',
+    skipBack5s: 'Cofnij o 5 s',
+    skipForward5s: 'Przewiń o 5 s',
+  },
+
+  // Notification Providers
+  notificationProviders: {
+    descriptions: {
+      email: 'Powiadomienia e-mail przez SMTP',
+      telegram: 'Powiadomienia przez bota Telegram',
+      discord: 'Wysyłanie na kanał Discord przez webhook',
+      ntfy: 'Darmowe powiadomienia push z możliwością własnego hostingu',
+      pushover: 'Proste, niezawodne powiadomienia push',
+      callmebot: 'Darmowe powiadomienia WhatsApp przez CallMeBot',
+      webhook: 'Ogólne żądanie HTTP POST na dowolny URL',
+    },
+  },
+
+  // Log Viewer
+  logViewer: {
+    searchPlaceholder: 'Szukaj w treści lub nazwie loggera...',
+    noLogEntries: 'Nie znaleziono wpisów dziennika',
+  },
+
+  // Switchbar Popover
+  switchbarPopover: {
+    noSwitchesInSwitchbar: 'Brak przełączników na pasku przełączników',
+  },
+
+  // Project Page Modal
+  projectPageModal: {
+    placeholders: {
+      title: 'Tytuł',
+      designer: 'Projektant',
+      license: 'Licencja',
+      description: 'Wpisz opis...',
+      profileTitle: 'Tytuł profilu',
+      profileDescription: 'Opis profilu...',
+    },
+  },
+
+  // Spoolman Settings
+  spoolmanSettings: {},
+
+  // Time
+  time: {
+    unknown: '-',
+    waiting: 'Oczekiwanie',
+    justNow: 'Przed chwilą',
+    now: 'Teraz',
+    minsAgo: '{{count}} min temu',
+    inMins: 'za {{count}} min',
+    hoursAgo: '{{count}} godz. temu',
+    inHours: 'za {{count}} godz.',
+    daysAgo: '{{count}} d temu',
+    inDays: 'za {{count}} d',
+  },
+
+  // SpoolBuddy Kiosk
+  spoolbuddy: {
+    nav: {
+      dashboard: 'Pulpit',
+      ams: 'AMS',
+      inventory: 'Magazyn',
+      writeTag: 'Zapis',
+      settings: 'Ustawienia',
+    },
+    status: {
+      nfcReady: 'NFC gotowe',
+      nfcOff: 'NFC wyłączone',
+      offline: 'Offline',
+      online: 'Online',
+      noPrinters: 'Brak drukarek',
+      deviceOffline: 'Urządzenie offline',
+      waitingConnection: 'Oczekiwanie na połączenie z urządzeniem...',
+      systemReady: 'System gotowy',
+      spoolmanUnavailable: 'Spoolman jest niedostępny, więc nie udało się wyszukać tagu',
+      lookupFailed: 'Wyszukiwanie tagu nie powiodło się',
+      status: 'Status',
+    },
+    dashboard: {
+      readyToScan: 'Gotowe do skanowania',
+      idleMessage: 'Połóż szpulę na wadze, aby ją zidentyfikować',
+      nfcHint: 'Tag NFC zostanie odczytany automatycznie',
+      device: 'Urządzenie',
+      syncWeight: 'Synchronizuj wagę',
+      weightSynced: 'Zsynchronizowano!',
+      unknownTag: 'Nieznany tag',
+      newTag: 'Wykryto nowy tag',
+      onScale: 'na wadze',
+      linkSpool: 'Powiąż ze szpulą',
+      linkTagTitle: 'Powiąż tag ze szpulą',
+      linkTag: 'Powiąż tag',
+      selectSpool: 'Wybierz szpulę, z którą powiązać ten tag:',
+      noUntagged: 'Nie znaleziono szpul bez tagów',
+      tagDetected: 'Wykryto tag',
+      noTag: 'Brak tagu',
+      tagId: 'Tag',
+      grossWeight: 'Waga brutto',
+      spoolSize: 'Rozmiar szpuli',
+      close: 'Zamknij',
+      currentSpool: 'Bieżąca szpula',
+      plateReady: 'Płyta gotowa: {{name}}',
+      plateReadyLabel: 'Płyty gotowe do opróżnienia',
+      plateClearAction: 'Opróżnij',
+      plateClearedToast: 'Płyta oznaczona jako opróżniona',
+      plateClearFailed: 'Nie udało się oznaczyć płyty jako opróżnionej',
+    },
+    modal: {
+      assignToAms: 'Przypisz do AMS',
+      syncWeight: 'Synchronizuj wagę',
+      addToInventory: 'Dodaj do magazynu',
+      quickAddFromTag: 'Dodaje tę szpulę z danymi odczytanymi z jej tagu Bambu. Możesz je później edytować w Bambuddy.',
+      assignToAmsTitle: 'Przypisz do AMS',
+      selectSlot: 'Wybierz slot',
+      assign: 'Przypisz',
+      assigning: 'Przypisywanie...',
+      assignSuccess: 'Przypisano!',
+      assignPendingInsert: 'Przypisano. Slot zostanie skonfigurowany po włożeniu szpuli.',
+      assignError: 'Nie udało się przypisać szpuli. Spróbuj ponownie.',
+      noPrinterSelected: 'Wybierz drukarkę...',
+      noAmsDetected: 'Nie wykryto AMS na tej drukarce',
+      slot: 'Slot',
+    },
+    weight: {
+      tare: 'Taruj',
+      calibrate: 'Kalibruj',
+    },
+    spool: {
+      remaining: 'Pozostało',
+      material: 'Materiał',
+      brand: 'Producent',
+      color: 'Kolor',
+      coreWeight: 'Rdzeń',
+      labelWeight: 'Nominalna',
+      scaleWeight: 'Waga',
+      netWeight: 'Netto',
+      lastUsed: 'Ostatnio użyta',
+      unknownColor: 'Nieznany kolor',
+    },
+    ams: {
+      noData: 'Nie wykryto AMS',
+      connectAms: 'Podłącz AMS, aby zobaczyć sloty filamentu',
+      noPrinter: 'Nie wybrano drukarki',
+      selectPrinter: 'Wybierz drukarkę na górnym pasku',
+      printerDisconnected: 'Drukarka rozłączona',
+      humidity: 'Wilgotność',
+      level: 'Poziom',
+      active: 'Aktywny',
+      slot: 'Slot',
+      empty: 'Pusty',
+    },
+    inventory: {
+      search: 'Szukaj szpul...',
+      empty: 'Brak szpul w magazynie',
+      noResults: 'Brak pasujących szpul',
+      spools: 'szt.',
+      addSpool: 'Dodaj szpulę',
+    },
+    settings: {
+      // Tabs
+      tabDevice: 'Urządzenie',
+      tabDisplay: 'Ekran',
+      tabScale: 'Waga',
+      tabUpdates: 'Aktualizacje',
+      // Device tab
+      nfcReader: 'Czytnik NFC',
+      type: 'Typ',
+      connection: 'Połączenie',
+      notConnected: 'b.d.',
+      deviceInfo: 'Informacje o urządzeniu',
+      hostname: 'Host',
+      uptime: 'Czas działania',
+      systemConfig: 'Backend i uwierzytelnianie',
+      backendUrl: 'URL backendu Bambuddy',
+      apiToken: 'Token API',
+      apiTokenPlaceholder: 'Wpisz token API',
+      saveConfig: 'Zapisz konfigurację',
+      systemSavedRestart: 'Zapisano. Uruchom ponownie demona, aby zastosować zmiany.',
+      systemApplying: 'Oczekiwanie, aż urządzenie przejmie konfigurację...',
+      systemRestarting: 'Ponowne uruchamianie demona...',
+      nfcDiagnostic: 'Diagnostyka NFC',
+      scaleDiagnostic: 'Diagnostyka wagi',
+      readTagDiagnostic: 'Diagnostyka odczytu tagu',
+      testNfc: 'Testuj czytnik',
+      testScale: 'Testuj dokładność',
+      testReadTag: 'Odczytaj tag',
+      systemFieldsRequired: 'URL backendu jest wymagany.',
+      // Display tab
+      brightness: 'Jasność',
+      saved: 'Zapisano',
+      noBacklight: 'Nie wykryto podświetlenia DSI. Regulacja jasności wymaga wyświetlacza DSI.',
+      screenBlank: 'Czas do wygaszenia ekranu',
+      screenBlankDesc: 'Ekran wyłącza się po okresie bezczynności. Dotknij, aby wybudzić.',
+      displayNote: 'Jasność jest stosowana jako filtr programowy.',
+      // Scale tab
+      scaleCalibration: 'Kalibracja wagi',
+      currentWeight: 'Bieżąca waga',
+      tareOffset: 'Tara',
+      calFactor: 'Współczynnik',
+      knownWeight: 'Znana masa',
+      calStep1: 'Zdejmij wszystko z wagi i naciśnij Ustaw zero.',
+      calStep2: 'Połóż na wadze przedmiot o znanej masie.',
+      setZero: 'Ustaw zero',
+      calibrateNow: 'Kalibruj',
+      calibrated: 'Skalibrowano',
+      tareSet: 'Wysłano polecenie tarowania. Oczekiwanie na urządzenie...',
+      tareComplete: 'Tarowanie zakończone!',
+      tareTimedOut: 'Przekroczono czas tarowania — czy demon SpoolBuddy działa?',
+      tareFailed: 'Nie udało się wysłać polecenia tarowania',
+      zeroSet: 'Ustawiono punkt zerowy. Połóż na wadze przedmiot o znanej masie.',
+      calibrationDone: 'Kalibracja zakończona!',
+      calibrationFailed: 'Kalibracja nieudana',
+      lastCalibrated: 'Ostatnia kalibracja',
+      stable: 'Stabilna',
+      settling: 'Stabilizowanie...',
+      firmware: 'Firmware',
+      scale: 'Waga',
+      noDevice: 'Nie znaleziono urządzenia SpoolBuddy',
+      // Updates tab
+      daemonVersion: 'Wersja demona',
+      currentVersion: 'Bieżąca',
+      versionPending: 'Oczekiwanie na demona...',
+      checking: 'Sprawdzanie...',
+      checkUpdates: 'Sprawdź aktualizacje',
+      updateAvailable: 'Dostępna aktualizacja',
+      updateInstructions: 'Aktualizacja przez SSH: uruchom skrypt instalacyjny SpoolBuddy, aby zaktualizować.',
+      upToDate: 'Aktualne',
+      includeBeta: 'Uwzględnij wersje beta',
+    },
+    writeTag: {
+      tabExisting: 'Istniejąca szpula',
+      tabNew: 'Nowa szpula',
+      tabReplace: 'Zastąp tag',
+      searchPlaceholder: 'Szukaj po materiale, kolorze, producencie...',
+      noUntaggedSpools: 'Brak szpul bez tagów',
+      noTaggedSpools: 'Brak szpul z tagami',
+      selectSpool: 'Wybierz szpulę, a następnie połóż pusty NTAG na czytniku',
+      placeTag: 'Połóż NTAG na czytniku',
+      tagReady: 'Wykryto tag — gotowe do zapisu',
+      writeTag: 'Zapisz tag',
+      replaceTag: 'Zastąp tag',
+      writing: 'Zapisywanie tagu...',
+      waiting: 'Oczekiwanie na SpoolBuddy...',
+      writeSuccess: 'Tag zapisany pomyślnie!',
+      writeFailed: 'Zapis nieudany',
+      linkFailedSpoolmanNotConfigured: 'Tag został zapisany, ale Spoolman nie jest skonfigurowany, więc tag nie jest powiązany ze szpulą',
+      linkFailedSpoolman: 'Tag został zapisany, ale nie udało się powiązać go ze szpulą w Spoolman',
+      linkFailedSpoolNotFound: 'Tag został zapisany, ale szpula już nie istnieje',
+      spoolmanUnavailable: 'Spoolman jest niedostępny. Sprawdź jego URL w ustawieniach Spoolman.',
+      queueFailed: 'Nie udało się dodać polecenia zapisu do kolejki',
+      linkedToAms: 'Ta szpula jest powiązana ze swoim tagiem RFID Bambu przez AMS. Naklejka zastąpiłaby to powiązanie w Spoolman.',
+      tryAgain: 'Spróbuj ponownie',
+      cancel: 'Anuluj',
+      replaceWarning: 'Stary tag zostanie odłączony. Nowy tag go zastąpi.',
+      deviceOffline: 'SpoolBuddy jest offline',
+      material: 'Materiał',
+      colorName: 'Nazwa koloru',
+      color: 'Kolor',
+      brand: 'Producent',
+      weight: 'Waga (g)',
+      createSpool: 'Utwórz szpulę',
+      creating: 'Tworzenie...',
+      spoolCreated: 'Szpula utworzona! Gotowe do zapisu.',
+      createFailed: 'Nie udało się utworzyć szpuli',
+      incompleteDataWarning: 'Tag zapisany z niekompletnymi danymi Spoolman',
+    },
+    quickMenu: {
+      printerPower: 'Zasilanie drukarki',
+      systemControls: 'System',
+      restartDaemon: 'Uruchom ponownie demona',
+      restartBrowser: 'Uruchom ponownie przeglądarkę',
+      reboot: 'Uruchom ponownie',
+      shutdown: 'Wyłącz',
+      swipeToClose: 'Przesuń w dół, aby zamknąć',
+      confirmTitle: 'Potwierdź',
+      confirmShutdown: 'Czy na pewno chcesz wyłączyć SpoolBuddy? Aby go ponownie włączyć, potrzebny będzie fizyczny dostęp.',
+      confirmReboot: 'Czy na pewno chcesz ponownie uruchomić SpoolBuddy?',
+      confirmRestartDaemon: 'Uruchomić ponownie demona SpoolBuddy? NFC i waga będą chwilowo niedostępne.',
+      confirmRestartBrowser: 'Uruchomić ponownie przeglądarkę kiosku? Ekran na chwilę zgaśnie.',
+      confirm: 'Potwierdź',
+      confirmPlugOn: 'Włączyć {{name}}?',
+      confirmPlugOff: 'Wyłączyć {{name}}?',
+      turnOn: 'Włącz',
+      turnOff: 'Wyłącz',
+    },
+  },
+
+  diagnostic: {
+    modalTitle: 'Diagnostyka połączenia — {{name}}',
+    running: 'Trwa diagnostyka...',
+    runningElapsed: 'Trwa diagnostyka... ({{elapsed}} s)',
+    waitingForReportHint: 'Oczekiwanie, aż drukarka opublikuje raport stanu — może to potrwać do {{max}} s.',
+    runFailed: 'Nie udało się uruchomić diagnostyki: {{error}}',
+    retry: 'Uruchom ponownie',
+    runButton: 'Uruchom diagnostykę',
+    sectionTitle: 'Diagnostyka połączenia',
+    sectionDescription: 'Sprawdź, dlaczego drukarka nie łączy się lub nie drukuje — dostępność portów, tryb dewelopera LAN, tryb sieci Docker i dane logowania.',
+    noPrinters: 'Brak skonfigurowanych drukarek.',
+    overall: {
+      ok: 'Nie znaleziono problemów — połączenie z drukarką wygląda prawidłowo.',
+      warnings: 'Drukarka powinna działać, ale niektóre rzeczy wymagają uwagi.',
+      problems: 'Znaleziono problemy, które wyjaśniają, dlaczego drukarka nie łączy się lub nie drukuje.',
+    },
+    check: {
+      port_mqtt: {
+        title: 'Port sterowania (MQTT 8883)',
+        pass: 'Dostępny — drukarka przyjmuje połączenia sterujące.',
+        fail: 'Port 8883 jest niedostępny. Drukarka jest wyłączona, ma inny adres IP albo blokuje ją zapora. Sprawdź adres IP drukarki i upewnij się, że nic nie blokuje portu 8883.',
+      },
+      port_ftps: {
+        title: 'Port przesyłania plików (FTPS 990)',
+        pass: 'Dostępny — wysyłanie plików do druku będzie działać.',
+        warn: 'Port 990 jest niedostępny. Monitorowanie może nadal działać, ale wysyłanie wydruków do drukarki się nie powiedzie. Upewnij się, że port 990 nie jest zablokowany.',
+        warn_no_tls: 'Port 990 jest otwarty, ale usługa plików drukarki nie kończy uzgadniania TLS. Nie można pobrać plików wydruków, okładek ani timelapse\'ów, więc archiwa pozostają puste. Uruchom ponownie drukarkę — odblokowanie portu nie pomoże.',
+      },
+      external_storage: {
+        title: 'Zapisuj wysłane pliki w pamięci zewnętrznej (krok instalacji 4)',
+        pass: 'Drukarka zgłasza, że ta opcja jest włączona — wysłane pliki będą zapisywane na karcie SD, a archiwa będą miały miniatury i metadane slicera.',
+        fail: 'Drukarka zgłasza, że ta opcja jest wyłączona. Włącz „Zapisuj wysłane pliki w pamięci zewnętrznej” — w nowszym firmware (P2S 01.02 / Bambu Studio 2.6+) przełącznik znajduje się w ustawieniach druku na drukarce; w starszych wersjach jest w zakładce Urządzenie w Bambu Studio / OrcaSlicer. Bez niej każdy zarchiwizowany wydruk nie ma miniatury ani metadanych slicera.',
+        skip: 'Nie sprawdzono — wymaga aktywnego połączenia MQTT. W starszych slicerach, w których to ustawienie istnieje tylko w slicerze, drukarka nigdy go nie zgłasza, więc ten test przejdzie nawet przy wyłączonej opcji — sprawdź krok instalacji 4 ręcznie.',
+        skip_unsupported_model: 'Ten model ma gniazdo SD, ale nie da się włączyć tej opcji — obecne firmware serii P1 nie udostępnia przełącznika w Bambu Studio, a drukarka nie ma ekranu. Nie ma tu nic do naprawy; zarchiwizowane wydruki mogą nie mieć miniatur i metadanych slicera, dopóki Bambu Lab nie doda obsługi w firmware.',
+        fail_no_media: 'Opcja jest włączona, ale drukarka zgłasza brak karty lub pendrive\'a w gnieździe, więc wysłane pliki nie mają gdzie trafić. Włóż nośnik i drukuj ponownie — do tego czasu każdy zarchiwizowany wydruk nie będzie miał miniatury ani metadanych slicera.',
+        warn_internal_storage: 'Opcja jest włączona i nośnik jest obecny, ale ostatni wydruk i tak trafił do pamięci wewnętrznej drukarki, której Bambuddy nie może odczytać. W serii H2, P2S i X2D przycisk Drukuj w Bambu Studio zawsze wysyła tam pliki, niezależnie od tej opcji. Wydruki są archiwizowane z nazwą i czasem, ale bez miniatury i metadanych slicera. Aby mieć pełne archiwa, uruchamiaj wydruki z Bambuddy lub slicuj w OrcaSlicer — albo w Bambu Studio użyj Wyślij z wybraną opcją Zewnętrzna, a potem uruchom wydruk.',
+        warn_internal_history: 'Opcja jest włączona i nośnik jest obecny, ale ostatni wydruk został uruchomiony z pliku, który już był na drukarce — ponowny wydruk z jej ekranu, start z Handy lub plik wysłany wcześniej. Ta biblioteka znajduje się w pamięci wewnętrznej, której Bambuddy nie może odczytać, i żadne ustawienie tego nie zmienia, bo dla tego wydruku nic nie zostało wysłane. Nadal jest archiwizowany z nazwą i czasem, ale bez miniatury i metadanych slicera. Aby mieć pełne archiwa, uruchamiaj wydruki z Bambuddy lub wysyłaj je ze slicera.',
+      },
+      port_rtsps: {
+        title: 'Port kamery ({{protocol}} {{port}})',
+        pass: 'Dostępny — strumień z kamery będzie działać.',
+        warn: 'Port {{port}} jest niedostępny. Podgląd na żywo z kamery nie będzie działać. Nie wpływa to na drukowanie.',
+      },
+      macos_local_network: {
+        title: 'Uprawnienie macOS do sieci lokalnej',
+        pass: 'macOS pozwala Bambuddy na dostęp do sieci lokalnej.',
+        warn_unsigned: 'Python, w którym działa Bambuddy, nie ma podpisu kodu, więc macOS nie ma do czego przypisać uprawnienia do sieci lokalnej i po cichu odrzuca każde połączenie z drukarką — bez błędu i bez monitu. Uruchom aktualizator Bambuddy (install/update_macos.sh), który go podpisuje, a następnie uruchom ponownie Bambuddy. Interpreter: {{executable}}',
+        warn_permission: 'Jeśli drukarka jest włączona i ma ten adres, otwórz Ustawienia systemowe > Prywatność i ochrona > Sieć lokalna i upewnij się, że Python, w którym działa Bambuddy, jest włączony. Gdy nie jest, macOS po cichu odrzuca połączenia lokalne, a aktualizacja Pythona może pozostawić stare uprawnienie.',
+      },
+      network_mode: {
+        title: 'Tryb sieci kontenera',
+        genericRuntime: 'kontener',
+        pass: 'Działa w {{runtime}} z siecią hosta.',
+        warn: 'Bambuddy działa w {{runtime}} z siecią typu bridge. Wykrywanie drukarek i wirtualna drukarka wymagają sieci hosta — utwórz kontener ponownie w trybie sieci hosta ("network_mode: host" w docker-compose, "--network=host" dla Podmana).',
+        skip: 'Nie działa w kontenerze — nie dotyczy.',
+        skip_unknown: 'Bambuddy działa w {{runtime}}, ale nie udało się ustalić trybu sieci. Jeśli wykrywanie drukarek lub wirtualna drukarka nie działają, utwórz kontener ponownie z siecią hosta.',
+        skip_system_container: 'Bambuddy działa w kontenerze systemowym {{runtime}}, który jest w sieci LAN jak maszyna wirtualna — nie dotyczy.',
+        pass_macvlan: 'Działa w {{runtime}} w sieci macvlan, z własnym adresem w sieci LAN.',
+        pass_ipvlan: 'Działa w {{runtime}} w sieci ipvlan (L2), z własnym adresem w sieci LAN.',
+        warn_ipvlan_l3: 'Bambuddy działa w {{runtime}} w sieci ipvlan w trybie L3. Tryb L3 nie przepuszcza broadcastu ani multicastu, więc slicer nie znajdzie wirtualnej drukarki, a drukarki można znaleźć tylko skanowaniem podsieci — zamiast tego użyj sieci macvlan lub trybu ipvlan L2.',
+      },
+      subnet: {
+        title: 'Podsieć',
+        pass: 'Drukarka i Bambuddy są w tej samej podsieci.',
+        warn: 'Drukarka ({{printer_ip}}) i Bambuddy ({{host_ip}}) są w różnych podsieciach. Mogą się nie widzieć, jeśli nie skonfigurowano routingu między podsieciami.',
+        skip: 'Nie udało się ustalić podsieci — pominięto.',
+      },
+      mqtt_auth: {
+        title: 'Dane logowania drukarki',
+        pass: 'Drukarka zaakceptowała połączenie.',
+        fail: 'Drukarka jest dostępna, ale Bambuddy nie jest z nią połączony. Najprawdopodobniej kod dostępu lub numer seryjny jest błędny — kod dostępu zmienia się przy każdym przełączeniu trybu LAN Only lub trybu dewelopera, więc skopiuj go ponownie z ekranu drukarki. Tak samo może wyglądać drukarka, która się uruchamia ponownie lub osiągnęła limit jednoczesnych połączeń.',
+        fail_auth_rejected: 'Drukarka odrzuciła dane logowania Bambuddy. Kod dostępu lub numer seryjny jest błędny — kod dostępu zmienia się przy każdym przełączeniu trybu LAN Only lub trybu dewelopera, więc skopiuj go ponownie z ekranu drukarki i zapisz w ustawieniach drukarki.',
+        skip: 'Nie sprawdzono — nie udało się połączyć z drukarką.',
+      },
+      developer_mode: {
+        title: 'Tryb dewelopera LAN',
+        pass: 'Tryb dewelopera jest włączony.',
+        fail: 'Tryb dewelopera jest WYŁĄCZONY na drukarce. Włącz go w ustawieniach LAN drukarki i potwierdź przyciskiem OK. Bez niego wydruki się nie uruchomią.',
+        skip: 'Nie udało się sprawdzić — wymaga aktywnego połączenia z drukarką.',
+      },
+      printer_publishing: {
+        title: 'Drukarka publikuje stan',
+        pass: 'Drukarka publikuje aktualizacje stanu — AMS, filamenty i profile K będą poprawnie odzwierciedlane w slicerze.',
+        fail: 'Broker MQTT zaakceptował połączenie, ale drukarka nie opublikowała żadnego raportu stanu. Prawie zawsze oznacza to błędny numer seryjny lub złą wielkość liter — temat device/<serial>/report rozróżnia wielkość liter. Porównaj numer seryjny w ustawieniach drukarki z tym na ekranie drukarki.',
+        skip: 'Nie udało się sprawdzić — wymaga aktywnego połączenia z drukarką.',
+      },
+    },
+  },
+
+  systemHealth: {
+    sectionTitle: 'Kondycja systemu',
+    sectionDescription: 'Przeszukuje najnowsze logi pod kątem znanych problemów, które zwykle możesz naprawić sam, zanim staną się zgłoszeniem do wsparcia.',
+    rescan: 'Skanuj ponownie',
+    clean: 'Nie znaleziono znanych problemów w ostatnich wpisach logu ({{times}}).',
+    logUnavailable: 'Logowanie do pliku jest wyłączone, więc nie można przeskanować logów. Włącz logowanie do pliku, aby użyć tego sprawdzenia.',
+    learnMore: 'Jak to naprawić',
+    fixLabel: 'Rozwiązanie:',
+    occurrences: 'Wystąpienia: {{times}}× — ostatnio {{lastSeen}}',
+    category: {
+      layer8: 'Możesz to naprawić',
+      environment: 'Środowisko',
+      bug: 'Zgłoś to',
+    },
+    signature: {
+      'ftp-auth-rejected': {
+        name: 'Drukarka odrzuciła kod dostępu',
+        cause: 'Drukarka odmówiła logowania do transferu plików. Kod dostępu jest błędny lub zmienił się po przełączeniu trybu deweloperskiego.',
+        fix: 'Skopiuj ponownie kod dostępu z ekranu drukarki (ustawienia LAN) i zaktualizuj go w ustawieniach drukarki w Bambuddy.',
+      },
+      'ftp-connection-timeout': {
+        name: 'Przekroczono czas połączenia transferu plików',
+        cause: 'Bambuddy nie może połączyć się z portem transferu plików drukarki (FTPS 990). Port jest zablokowany albo drukarka jest wyłączona lub w innej podsieci.',
+        fix: 'Upewnij się, że nic nie blokuje portu 990 między Bambuddy a drukarką i że oba urządzenia są w tej samej sieci.',
+      },
+      'ftp-ssl-error': {
+        name: 'Nieudane uzgadnianie bezpiecznego transferu plików',
+        cause: 'Usługa plików drukarki odpowiedziała na porcie 990 bez TLS. Jej serwer plików się zawiesił — to usterka po stronie drukarki, a nie problem z zaporą lub firmware.',
+        fix: 'Uruchom ponownie drukarkę. Do tego czasu nie można pobierać plików wydruków, okładek ani timelapse\'ów; samo drukowanie działa normalnie.',
+      },
+      'bambu-cloud-captcha': {
+        name: 'Bambu Cloud wymaga CAPTCHA',
+        cause: 'Warstwa ochrony przed nadużyciami Bambu weryfikuje tę sieć, więc żadne logowanie do Bambu Cloud nie może się zakończyć. Jest to powiązane z publicznym adresem IP, a nie z twoim kontem czy tą instalacją.',
+        fix: 'Poczekaj — zwykle ustępuje w ciągu kilku godzin, a powtarzane próby logowania to wydłużają. Aby połączyć się w międzyczasie, zaloguj się tokenem dostępu pobranym z sesji przeglądarki.',
+      },
+      'mqtt-connection-flapping': {
+        name: 'Połączenie z drukarką ciągle się zrywa',
+        cause: 'Połączenie sterujące (MQTT 8883) wielokrotnie się rozłącza i łączy ponownie — zwykle przez słabą ścieżkę sieciową lub częściowo zablokowany port.',
+        fix: 'Sprawdź sygnał Wi-Fi przy drukarce, preferuj połączenie przewodowe i upewnij się, że port 8883 jest niezawodnie osiągalny.',
+      },
+      'camera-connection-refused': {
+        name: 'Strumień kamery nieosiągalny',
+        cause: 'Nie można połączyć się z kamerą na żywo na porcie RTSPS 322. Port jest zablokowany albo kamera lub podgląd LAN jest wyłączony w drukarce.',
+        fix: 'Włącz kamerę i podgląd LAN w drukarce i upewnij się, że port 322 nie jest zablokowany. Nie wpływa to na drukowanie.',
+      },
+      'database-locked': {
+        name: 'Rywalizacja o zapis do bazy danych',
+        cause: 'Baza danych SQLite pod obciążeniem zgłasza błędy "database is locked" — częste przy jednoczesnej pracy kilku drukarek.',
+        fix: 'Przełącz Bambuddy na zewnętrzną bazę danych PostgreSQL. Zobacz przewodnik PostgreSQL w dokumentacji.',
+      },
+    },
+  },
+
+  vpDiagnostic: {
+    title: 'Sprawdzenie konfiguracji — {{name}}',
+    runButton: 'Uruchom sprawdzenie konfiguracji',
+    running: 'Trwa sprawdzanie konfiguracji...',
+    runFailed: 'Nie można uruchomić sprawdzenia konfiguracji: {{error}}',
+    retry: 'Uruchom ponownie',
+    overall: {
+      ok: 'Wszystkie testy zaliczone — ta wirtualna drukarka jest poprawnie skonfigurowana.',
+      warnings: 'Wirtualna drukarka powinna działać, ale niektóre rzeczy wymagają uwagi.',
+      problems: 'Znaleziono problemy, które wyjaśniają, dlaczego slicer nie widzi tej wirtualnej drukarki lub nie może jej użyć.',
+    },
+    check: {
+      enabled: {
+        title: 'Wirtualna drukarka włączona',
+        fail: 'Ta wirtualna drukarka jest wyłączona. Włącz ją, aby była wykrywalna.',
+      },
+      running: {
+        title: 'Usługi uruchomione',
+        fail: 'Wirtualna drukarka jest włączona, ale jej usługi nie działają. Sprawdź log Bambuddy — zwykle zatrzymuje je konflikt adresu IP powiązania lub błąd uprawnień.',
+      },
+      bind_interface: {
+        title: 'Interfejs sieciowy powiązania',
+        fail: 'Interfejs powiązania nie jest ustawiony lub nie istnieje już na tym hoście. Wybierz aktualny interfejs z listy Interfejs powiązania.',
+      },
+      access_code: {
+        title: 'Kod dostępu ustawiony',
+        fail: 'Nie ustawiono kodu dostępu. W slicerze musi zostać podany ten sam 8-znakowy kod dostępu, który ustawisz tutaj.',
+      },
+      target_printer: {
+        title: 'Drukarka docelowa',
+        fail: 'Nie wybrano drukarki docelowej. Tryb proxy wymaga prawdziwej drukarki, do której będzie przekazywać.',
+        warn: 'Drukarka docelowa jest teraz offline — przekazywanie zostanie wznowione po jej ponownym połączeniu.',
+      },
+      port_ftps: {
+        title: 'Usługa przesyłania plików (port {{port}})',
+        fail: 'Nic nie nasłuchuje na porcie {{port}} adresu IP powiązania, więc slicer nie może przesyłać plików. Zwykłą przyczyną jest konflikt portów na tym interfejsie.',
+      },
+      port_mqtt: {
+        title: 'Usługa sterowania (port {{port}})',
+        fail: 'Nic nie nasłuchuje na porcie {{port}} adresu IP powiązania, więc slicer nie może się połączyć ani pokazać stanu.',
+      },
+      port_bind: {
+        title: 'Usługa wykrywania (port {{port}})',
+        fail: 'Nic nie nasłuchuje na porcie {{port}} adresu IP powiązania, więc uzgadnianie wykrywania w slicerze kończy się niepowodzeniem.',
+      },
+      privileged_ports: {
+        title: 'Powiązanie portu uprzywilejowanego',
+        fail: 'Port {{port}} jest poniżej 1024, a ta usługa nie ma uprawnień do jego powiązania — dlatego nic nie nasłuchuje powyżej. Dodaj AmbientCapabilities=CAP_NET_BIND_SERVICE do /etc/systemd/system/bambuddy.service i uruchom ponownie albo wykonaj "sudo setcap cap_net_bind_service=+ep $(readlink -f $(which python3))". W Dockerze dodaj cap_add: [NET_BIND_SERVICE].',
+      },
+      certificate: {
+        title: 'Certyfikat TLS',
+        pass: 'Certyfikat gotowy. Upewnij się, że certyfikat CA Bambuddy (powyżej) jest zaimportowany do magazynu zaufanych certyfikatów slicera.',
+        fail: 'Brakuje certyfikatu TLS dla tej wirtualnej drukarki. Sprawdź, czy katalog danych Bambuddy jest zapisywalny.',
+      },
+    },
+  },
+
+  bugReport: {
+    title: 'Zgłoś błąd',
+    description: 'Opis',
+    descriptionPlaceholder: 'Co poszło nie tak? Opisz problem...',
+    email: 'E-mail (opcjonalnie)',
+    emailPlaceholder: 'twoj@email.com',
+    emailPrivacy: 'Jeśli go podasz, twój e-mail zostanie dołączony w zwiniętej sekcji zgłoszenia na GitHubie, aby opiekun projektu mógł się z tobą skontaktować.',
+    screenshot: 'Zrzut ekranu',
+    uploadOrPaste: 'Prześlij, wklej lub przeciągnij obraz',
+    dataCollectedSummary: 'Jakie dane są dołączane do zgłoszenia?',
+    dataIncluded: 'Dołączane:',
+    dataIncludedList: 'Wersja aplikacji, system operacyjny, architektura, wersja Pythona, statystyki bazy danych (tylko liczby), modele drukarek, liczba dysz, wersje firmware, stan łączności, stan integracji (Spoolman, MQTT, HA), niewrażliwe ustawienia, liczba interfejsów sieciowych, szczegóły Dockera, wersje zależności.',
+    dataNeverIncluded: 'Nigdy niedołączane:',
+    dataNeverIncludedList: 'Nazwy drukarek, numery seryjne, kody dostępu, hasła, adresy IP, adresy e-mail, klucze API, tokeny, adresy URL webhooków, nazwy hostów ani nazwy użytkowników.',
+    submit: 'Wyślij',
+    startLogging: 'Rozpocznij logowanie debugowania',
+    stepEnableLogging: 'Logowanie debugowania włączone',
+    stepReproduce: 'Odtwórz teraz problem',
+    stepReview: 'Zatrzymaj logowanie i przejrzyj zgłoszenie',
+    stopLogging: 'Zatrzymaj logowanie',
+    maxDuration: 'Zatrzymuje się automatycznie po {{minutes}} min',
+    collectingLogs: 'Zbieranie logów...',
+    submitting: 'Wysyłanie zgłoszenia błędu...',
+    reviewTitle: 'Nic jeszcze nie zostało wysłane',
+    reviewBody: 'Wysłanie tworzy publiczne zgłoszenie na GitHubie z twoim opisem, zrzutem ekranu i e-mailem (jeśli je dodano), informacjami o systemie i zebranymi logami.',
+    reviewLogLines: 'Zebrane linie logu: {{lines}}',
+    discard: 'Odrzuć',
+    submittingStepConnection: 'Sprawdzanie łączności z drukarkami',
+    submittingStepVirtualPrinters: 'Sprawdzanie konfiguracji wirtualnych drukarek',
+    submittingStepLogScan: 'Skanowanie najnowszych logów pod kątem znanych problemów',
+    submittingStepSubmit: 'Wysyłanie zgłoszenia na GitHub',
+    submitSuccess: 'Zgłoszenie błędu zostało wysłane!',
+    submitFailed: 'Nie udało się wysłać zgłoszenia błędu',
+    diagnosticChecking: 'Sprawdzanie połączeń z drukarkami...',
+    diagnosticHealthy: 'Sprawdzenie połączeń zaliczone — nie znaleziono problemów z drukarkami.',
+    diagnosticSummary: 'Drukarki z problemami z połączeniem: {{problems}} z {{total}}',
+    diagnosticIntro: 'Co najmniej jedna drukarka ma problem z połączeniem, który może powodować twój problem. Rozwiń drukarkę poniżej, aby zobaczyć rozwiązanie — jego zastosowanie może rozwiązać problem bez zgłaszania błędu. Nadal możesz wysłać zgłoszenie poniżej.',
+    logHealthSummary: 'W logach znaleziono znane problemy',
+    logHealthIntro: 'Najnowsze logi pasują do znanych problemów. Sprawdź rozwiązania poniżej — ich zastosowanie może rozwiązać twój problem bez zgłaszania błędu. Nadal możesz wysłać zgłoszenie poniżej.',
+    thankYou: 'Dziękujemy!',
+    submitted: 'Twoje zgłoszenie błędu zostało wysłane.',
+    viewIssue: 'Pokaż zgłoszenie',
+    closeKeepsRecording: 'Możesz zamknąć ten panel podczas odtwarzania problemu — nagrywanie trwa dalej, a ponowne otwarcie przywróci cię tutaj.',
+    resumeRecording: 'Nagrywanie zgłoszenia błędu — {{elapsed}}. Kliknij, aby zakończyć.',
+    resumeReport: 'Wróć do zgłoszenia',
+    unexpectedError: 'Wystąpił nieoczekiwany błąd',
+  },
+  failureDetection: {
+    title: 'Wykrywanie awarii AI',
+    description: 'Monitoruj wydruki za pomocą samodzielnie hostowanego Obico ML API i automatycznie reaguj na wykryte awarie.',
+    mlUrl: 'URL Obico ML API',
+    mlUrlHint: 'Bazowy URL twojego samodzielnie hostowanego kontenera Obico ml_api (np. http://192.168.1.10:3333).',
+    bambuddyInternalUrl: 'Wewnętrzny URL Bambuddy (opcjonalnie)',
+    bambuddyInternalUrlHint: 'Adres Bambuddy osiągalny z ML API, np. nazwa usługi Dockera lub adres IP w LAN. Pozostaw puste, aby użyć zewnętrznego URL. Inne integracje nadal używają zewnętrznego URL.',
+    bambuddyInternalUrlInvalid: 'Musi zaczynać się od http:// lub https:// (na przykład http://bambuddy:8000). Nie zostanie zapisany, dopóki tak nie będzie.',
+    mlToken: 'Token ML API (opcjonalnie)',
+    mlTokenPlaceholder: 'Pozostaw puste, jeśli serwer działa bez ML_API_TOKEN',
+    mlTokenHint: 'Musi odpowiadać zmiennej środowiskowej ML_API_TOKEN twojego kontenera Obico ml_api. Pozostaw puste, gdy kontener działa bez niej.',
+    test: 'Testuj',
+    testSuccess: 'ML API jest osiągalne i działa poprawnie.',
+    testSuccessTokenUnknown: 'ML API jest osiągalne i działa poprawnie. Nie można sprawdzić tokenu.',
+    testFailed: 'Nie można połączyć się z ML API.',
+    sensitivity: 'Czułość',
+    sensitivityLow: 'Niska (mniej fałszywych alarmów)',
+    sensitivityMedium: 'Średnia (zrównoważona)',
+    sensitivityHigh: 'Wysoka (wczesne wykrywanie, więcej fałszywych alarmów)',
+    sensitivityHint: 'Dostosowuje progi pewności, które wyzwalają ostrzeżenia i awarie.',
+    action: 'Działanie po wykryciu awarii',
+    actionNotify: 'Tylko powiadom',
+    actionPause: 'Wstrzymaj wydruk',
+    actionPauseOff: 'Wstrzymaj i odetnij zasilanie',
+    pollInterval: 'Interwał odpytywania (sekundy)',
+    pollIntervalHint: 'Jak często sprawdzać każdą drukarkę podczas drukowania. Minimum 5 s, maksimum 120 s.',
+    externalUrlMissing: 'Nie ustawiono adresu, z którego ML API mogłoby pobierać zrzuty.',
+    externalUrlHint: 'Ustaw tutaj wewnętrzny URL Bambuddy lub zewnętrzny URL w Ustawienia → Sieć, aby ML API mogło pobierać zrzuty.',
+    perPrinterTitle: 'Monitorowane drukarki',
+    perPrinterHint: 'Wybierz, które drukarki obserwuje usługa wykrywania.',
+    monitorAll: 'Monitoruj wszystkie połączone drukarki',
+    statusTitle: 'Status',
+    serviceRunning: 'Usługa działa',
+    thresholds: 'Progi niski / wysoki',
+    activePrinters: 'Aktywne wydruki',
+    noActivePrints: 'Obecnie nie trwają żadne wydruki.',
+    historyTitle: 'Ostatnie wykrycia',
+    noHistory: 'Brak wykryć.',
+  },
+
+  modelSources: {
+    title: 'Źródła modeli',
+    tabMakerworld: 'MakerWorld',
+    tabManyfold: 'Manyfold',
+  },
+  manyfold: {
+    description: 'Przeglądaj i przeszukuj bibliotekę Manyfold oraz importuj jej pliki, aby je pociąć i wydrukować.',
+    notConnectedTitle: 'Manyfold nie jest połączony',
+    notConnectedBody: 'Poproś administratora o połączenie twojej biblioteki Manyfold.',
+    connectionTitle: 'Połączenie z Manyfold',
+    connectionHelp: 'W Manyfold otwórz Ustawienia → API i utwórz aplikację z zakresami "public" i "read". Wpisz tutaj jej identyfikator klienta i sekret. Bambuddy widzi modele, które widzi właściciel aplikacji.',
+    url: 'URL Manyfold',
+    urlPlaceholder: 'http://192.168.1.10:3214',
+    clientId: 'Identyfikator klienta',
+    clientSecret: 'Sekret klienta',
+    clientSecretStored: 'Zapisany. Pozostaw puste, aby go zachować.',
+    test: 'Testuj połączenie',
+    testOk: 'Połączono. Modele widoczne dla Bambuddy: {{count}}',
+    disconnect: 'Rozłącz',
+    disconnectTitle: 'Rozłączyć Manyfold?',
+    disconnectBody: 'Bambuddy zapomni URL Manyfold, identyfikator klienta i sekret. Zaimportowane pliki pozostaną w twojej bibliotece.',
+    disconnected: 'Manyfold rozłączony',
+    editConnection: 'Połączenie',
+    searchPlaceholder: 'Szukaj modeli',
+    modelCount: 'Modele: {{count}}',
+    noModels: 'Nie znaleziono modeli.',
+    previous: 'Poprzednia',
+    next: 'Następna',
+    page: 'Strona {{page}}',
+    back: 'Wróć do modeli',
+    openInManyfold: 'Otwórz w Manyfold',
+    license: 'Licencja',
+    files: 'Pliki',
+    noFiles: 'Ten model nie ma plików.',
+    importTo: 'Importuj do',
+    folderAuto: 'Folder Manyfold',
+    import: 'Importuj',
+    importing: 'Importowanie…',
+    imported: 'Zaimportowano {{filename}}',
+    alreadyInLibrary: 'Już w twojej bibliotece',
+    inLibrary: 'W bibliotece',
+    showInLibrary: 'Pokaż w bibliotece',
+    notImportable: 'Bambuddy nie może pociąć ani wydrukować tego typu',
+    selectAll: 'Zaznacz wszystko',
+    selectFile: 'Zaznacz {{name}}',
+    importSelected: 'Importuj zaznaczone ({{count}})',
+    importAll: 'Importuj wszystko',
+    importProgress: 'Importowanie {{current}}/{{total}}',
+    bulkDone: 'Zaimportowano: {{imported}} · już w bibliotece: {{existing}} · nieudane: {{failed}}',
+    bulkFailed: 'Nie zaimportowano: {{names}}. {{reason}}',
+    bulkNothing: 'Nic do zaimportowania: każdy plik do druku jest już w twojej bibliotece.',
+    selectModel: 'Zaznacz {{name}}',
+    selectPage: 'Zaznacz stronę',
+    modelsSelected: 'Zaznaczone modele: {{count}}',
+    importModels: 'Importuj ich pliki',
+    clearSelection: 'Wyczyść zaznaczenie',
+    collectProgress: 'Odczytywanie modeli {{current}}/{{total}}',
+    modelsUnreadable: 'Nie można odczytać: {{names}}',
+    errors: {
+      manyfold_not_configured: 'Manyfold nie jest połączony.',
+      manyfold_credentials: 'Manyfold nie zaakceptował identyfikatora klienta lub sekretu.',
+      manyfold_scope: 'Aplikacja Manyfold wymaga zakresu "read". Edytuj ją w Manyfold w Ustawienia → API.',
+      manyfold_rate_limited: 'Manyfold ogranicza logowania. Spróbuj ponownie za kilka minut.',
+      manyfold_unreachable: 'Bambuddy nie może połączyć się z Manyfold. Sprawdź URL i czy Manyfold działa.',
+      manyfold_forbidden: 'Manyfold odmówił dostępu. Sprawdź, czy właściciel aplikacji widzi ten model.',
+      manyfold_not_found: 'Manyfold nie może znaleźć tego modelu ani pliku.',
+      manyfold_too_large: 'Plik jest większy niż 200 MB.',
+      manyfold_not_importable: 'Można importować tylko pliki 3MF, STL i STEP.',
+      manyfold_bad_url: 'Wpisz URL Manyfold zaczynający się od http:// lub https://.',
+      manyfold_secret_required: 'Wpisz sekret klienta.',
+      manyfold_failed: 'Manyfold odpowiedział błędem.',
+    },
+  },
+  makerworld: {
+    title: 'MakerWorld',
+    description: 'Wklej URL modelu z MakerWorld, aby go zaimportować i wydrukować bezpośrednio z Bambuddy — bez przechodzenia do aplikacji Bambu Handy.',
+    pasteUrlHeader: 'Importuj z MakerWorld',
+    pasteUrlPlaceholder: 'https://makerworld.com/en/models/… lub wklej dowolny link MakerWorld',
+    resolveButton: 'Rozwiąż',
+    signInRequiredTitle: 'Pobieranie wymaga zalogowania do Bambu Cloud',
+    signInRequiredBody: 'Szczegóły modelu możesz przeglądać anonimowo, ale MakerWorld wymaga konta Bambu Cloud do pobierania plików 3MF.',
+    signInExpiredTitle: 'Sesja Bambu Cloud wygasła',
+    signInExpiredBody: 'Nadal jesteś zalogowany do Bambuddy, ale Bambu Lab przestał akceptować zapisany token, więc pobieranie się nie powiedzie. Zaloguj się ponownie do Bambu Cloud.',
+    openCloudSettings: 'Otwórz ustawienia chmury',
+    untitledModel: 'Model bez nazwy',
+    byCreator: 'autor: {{name}}',
+    downloadsCount: 'Pobrania: {{count}}',
+    licensePrefix: 'Licencja',
+    alreadyImported: 'Już w bibliotece',
+    openOnMakerworld: 'Otwórz w MakerWorld',
+    alreadyInLibrary: 'Ten model jest już w twojej bibliotece — znajdziesz go w Menedżer plików → MakerWorld',
+    importSuccess: 'Zaimportowano {{filename}} — zapisano w Menedżer plików → MakerWorld',
+    platesHeader: 'Płyty ({{count}})',
+    plateDefaultName: 'Płyta {{n}}',
+    materialCount: 'Filamenty: {{count}}',
+    amsRequired: 'Wymaga AMS',
+    slicedFor: 'Pocięto dla {{printer}}',
+    alsoCompatible: 'Oznaczono też jako zgodne: {{printers}}',
+    importToLibrary: 'Zapisz',
+    sliceIn: 'Zapisz i potnij w {{slicer}}',
+    disclaimer: 'Integracja z MakerWorld korzysta z punktów końcowych API udokumentowanych przez społeczność. Bambuddy nie jest powiązany z MakerWorld ani Bambu Lab, ani przez nie popierany.',
+    lastImportSuccess: 'Zaimportowano do twojej biblioteki',
+    lastImportAlreadyInLibrary: 'Już w twojej bibliotece',
+    viewInLibrary: 'Pokaż w menedżerze plików',
+    openInBambuStudio: 'Otwórz w Bambu Studio',
+    openInOrcaSlicer: 'Otwórz w OrcaSlicer',
+    importTo: 'Importuj do menedżera plików',
+    recentImportsHeader: 'Ostatnie importy',
+    phaseResolving: 'Rozwiązywanie',
+    phaseDownloading: 'Pobieranie',
+    folderAuto: 'MakerWorld (domyślny)',
+    importAll: 'Importuj wszystko',
+    importAllProgress: 'Importowanie {{current}}/{{total}}',
+    openGallery: 'Otwórz galerię obrazów',
+    galleryPrev: 'Poprzedni obraz',
+    galleryNext: 'Następny obraz',
+    deleteImport: 'Usuń z biblioteki',
+    importDeleting: 'Usuwanie…',
+    importDeleted: 'Usunięto z biblioteki',
+    confirmDelete: 'Usunąć {{filename}} z biblioteki? Spowoduje to usunięcie pliku lokalnego, ale płytę można ponownie zaimportować z MakerWorld.',
+    errors: {
+      resolveFailed: 'Nie można rozwiązać tego URL MakerWorld.',
+      downloadFailed: 'Pobieranie nie powiodło się. Spróbuj ponownie.',
+      deleteFailed: 'Nie można usunąć pliku z biblioteki.',
+    },
+  },
+  gcodeViewer: {
+    filamentSlot: 'Filament {{n}}',
+    loading: 'Odczytywanie ścieżki narzędzia…',
+    loadFailed: 'Nie można wczytać G-code dla tego pliku.',
+    showTravel: 'Ruchy jałowe',
+    topLayer: 'Górna warstwa',
+    bottomLayer: 'Dolna warstwa',
+    noSource: 'Nie podano pliku do podglądu.',
+    view: {
+      filament: 'Filament',
+      feature: 'Element',
+      height: 'Wysokość',
+      width: 'Szerokość',
+    },
+    feature: {
+      wall: 'Ściany',
+      sparseInfill: 'Wypełnienie rzadkie',
+      solidInfill: 'Wypełnienie pełne',
+      bridge: 'Most / nawis',
+      support: 'Podpory',
+      skirt: 'Skirt / brim',
+      gapFill: 'Wypełnienie szczelin',
+      ironing: 'Prasowanie',
+      primeTower: 'Wieża czyszcząca',
+    },
+    back: 'Wstecz',
+    backToArchives: 'Wróć do archiwum wydruków',
+    backToFiles: 'Wróć do menedżera plików',
+    plates: 'Płyty',
+    plateN: 'Płyta {{n}}',
+  },
+  libraryTrash: {
+    title: 'Kosz',
+    headerButton: 'Kosz',
+    headerTooltip: 'Pokaż pliki przeniesione do kosza',
+    backToFiles: 'Wróć do menedżera plików',
+    subtitleAdmin: 'Usunięte pliki pozostają tutaj przez {{days}} dni, a następnie są usuwane automatycznie. Ten widok pokazuje pliki w koszu wszystkich użytkowników.',
+    subtitleUser: 'Usunięte pliki pozostają tutaj przez {{days}} dni, a następnie są usuwane automatycznie.',
+    loading: 'Wczytywanie kosza…',
+    loadError: 'Nie można wczytać kosza.',
+    empty: 'Kosz jest pusty.',
+    summary: 'Pliki: {{count}} · {{size}}',
+    emptyTrash: 'Opróżnij kosz',
+    restore: 'Przywróć',
+    purgeNow: 'Usuń teraz',
+    autoPurgeIn: 'Automatyczne usunięcie za {{when}}',
+    days: 'dni',
+    retentionLabel: 'Usuń automatycznie po',
+    selectAll: 'Zaznacz wszystko',
+    selectOne: 'Zaznacz {{filename}}',
+    selectionCount: 'Zaznaczono: {{count}}',
+    bulkRestore: 'Przywróć zaznaczone',
+    bulkPurge: 'Usuń zaznaczone',
+    col: {
+      filename: 'Plik',
+      folder: 'Folder',
+      size: 'Rozmiar',
+      deleted: 'Przeniesiono do kosza',
+      autoPurge: 'Automatyczne usunięcie',
+      owner: 'Właściciel',
+      actions: 'Akcje',
+    },
+    confirm: {
+      purgeTitle: 'Usunąć trwale?',
+      purgeBody: '{{filename}} zostanie usunięty z dysku i nie będzie można go przywrócić.',
+      emptyTitle: 'Opróżnić kosz?',
+      emptyBody: 'Wszystkie pliki (liczba: {{count}}) zostaną usunięte z dysku. Tej operacji nie można cofnąć.',
+      bulkPurgeTitle: 'Trwale usunąć zaznaczone pliki?',
+      bulkPurgeBody: 'Zaznaczone pliki (liczba: {{count}}) zostaną usunięte z dysku i nie będzie można ich przywrócić.',
+      cta: 'Usuń trwale',
+    },
+    toast: {
+      restored: 'Plik przywrócony.',
+      restoreFailed: 'Nie można przywrócić pliku.',
+      purged: 'Plik trwale usunięty.',
+      purgeFailed: 'Nie można usunąć pliku.',
+      emptied: 'Usunięte pliki z kosza: {{count}}.',
+      emptyFailed: 'Nie można opróżnić kosza.',
+      retentionSaved: 'Automatyczne usuwanie ustawiono na {{days}} dni.',
+      retentionFailed: 'Nie można zapisać ustawienia przechowywania.',
+      bulkRestored: 'Przywrócone pliki: {{count}}.',
+      bulkPurged: 'Usunięte pliki: {{count}}.',
+    },
+  },
+  libraryPurge: {
+    title: 'Wyczyść stare pliki',
+    headerButton: 'Wyczyść stare',
+    headerTooltip: 'Przenieś hurtowo stare pliki do kosza',
+    description: 'Usuń stare pliki z biblioteki za jednym razem. Wiek plików z historią wydruków liczony jest od daty ostatniego wydruku; plików nigdy niedrukowanych — od daty przesłania.',
+    ageLabel: 'Przenieś pliki starsze niż',
+    days: 'dni',
+    includeNeverPrinted: 'Uwzględnij pliki, które nigdy nie zostały wydrukowane',
+    effectsTitle: 'Co się stanie po kliknięciu Wyczyść',
+    effect1: 'Pasujące pliki zostaną przeniesione do kosza — nie są jeszcze usuwane z dysku.',
+    effect2: 'Możesz je przywrócić z kosza w dowolnym momencie, dopóki nie minie okres przechowywania.',
+    effect3: 'Po okresie przechowywania mechanizm czyszczenia kosza trwale usunie je z dysku.',
+    effect4: 'Pliki w folderach zewnętrznych (połączonych) są pomijane — Bambuddy nigdy nie usuwa danych, które nie należą do niego.',
+    previewLoading: 'Sprawdzanie, ile plików pasuje…',
+    previewFailed: 'Nie można wyświetlić podglądu czyszczenia.',
+    previewSummary: 'Pliki: {{count}} · {{size}} — zostałyby przeniesione do kosza',
+    andMore: '…i jeszcze {{count}}',
+    warning: 'Pliki w koszu nadal zajmują miejsce, dopóki nie minie okres przechowywania. Opróżnij potem kosz, aby natychmiast zwolnić miejsce na dysku.',
+    confirmCta: 'Przenieś do kosza ({{count}})',
+    purging: 'Przenoszenie do kosza…',
+    toast: {
+      success: 'Przeniesione do kosza pliki: {{count}}.',
+      failed: 'Nie można wyczyścić plików.',
+    },
+  },
+  libraryAutoPurge: {
+    enableLabel: 'Automatycznie czyść stare pliki',
+    enableDescription: 'Uruchamia czyszczenie administratora raz dziennie. Pliki trafiają najpierw do kosza — nie są usuwane od razu.',
+    ageLabel: 'Automatycznie czyść pliki starsze niż',
+    ageDescription: 'Minimum 7 dni, maksimum 10 lat. Używa tej samej reguły wieku co ręczny przycisk Wyczyść.',
+    days: 'dni',
+    includeNeverPrinted: 'Uwzględnij pliki, które nigdy nie zostały wydrukowane',
+    saveFailed: 'Nie można zapisać ustawień automatycznego czyszczenia.',
+  },
+  archiveMerge: {
+    headerButton: 'Scal duplikaty',
+    headerTooltip: 'Scal archiwa zawierające ten sam plik w jedno',
+    duplicatesHint: 'Archiwa tego samego pliku, właściciela i projektu można scalić w jedno, wraz z każdym ich wydrukiem.',
+    title: 'Scal zduplikowane archiwa',
+    effectsTitle: 'Co robi scalanie',
+    effect1: 'Najstarsze archiwum każdej grupy pozostaje i przejmuje każdy wydruk pozostałych, wraz z ich zdjęciami, filmami i plikami.',
+    effect2: 'Pozostałe znikają z archiwów; ich stare linki i zakładki otwierają archiwum, do którego zostały scalone.',
+    effect3: 'Obciążenia portfela i rezerwacje budżetu pozostają tam, gdzie zostały zaksięgowane.',
+    previewLoading: 'Szukanie archiwów tego samego pliku…',
+    previewFailed: 'Nie można wyszukać duplikatów.',
+    none: 'Brak duplikatów do scalenia.',
+    selectGroup: 'Scal archiwa {{name}}',
+    keeps: 'Pozostaje · utworzono {{date}} · wydruki: {{count}}',
+    mergesIn: '{{name}} · utworzono {{date}} · wydruki: {{count}}',
+    leftOutTitle: 'Pominięte przy scalaniu',
+    found: 'Znalezione grupy zduplikowanych archiwów: {{count}}.',
+    openCta: 'Scal duplikaty…',
+    bannerText: 'Grupy archiwów zawierających ten sam plik: {{count}}. Scalenie zamienia każdą grupę w jedno archiwum, z każdym jej wydrukiem.',
+    dismiss: 'Odrzuć',
+    waitingTitle: 'Na razie pominięte',
+    mergeCta: 'Scal grupy ({{count}})',
+    confirmCta: 'Tak, scal grupy ({{count}})',
+    confirmWarning: 'Grupy do scalenia: {{count}}. Tego nie można tutaj cofnąć.',
+    merging: 'Scalanie…',
+    skipped: {
+      busy: 'W użyciu: drukowane, w kolejce lub właśnie wydrukowane. Spróbuj później.',
+      conflicting_files: 'Archiwa zawierają różne pliki źródłowe, pliki projektu lub filmy. Najpierw zachowaj jedno ręcznie.',
+      failed: 'Scalanie nie powiodło się.',
+      not_a_group: 'To już nie jest grupa duplikatów.',
+    },
+    toast: {
+      merged: 'Scalone grupy: {{count}}.',
+      mergedSome: 'Scalone grupy: {{count}}; pominięte: {{left}}.',
+      failed: 'Nie można scalić archiwów.',
+    },
+  },
+  archivePurge: {
+    headerButton: 'Wyczyść stare',
+    headerTooltip: 'Usuń hurtowo stare archiwa',
+    title: 'Wyczyść stare archiwa',
+    description: 'Wyczyść starą historię wydruków. Wiek każdego archiwum liczony jest od ostatniego ukończonego wydruku — ponowny wydruk archiwum odświeża jego wiek, więc aktywna praca nigdy nie zostanie wyczyszczona.',
+    ageLabel: 'Usuń archiwa niedrukowane w ciągu ostatnich',
+    days: 'dni',
+    effectsTitle: 'Co się stanie po kliknięciu Wyczyść',
+    effect1: 'Każde pasujące archiwum zostanie ukryte na listach, a jego pliki usunięte z dysku (3MF, miniatura, timelapse, źródłowy 3MF, plik projektu F3D, zdjęcia).',
+    effect2: 'Wiersz archiwum pozostaje w bazie danych, więc Szybkie statystyki zachowują udział filamentu, czasu, kosztu i energii — tak samo jak domyślne usuwanie pojedynczego archiwum.',
+    effect3: 'Zaznacz poniżej "Usuń też ze statystyk", aby usunąć również udział w Szybkich statystykach (odpowiada opcji usuwania pojedynczego archiwum). Tej operacji nie można cofnąć.',
+    effect4: 'Ponowny wydruk archiwum odświeża jego licznik wieku, więc archiwa, których nadal używasz, są bezpieczne.',
+    purgeStatsLabel: 'Usuń też ze statystyk',
+    purgeStatsHint: 'Usuwa pasujące archiwa z Szybkich statystyk (filament, czas, koszt, energia). Bez tego Szybkie statystyki zachowują każdy udział, a z dysku znikają tylko pliki.',
+    previewLoading: 'Sprawdzanie, ile archiwów pasuje…',
+    previewFailed: 'Nie można wyświetlić podglądu czyszczenia.',
+    previewSummary: 'Archiwa: {{count}} · {{size}} — zostałyby usunięte',
+    andMore: '…i jeszcze {{count}}',
+    warning: 'Pliki zostaną usunięte z dysku i nie będzie można ich przywrócić. Przed kontynuowaniem pobierz lub dodaj do ulubionych wszystko, co chcesz zachować.',
+    confirmCta: 'Usuń archiwa ({{count}})',
+    purging: 'Usuwanie…',
+    toast: {
+      success: 'Usunięte archiwa: {{count}}.',
+      failed: 'Nie można wyczyścić archiwów.',
+    },
+  },
+  archiveAutoPurge: {
+    enableLabel: 'Automatycznie czyść stare archiwa',
+    enableDescription: 'Raz dziennie ukrywa archiwa na listach i usuwa ich pliki z dysku, jeśli nie zostały wydrukowane w ustalonym okresie. Ponowny wydruk archiwum resetuje licznik.',
+    ageLabel: 'Automatycznie usuwaj archiwa niedrukowane w ciągu ostatnich',
+    ageDescription: 'Minimum 7 dni, maksimum 10 lat. Na podstawie ostatniego ukończonego wydruku — ponowny wydruk archiwum odświeża jego wiek. Usuwa 3MF, miniaturę, timelapse, źródłowy 3MF, F3D i zdjęcia.',
+    days: 'dni',
+    purgeStatsLabel: 'Usuń też ze statystyk',
+    purgeStatsDescription: 'Po włączeniu codzienne czyszczenie usuwa też każde wyczyszczone archiwum z Szybkich statystyk (filament, czas, koszt, energia). Domyślnie wyłączone — Szybkie statystyki zachowują udział, a z dysku znikają tylko pliki.',
+    runNow: 'Wyczyść archiwa teraz',
+    saveFailed: 'Nie można zapisać ustawień automatycznego czyszczenia.',
+  },
+  connectedApps: {
+    title: 'Połączone aplikacje',
+    description: 'Aplikacje, które logują użytkowników za pomocą konta Bambuddy. Każda aplikacja otrzymuje identyfikator klienta i sekret, a Bambuddy wysyła logowanie wyłącznie na zarejestrowany tutaj URL zwrotny.',
+    requiresAuth: 'Połączone aplikacje wymagają uwierzytelniania Bambuddy. Najpierw włącz je w sekcji Użytkownicy.',
+    name: 'Nazwa aplikacji',
+    namePlaceholder: 'np. Menedżer zamówień',
+    callbackUrl: 'URL zwrotny',
+    callbackHint: 'URL zwrotny podany jest w dokumentacji aplikacji. Musi się dokładnie zgadzać.',
+    add: 'Dodaj aplikację',
+    empty: 'Brak połączonych aplikacji.',
+    clientId: 'Identyfikator klienta',
+    clientSecret: 'Sekret klienta',
+    lastUsed: 'Ostatnie logowanie',
+    disabledBadge: 'Wyłączona',
+    enable: 'Włącz',
+    disable: 'Wyłącz',
+    rotate: 'Nowy sekret',
+    delete: 'Usuń',
+    cancel: 'Anuluj',
+    copy: 'Kopiuj',
+    secret: {
+      title: '{{name}}: skopiuj teraz sekret',
+      warning: 'Wklej identyfikator klienta i sekret do aplikacji. Sekret jest pokazywany tylko ten jeden raz; jeśli go zgubisz, utwórz nowy.',
+      dismiss: 'Zapisane',
+    },
+    confirmRotate: {
+      title: 'Utworzyć nowy sekret?',
+      body: '"{{name}}" przestanie logować użytkowników, dopóki nie wkleisz do niej nowego sekretu.',
+    },
+    confirmDelete: {
+      title: 'Usunąć tę aplikację?',
+      body: '"{{name}}" nie będzie już mogła nikogo logować. Jeśli zostanie dodana ponownie, każdy zostanie ponownie poproszony o zgodę.',
+    },
+    toast: {
+      created: 'Dodano aplikację',
+      enabled: 'Aplikacja włączona',
+      disabled: 'Aplikacja wyłączona',
+      rotated: 'Utworzono nowy sekret',
+      deleted: 'Aplikacja usunięta',
+      copied: 'Skopiowano do schowka',
+      copyFailed: 'Kopiowanie nie powiodło się. Zaznacz tekst i skopiuj go ręcznie.',
+      failed: 'Coś poszło nie tak',
+    },
+    authorize: {
+      checking: 'Sprawdzanie żądania logowania…',
+      redirecting: 'Logowanie…',
+      errorTitle: 'Nie można cię zalogować',
+      invalidRequest: 'To żądanie logowania jest nieprawidłowe: aplikacja nie jest zarejestrowana, jest wyłączona lub używa innego URL zwrotnego. Poproś administratora Bambuddy o sprawdzenie Ustawienia > Klucze API > Połączone aplikacje.',
+      authDisabled: 'Logowanie przez Bambuddy jest niedostępne, ponieważ uwierzytelnianie Bambuddy jest wyłączone. Użyj własnego logowania aplikacji.',
+      failed: 'Logowanie nie powiodło się. Wróć do aplikacji i spróbuj ponownie.',
+      title: '{{app}} chce cię zalogować',
+      signedInAs: 'Zalogowano do Bambuddy jako {{username}}',
+      sharedData: '{{app}} zobaczy twoją nazwę użytkownika, adres e-mail, grupy i uprawnienia. Nie otrzyma twojego hasła ani sesji Bambuddy.',
+      allow: 'Zezwól',
+      deny: 'Anuluj',
+    },
+  },
+  cameraTokens: {
+    scope: {
+      camera_stream: 'Strumień kamery',
+      camwall: 'Ściana kamer',
+      overlay: 'Nakładka do streamingu',
+    },
+    title: 'Tokeny API kamer',
+    navTitle: 'Tokeny API kamer',
+    description:
+      'Długoterminowe tokeny do osadzania strumienia kamery w Home Assistant, Frigate, kioskach lub innym narzędziu, które potrzebuje stałego URL. Wybierz zakres podczas tworzenia; token można odwołać w dowolnym momencie.',
+    loading: 'Wczytywanie…',
+    confirmRevoke: {
+      title: 'Odwołać ten token?',
+      body: 'Każde urządzenie używające "{{name}}" natychmiast straci dostęp. Tej operacji nie można cofnąć.',
+      cancel: 'Anuluj',
+      confirm: 'Odwołaj',
+    },
+    create: {
+      scopeLabel: 'Zakres',
+      hintCameraStream:
+        'Token strumienia kamery może pobierać tylko strumienie i zrzuty z kamer. Użyj go dla Home Assistant, Frigate lub czegokolwiek, co osadza pojedynczą kamerę.',
+      hintCamWall:
+        "Token Ściany kamer otwiera /camwall na ekranie bez logowania. Widzi nazwę i stan każdej drukarki oraz strumienie ich kamer. Nie widzi nazw plików, adresów ani kodów dostępu.",
+      hintOverlay:
+        "Token Nakładki do streamingu otwiera /overlay/{printerId} na ekranie bez logowania — dla OBS lub dowolnej transmisji na żywo. Widzi strumień kamery jednej drukarki oraz bieżący stan wydruku, w tym nazwę pliku wyświetlaną na ekranie. Nie widzi adresów ani kodów dostępu.",
+      title: 'Utwórz nowy token',
+      nameLabel: 'Nazwa tokenu',
+      namePlaceholder: 'np. Home Assistant',
+      daysLabel: 'Dni do wygaśnięcia',
+      submit: 'Utwórz',
+      hint:
+        'Maksymalny czas ważności to 365 dni. Wartość tokenu jest pokazywana tylko raz przy tworzeniu — skopiuj ją teraz.',
+    },
+    created: {
+      camWallUrlTitle: 'URL Ściany kamer dla tego wyświetlacza',
+      camWallUrlHint:
+        'Otwórz go na ekranie. Każdy, kto zna ten URL, może oglądać ścianę, więc traktuj go jak klucz — odwołaj token, aby odciąć wyświetlacz.',
+      overlayUrlTitle: 'URL nakładki dla OBS',
+      overlayUrlHint:
+        "Dodaj go jako źródło przeglądarki w OBS. Zmień liczbę w /overlay/1 na numer swojej drukarki (z jej URL na stronie Drukarki). Każdy, kto zna ten URL, może oglądać strumień, więc traktuj go jak klucz — odwołaj token, aby go odciąć.",
+      title: 'Token utworzony — skopiuj go teraz',
+      warning:
+        'To jedyny raz, kiedy ten token będzie widoczny. Po zamknięciu tego okna nie będzie można go już nigdy wyświetlić.',
+      copy: 'Kopiuj',
+      dismiss: "Zapisane",
+    },
+    list: {
+      scope: 'Zakres',
+      myTitle: 'Moje tokeny',
+      allTitle: 'Wszyscy użytkownicy (widok administratora)',
+      empty: 'Brak tokenów.',
+      name: 'Nazwa',
+      owner: 'Właściciel',
+      prefix: 'Prefiks',
+      created: 'Utworzono',
+      expires: 'Wygasa',
+      lastUsed: 'Ostatnio użyty',
+      revoke: 'Odwołaj',
+      expired: 'Wygasł',
+    },
+    toast: {
+      created: 'Token utworzony',
+      createFailed: 'Nie udało się utworzyć tokenu',
+      revoked: 'Token odwołany',
+      revokeFailed: 'Nie udało się odwołać tokenu',
+      loadFailed: 'Nie udało się wczytać tokenów',
+      copied: 'Skopiowano do schowka',
+      copyFailed: 'Kopiowanie nie powiodło się — zaznacz i skopiuj ręcznie',
+    },
+  },
+  // Forecast & Inventory Intelligence
+  forecast: {
+    clearAllConfirmTitle: 'Wyczyścić listę zakupów?',
+    clearAllConfirmMessage: 'Spowoduje to usunięcie wszystkich pozycji z listy zakupów (liczba: {{count}}).',
+    title: 'Prognoza',
+    noSpools: 'Nie znaleziono aktywnych szpul. Dodaj szpule do magazynu, aby zobaczyć dane prognozy.',
+    noUsageData: 'Brak danych o zużyciu — nie można prognozować stanu magazynu.',
+    // Table headers
+    sku: 'SKU',
+    material: 'Materiał',
+    stock: 'Zapas',
+    dailyRate: 'Tempo',
+    daysLeft: 'Pozostało dni',
+    emptyBy: 'Wyczerpie się',
+    reorderBy: 'Zamów do',
+    actions: 'Akcje',
+    // Rate tier badges
+    trend: 'Trend',
+    estimated: 'Szac.',
+    noData: 'Brak danych',
+    // Timeframe
+    timeframe: 'Zakres czasu',
+    // Chart
+    chartTitle: 'Prognozowany zapas — 5 głównych materiałów',
+    dashedLinesROP: 'Linie przerywane = punkty ponownego zamówienia',
+    stockLevel: 'Poziom zapasu',
+    reorderPoint: 'Punkt ponownego zamówienia',
+    safetyMargin: 'Margines bezpieczeństwa',
+    // Legend labels
+    trendLegend: 'Trend (na podstawie historii, poziom obsługi 95%)',
+    estimatedLegend: 'Szacowane (różnica wagi)',
+    noDataLegend: 'Brak danych',
+    ropLabel: 'ROP',
+    ssLabel: 'SS',
+    safetyStockLegend: 'Zapas bezpieczeństwa',
+    stockArrivalLegend: 'Dostawa zapasu',
+    stockoutLegend: 'Brak zapasu',
+    // Alerts toolbar
+    alertCount_one: '{{count}} alert',
+    alertCount_other: 'Alerty: {{count}}',
+    order: 'Zamów',
+    // Settings
+    save: 'Zapisz',
+    cancel: 'Anuluj',
+    settingsSaved: 'Ustawienia zapisane',
+    failedSaveSettings: 'Nie udało się zapisać ustawień',
+    globalLeadTimeSaved: 'Globalny czas realizacji zapisany',
+    globalLeadTime: 'Globalny czas realizacji',
+    globalLeadTimeHint: 'Minimalny globalny czas realizacji — używany do obliczania punktu ponownego zamówienia dla wszystkich SKU',
+    skuLeadTimeOverride: 'Nadpisanie czasu realizacji',
+    skuLeadTimeHint: '0 = użyj globalnego czasu realizacji. Ustaw >0, aby nadpisać dla tego SKU.',
+    safetyMarginLabel: 'Margines bezpieczeństwa',
+    effectiveLeadTime: 'Efektywny czas realizacji',
+    effectiveLeadTimeHint: 'max(globalny {{global}} d, SKU {{sku}} d)',
+    reorderPointHint: 'd̄ × LT + margines bezpieczeństwa — zamów, gdy zapas osiągnie ten poziom',
+    safetyMarginHint: 'Statystyczny zapas bezpieczeństwa (z=1.65 × σ × √LT) + bufor użytkownika',
+    safetyMarginHintDays: 'Bufor dodawany do statystycznego zapasu bezpieczeństwa.{{approx}}',
+    safetyMarginHintDaysApprox: ' ≈ {{g}} g przy obecnym tempie.',
+    safetyMarginHintG: 'Stały bufor wagowy dodawany do statystycznego zapasu bezpieczeństwa.{{approx}}',
+    safetyMarginHintGApprox: ' ≈ {{days}} d przy obecnym tempie.',
+    individualSpools: 'Pojedyncze szpule',
+    labelWeight: 'Nominalna',
+    spoolCount_one: '{{count}} szpula',
+    spoolCount_other: 'Szpule: {{count}}',
+    // Alerts
+    stockBreakRisk: 'Ryzyko braku zapasu',
+    stockBreakDetail: 'Pozostało {{days}} d, czas realizacji {{lt}} d.',
+    stockBreakBefore: 'Brak zapasu przed uzupełnieniem',
+    reorderNow: 'Zamów teraz',
+    reorderTriggerPassed: 'Data wyzwolenia {{date}} już minęła.',
+    // Shopping list
+    shoppingList: 'Lista zakupów',
+    shoppingListItems_one: '({{count}} pozycja)',
+    shoppingListItems_other: '(pozycje: {{count}})',
+    shoppingListEmpty: 'Lista zakupów jest pusta. Kliknij ikonę koszyka w dowolnym wierszu, aby dodać pozycje.',
+    addToCart: 'Dodaj do listy zakupów',
+    alertsSnoozed: 'Wycisz alerty dla tego SKU',
+    alertsEnabled: 'Wyłącz wyciszenie alertów dla tego SKU',
+    addedToCart: 'Dodano do listy zakupów',
+    failedAddItem: 'Nie udało się dodać pozycji',
+    listView: 'Lista',
+    logisticsView: 'Logistyka',
+    qty: 'Ilość',
+    weight: 'Waga',
+    leadTime: 'Czas realizacji',
+    expectedRestock: 'Oczekiwane uzupełnienie',
+    status: 'Status',
+    note: 'Notatka',
+    pending: 'Oczekujące',
+    purchased: 'Kupione',
+    received: 'Odebrane',
+    markPurchased: 'Oznacz jako kupione',
+    markReceived: 'Oznacz jako odebrane — dodaje szpule do magazynu',
+    resetToPending: 'Przywróć do oczekujących',
+    remove: 'Usuń',
+    clearAll: 'Wyczyść wszystko',
+    downloadCsv: 'CSV',
+    // Add to cart modal
+    addToCartTitle: 'Dodaj do listy zakupów',
+    byQuantity: 'Według ilości',
+    byDuration: 'Według czasu',
+    numberOfSpools: 'Liczba szpul',
+    lastHowManyDays: 'Na ile dni ma wystarczyć?',
+    noUsageQty: 'Brak danych o zużyciu — ilość ustawiona na 1.',
+    noteOptional: 'Notatka (opcjonalnie)',
+    notePlaceholder: 'np. do projektu X, pilne…',
+    addNSpools_one: 'Dodaj {{count}} szpulę',
+    addNSpools_other: 'Dodaj szpule ({{count}})',
+    // Cart logistics
+    onArrival: 'Przy dostawie',
+    stockBreakIn: 'Brak zapasu za {{days}} d.',
+    stockRunsOutBefore: 'Zapas wyczerpie się przed upływem {{lt}} d czasu realizacji.',
+    atRate: 'Przy tempie {{rate}} g/dzień potrzebujesz',
+    moreSpools_one: 'jeszcze {{count}} szpuli',
+    moreSpools_other: 'dodatkowych szpul ({{count}})',
+    bridgeGap: 'aby pokryć lukę.',
+    // Permissions
+    noReadAccess: 'Nie masz uprawnień do wyświetlania prognoz magazynu.',
+    noWriteAccess: 'Nie masz uprawnień do zmiany ustawień prognozy.',
+  },
+};

File diff suppressed because it is too large
+ 0 - 0
static/assets/ArchivesPage-8CknuujW.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/CamWallPage-C3tb3N4Q.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/CameraPage-CcU66lHE.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/FileManagerPage-C9YCGWxX.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/InventoryPage-CaIFj3z6.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/Layout-zU06-Qgt.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/ModelSourcesPage-D_11Pm1a.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/PrintersPage-DP4udQlz.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SettingsPage-C0IWxwPD.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SliceModal-B99RGGHt.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/SpoolBuddyInventoryPage-DWPKdfMC.js


File diff suppressed because it is too large
+ 1 - 1
static/assets/SpoolBuddySettingsPage-B4gxLS8t.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/index-B8Yl2nqQ.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/locationSensorDefaults-Dge3lLK0.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/pl-CcBt56DA.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/spoolCost-DafXHA2C.js


File diff suppressed because it is too large
+ 0 - 0
static/assets/usePageFileDrop-D5a7DdnT.js


+ 2 - 2
static/index.html

@@ -26,7 +26,7 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-CddO-Q62.js"></script>
+    <script type="module" crossorigin src="/assets/index-B8Yl2nqQ.js"></script>
     <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-aKtaBQYM.js">
     <link rel="modulepreload" crossorigin href="/assets/client-Bw3urp1w.js">
     <link rel="modulepreload" crossorigin href="/assets/react-dom-Bihwyis7.js">
@@ -122,7 +122,7 @@
     <link rel="modulepreload" crossorigin href="/assets/useColorCatalogVersion-D6uXNSEZ.js">
     <link rel="modulepreload" crossorigin href="/assets/circle-minus-C2rRKF7J.js">
     <link rel="modulepreload" crossorigin href="/assets/ConnectionDiagnostic-BaFc8Rjv.js">
-    <link rel="modulepreload" crossorigin href="/assets/Layout-kPbuVGjS.js">
+    <link rel="modulepreload" crossorigin href="/assets/Layout-zU06-Qgt.js">
     <link rel="stylesheet" crossorigin href="/assets/index-Vboviekw.css">
   </head>
   <body>

Some files were not shown because too many files changed in this diff