From bc895dff6a7ab69f054ec062f8861f4ec3276f86 Mon Sep 17 00:00:00 2001 From: maziggy Date: Mon, 20 Apr 2026 12:45:49 +0200 Subject: [PATCH] =?UTF-8?q?=E2=97=8F=20fix(ams):=20restore=20Configure/Ass?= =?UTF-8?q?ign=20actions=20on=20reset=20slots=20+=20relax=20Assign=20Spool?= =?UTF-8?q?=20filtering=20(#1047)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three related fixes reported together: (1) After resetting an AMS slot, the printer card showed "Empty Slot" with no Configure or Assign Spool actions while SpoolBuddy's AMS page still let the user re-configure the same slot. Commit c9efa4b8 (#784) added a `tray?.state === 10` gate to the EmptySlotHoverCard actions, intended to hide them on physically-empty slots (state=9). In practice firmware often reports state=9 (or omits state entirely) after a user-initiated reset even when a spool is still present, so the gate hit the wrong case. The gate was redundant anyway — EmptySlotHoverCard only renders when tray_type is empty — so it's removed at both the standard-AMS and AMS-HT render paths. (2) After configuring a slot with a Generic profile, the Assign Spool modal hid manually-added inventory spools even when material matched, unless the user flipped "Show all spools". The filter required exact slicer_filament_name equality, which manually-added spools don't populate. Filter now prefers exact slicer-profile match when both sides have one, and falls back to partial material match in either direction (so a "PLA" spool shows up for a "PLA Basic" slot). (3) On assign, the mismatch dialog fired on every Generic spool because Bambu Studio / OrcaSlicer profile names carry an @printer nozzle (variant) qualifier while the tray stores the bare base name. Both the filter and checkProfileMatch now strip everything from @ onward before comparing. Adds 3 regression tests covering each path. --- CHANGELOG.md | 1 + .../components/AssignSpoolModal.test.tsx | 105 +++++++++++++++ frontend/src/components/AssignSpoolModal.tsx | 35 ++++- frontend/src/pages/PrintersPage.tsx | 16 +-- .../{index-BVXFAk6e.js => index-C60hlRK5.js} | 126 +++++++++--------- static/index.html | 2 +- 6 files changed, 206 insertions(+), 79 deletions(-) rename static/assets/{index-BVXFAk6e.js => index-C60hlRK5.js} (92%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19bc80898..6fe973000 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to Bambuddy will be documented in this file. ## [0.2.4b1] - Unreleased ### Fixed +- **AMS: Configure / Assign Spool Hidden on Reset Slots, and Assign Spool Missing Matching-Material Inventory** ([#1047](https://github.com/maziggy/bambuddy/issues/1047)) — Two separate symptoms from the same report. (1) After resetting an AMS slot from the printer UI, the Bambuddy printer card showed "Empty Slot" with no Configure or Assign Spool actions on hover, while the same slot in SpoolBuddy's AMS page still let the user re-configure it. Root cause: commit `c9efa4b8` (#784) added a `tray?.state === 10` gate to the `EmptySlotHoverCard` actions, intended to show the buttons only when a spool was physically present but not loaded (state=10) and hide them on truly empty slots (state=9). In practice, firmware often reports `state=9` (or no `state` field at all) after a user-initiated reset — even when a spool is still physically in the slot — so the actions disappeared exactly when the user needed them. The gate is redundant anyway (`EmptySlotHoverCard` is only rendered when the slot has no `tray_type`, so it's definitionally empty from Bambuddy's perspective), and configuring an empty slot is a valid "tell the printer what will be loaded here" operation. The gate is now removed at both the standard-AMS and AMS-HT render paths. (2) After configuring a slot with a Generic profile (e.g. "Devil Design PLA Basic Red"), the Assign Spool modal didn't list the matching inventory spool unless the user enabled the "Show all spools" toggle. Root cause: the filter at `AssignSpoolModal.tsx:144` required `normalizeValue(spool.slicer_filament_name) === normalizeValue(trayInfo.profile)` — manually-added inventory spools typically don't have `slicer_filament_name` populated, so they failed the exact-profile check even when the material matched. The filter now prefers an exact slicer-profile match when both sides advertise one, and falls back to partial material match in either direction (so e.g. a spool with `material="PLA"` is selectable for a slot reporting `"PLA Basic"`) when profile info is missing. (3) Once the matching spool was assignable, a "profile mismatch" confirmation dialog still warned on every assignment because Bambu Studio / OrcaSlicer slicer-profile names carry a printer/nozzle/variant qualifier after `@` (e.g. `"Devil Design PLA Basic @Bambu Lab H2D 0.4 nozzle (Custom)"`) while the tray stores only the bare base name (`"Devil Design PLA Basic"`), and `checkProfileMatch` compared the full strings. Both the filter and the mismatch check now strip the `@…` qualifier before comparing, so identical base profiles are treated as a match. Regression test covers a spool with no slicer profile being surfaced for a slot whose profile + material are both set. Thanks to @TravisWilder for the report. - **Skip Objects: Enlarged Preview Image Fails to Load on Auth-Enabled Instances** ([#1046](https://github.com/maziggy/bambuddy/issues/1046)) — Clicking the mini print-pr diff --git a/frontend/src/__tests__/components/AssignSpoolModal.test.tsx b/frontend/src/__tests__/components/AssignSpoolModal.test.tsx index 594145e89..21098cb75 100644 --- a/frontend/src/__tests__/components/AssignSpoolModal.test.tsx +++ b/frontend/src/__tests__/components/AssignSpoolModal.test.tsx @@ -134,4 +134,109 @@ describe('AssignSpoolModal', () => { expect(screen.getByText(/No manually added spools/i)).toBeInTheDocument(); }); }); + + it('lists spool with no slicer profile when material matches the tray (#1047)', async () => { + const spoolWithoutSlicerProfile = { + id: 10, + material: 'PLA', + subtype: 'Basic', + brand: 'Devil Design', + color_name: 'Red', + rgba: 'FF0000FF', + label_weight: 1000, + weight_used: 0, + tag_uid: null, + tray_uuid: null, + slicer_filament_name: null, + slicer_filament: null, + }; + (api.getSpools as ReturnType).mockResolvedValue([spoolWithoutSlicerProfile]); + + render( + + ); + + await waitFor(() => { + expect(screen.getByText(/Devil Design/)).toBeInTheDocument(); + }); + }); + + it('lists spool with shorter material when tray advertises a qualified variant (#1047)', async () => { + // Spool.material = "PLA", tray material = "PLA Basic" — partial match in either direction. + const shortMaterialSpool = { + id: 11, + material: 'PLA', + subtype: 'Basic', + brand: 'Devil Design', + color_name: 'Red', + rgba: 'FF0000FF', + label_weight: 1000, + weight_used: 0, + tag_uid: null, + tray_uuid: null, + slicer_filament_name: null, + slicer_filament: null, + }; + (api.getSpools as ReturnType).mockResolvedValue([shortMaterialSpool]); + + render( + + ); + + await waitFor(() => { + expect(screen.getByText(/Devil Design/)).toBeInTheDocument(); + }); + }); + + it('lists spool whose slicer profile has an @printer qualifier that strips to the tray profile (#1047)', async () => { + const qualifiedProfileSpool = { + id: 12, + material: 'PLA', + subtype: 'Basic', + brand: 'Devil Design', + color_name: 'Red', + rgba: 'FF0000FF', + label_weight: 1000, + weight_used: 0, + tag_uid: null, + tray_uuid: null, + slicer_filament_name: 'Devil Design PLA Basic @Bambu Lab H2D 0.4 nozzle (Custom)', + }; + // Use a non-matching material to force the filter to rely on the profile path only. + (api.getSpools as ReturnType).mockResolvedValue([qualifiedProfileSpool]); + + render( + + ); + + await waitFor(() => { + expect(screen.getByText(/Devil Design/)).toBeInTheDocument(); + }); + }); }); diff --git a/frontend/src/components/AssignSpoolModal.tsx b/frontend/src/components/AssignSpoolModal.tsx index 860229d31..7670f5a24 100644 --- a/frontend/src/components/AssignSpoolModal.tsx +++ b/frontend/src/components/AssignSpoolModal.tsx @@ -111,12 +111,18 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr return 'none'; }; + // Bambu Studio / OrcaSlicer profile names carry a printer/nozzle/variant qualifier after + // `@` (e.g. "Devil Design PLA Basic @Bambu Lab H2D 0.4 nozzle (Custom)"), while the tray's + // profile is typically the bare base name. Strip the qualifier before comparing so identical + // base profiles don't trigger a mismatch warning (#1047). + const stripProfileQualifier = (value: string) => value.split('@')[0].trim(); + const checkProfileMatch = ( spoolProfile: string | undefined | null, trayProfile: string | undefined | null ): boolean => { - const normalizedSpoolProfile = normalizeValue(spoolProfile); - const normalizedTrayProfile = normalizeValue(trayProfile); + const normalizedSpoolProfile = stripProfileQualifier(normalizeValue(spoolProfile)); + const normalizedTrayProfile = stripProfileQualifier(normalizeValue(trayProfile)); if (!normalizedSpoolProfile || !normalizedTrayProfile) return false; @@ -138,14 +144,29 @@ export function AssignSpoolModal({ isOpen, onClose, printerId, amsId, trayId, tr !assignedSpoolIds.has(spool.id) && (isExternalSlot || (!spool.tag_uid && !spool.tray_uuid)) ); - // Filtering logic with toggle: search filter always applies, AMS tray profile filter is optional + // Filtering logic with toggle: search filter always applies, AMS tray profile filter is optional. + // Show a spool if EITHER the slicer profile matches exactly OR the material overlaps with the + // tray's material (partial-match both directions — "PLA" spool accepts a "PLA Basic" slot and + // vice versa). Manually-added inventory spools typically have no slicer_filament_name; gating + // on strict profile equality alone hid them even when the material matched (#1047). let filteredSpools = manualSpools; if (!disableFiltering) { - if (trayInfo?.profile || trayInfo?.type) { - const trayProfile = normalizeValue(trayInfo.profile || trayInfo.type); + const trayProfile = stripProfileQualifier(normalizeValue(trayInfo?.profile)); + const trayMaterial = normalizeValue(trayInfo?.material || trayInfo?.type); + if (trayProfile || trayMaterial) { filteredSpools = filteredSpools?.filter((spool: InventorySpool) => { - const spoolProfile = normalizeValue(spool.slicer_filament_name || spool.slicer_filament); - return trayProfile && spoolProfile && spoolProfile === trayProfile; + const spoolProfile = stripProfileQualifier(normalizeValue(spool.slicer_filament_name || spool.slicer_filament)); + const spoolMaterial = normalizeValue(spool.material); + if (trayProfile && spoolProfile && spoolProfile === trayProfile) return true; + if (trayMaterial && spoolMaterial) { + return ( + spoolMaterial === trayMaterial || + trayMaterial.includes(spoolMaterial) || + spoolMaterial.includes(trayMaterial) + ); + } + // Neither side has filterable info on whatever dimension remains — show it. + return !spoolProfile && !spoolMaterial; }); } } diff --git a/frontend/src/pages/PrintersPage.tsx b/frontend/src/pages/PrintersPage.tsx index f2087c87c..938ae169f 100644 --- a/frontend/src/pages/PrintersPage.tsx +++ b/frontend/src/pages/PrintersPage.tsx @@ -3552,7 +3552,7 @@ function PrinterCard({ ) : ( setConfigureSlotModal({ amsId: ams.id, @@ -3560,8 +3560,8 @@ function PrinterCard({ trayCount: ams.tray.length, extruderId: mappedExtruderId, }), - } : undefined} - inventory={tray?.state === 10 && !spoolmanEnabled ? { + }} + inventory={spoolmanEnabled ? undefined : { onAssignSpool: () => setAssignSpoolModal({ printerId: printer.id, amsId: ams.id, @@ -3572,7 +3572,7 @@ function PrinterCard({ location: `${getAmsLabel(ams.id, ams.tray.length)} Slot ${slotIdx + 1}`, }, }), - } : undefined} + }} > {slotVisual} @@ -3870,7 +3870,7 @@ function PrinterCard({ ) : ( setConfigureSlotModal({ amsId: ams.id, @@ -3878,8 +3878,8 @@ function PrinterCard({ trayCount: ams.tray.length, extruderId: mappedExtruderId, }), - } : undefined} - inventory={tray?.state === 10 && !spoolmanEnabled ? { + }} + inventory={spoolmanEnabled ? undefined : { onAssignSpool: () => setAssignSpoolModal({ printerId: printer.id, amsId: ams.id, @@ -3890,7 +3890,7 @@ function PrinterCard({ location: getAmsLabel(ams.id, ams.tray.length), }, }), - } : undefined} + }} > {slotVisual} diff --git a/static/assets/index-BVXFAk6e.js b/static/assets/index-C60hlRK5.js similarity index 92% rename from static/assets/index-BVXFAk6e.js rename to static/assets/index-C60hlRK5.js index bc2d3d835..d6093b528 100644 --- a/static/assets/index-BVXFAk6e.js +++ b/static/assets/index-C60hlRK5.js @@ -1,12 +1,12 @@ -function Fde(t,e){for(var n=0;nr[i]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(i){if(i.ep)return;i.ep=!0;const s=n(i);fetch(i.href,s)}})();var $_=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function bc(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var mM={exports:{}},kv={};var T8;function Rde(){if(T8)return kv;T8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function n(r,i,s){var o=null;if(s!==void 0&&(o=""+s),i.key!==void 0&&(o=""+i.key),"key"in i){s={};for(var l in i)l!=="key"&&(s[l]=i[l])}else s=i;return i=s.ref,{$$typeof:t,type:r,key:o,ref:i!==void 0?i:null,props:s}}return kv.Fragment=e,kv.jsx=n,kv.jsxs=n,kv}var A8;function Lde(){return A8||(A8=1,mM.exports=Rde()),mM.exports}var a=Lde(),hM={exports:{}},Xn={};var j8;function Ode(){if(j8)return Xn;j8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),s=Symbol.for("react.consumer"),o=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),u=Symbol.for("react.lazy"),m=Symbol.for("react.activity"),p=Symbol.iterator;function f(W){return W===null||typeof W!="object"?null:(W=p&&W[p]||W["@@iterator"],typeof W=="function"?W:null)}var x={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},v=Object.assign,b={};function g(W,ne,fe){this.props=W,this.context=ne,this.refs=b,this.updater=fe||x}g.prototype.isReactComponent={},g.prototype.setState=function(W,ne){if(typeof W!="object"&&typeof W!="function"&&W!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,W,ne,"setState")},g.prototype.forceUpdate=function(W){this.updater.enqueueForceUpdate(this,W,"forceUpdate")};function _(){}_.prototype=g.prototype;function C(W,ne,fe){this.props=W,this.context=ne,this.refs=b,this.updater=fe||x}var P=C.prototype=new _;P.constructor=C,v(P,g.prototype),P.isPureReactComponent=!0;var N=Array.isArray;function A(){}var T={H:null,A:null,T:null,S:null},F=Object.prototype.hasOwnProperty;function k(W,ne,fe){var be=fe.ref;return{$$typeof:t,type:W,key:ne,ref:be!==void 0?be:null,props:fe}}function D(W,ne){return k(W.type,ne,W.props)}function H(W){return typeof W=="object"&&W!==null&&W.$$typeof===t}function z(W){var ne={"=":"=0",":":"=2"};return"$"+W.replace(/[=:]/g,function(fe){return ne[fe]})}var Y=/\/+/g;function L(W,ne){return typeof W=="object"&&W!==null&&W.key!=null?z(""+W.key):ne.toString(36)}function te(W){switch(W.status){case"fulfilled":return W.value;case"rejected":throw W.reason;default:switch(typeof W.status=="string"?W.then(A,A):(W.status="pending",W.then(function(ne){W.status==="pending"&&(W.status="fulfilled",W.value=ne)},function(ne){W.status==="pending"&&(W.status="rejected",W.reason=ne)})),W.status){case"fulfilled":return W.value;case"rejected":throw W.reason}}throw W}function ae(W,ne,fe,be,Pe){var q=typeof W;(q==="undefined"||q==="boolean")&&(W=null);var Q=!1;if(W===null)Q=!0;else switch(q){case"bigint":case"string":case"number":Q=!0;break;case"object":switch(W.$$typeof){case t:case e:Q=!0;break;case u:return Q=W._init,ae(Q(W._payload),ne,fe,be,Pe)}}if(Q)return Pe=Pe(W),Q=be===""?"."+L(W,0):be,N(Pe)?(fe="",Q!=null&&(fe=Q.replace(Y,"$&/")+"/"),ae(Pe,ne,fe,"",function(O){return O})):Pe!=null&&(H(Pe)&&(Pe=D(Pe,fe+(Pe.key==null||W&&W.key===Pe.key?"":(""+Pe.key).replace(Y,"$&/")+"/")+Q)),ne.push(Pe)),1;Q=0;var E=be===""?".":be+":";if(N(W))for(var j=0;j>>1,oe=ae[se];if(0>>1;sei(fe,le))bei(Pe,fe)?(ae[se]=Pe,ae[be]=le,se=be):(ae[se]=fe,ae[ne]=le,se=ne);else if(bei(Pe,le))ae[se]=Pe,ae[be]=le,se=be;else break e}}return J}function i(ae,J){var le=ae.sortIndex-J.sortIndex;return le!==0?le:ae.id-J.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var s=performance;t.unstable_now=function(){return s.now()}}else{var o=Date,l=o.now();t.unstable_now=function(){return o.now()-l}}var c=[],d=[],u=1,m=null,p=3,f=!1,x=!1,v=!1,b=!1,g=typeof setTimeout=="function"?setTimeout:null,_=typeof clearTimeout=="function"?clearTimeout:null,C=typeof setImmediate<"u"?setImmediate:null;function P(ae){for(var J=n(d);J!==null;){if(J.callback===null)r(d);else if(J.startTime<=ae)r(d),J.sortIndex=J.expirationTime,e(c,J);else break;J=n(d)}}function N(ae){if(v=!1,P(ae),!x)if(n(c)!==null)x=!0,A||(A=!0,z());else{var J=n(d);J!==null&&te(N,J.startTime-ae)}}var A=!1,T=-1,F=5,k=-1;function D(){return b?!0:!(t.unstable_now()-kae&&D());){var se=m.callback;if(typeof se=="function"){m.callback=null,p=m.priorityLevel;var oe=se(m.expirationTime<=ae);if(ae=t.unstable_now(),typeof oe=="function"){m.callback=oe,P(ae),J=!0;break t}m===n(c)&&r(c),P(ae)}else r(c);m=n(c)}if(m!==null)J=!0;else{var W=n(d);W!==null&&te(N,W.startTime-ae),J=!1}}break e}finally{m=null,p=le,f=!1}J=void 0}}finally{J?z():A=!1}}}var z;if(typeof C=="function")z=function(){C(H)};else if(typeof MessageChannel<"u"){var Y=new MessageChannel,L=Y.port2;Y.port1.onmessage=H,z=function(){L.postMessage(null)}}else z=function(){g(H,0)};function te(ae,J){T=g(function(){ae(t.unstable_now())},J)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(ae){ae.callback=null},t.unstable_forceFrameRate=function(ae){0>ae||125se?(ae.sortIndex=le,e(d,ae),n(c)===null&&ae===n(d)&&(v?(_(T),T=-1):v=!0,te(N,le-se))):(ae.sortIndex=oe,e(c,ae),x||f||(x=!0,A||(A=!0,z()))),ae},t.unstable_shouldYield=D,t.unstable_wrapCallback=function(ae){var J=p;return function(){var le=p;p=J;try{return ae.apply(this,arguments)}finally{p=le}}}})(gM)),gM}var D8;function Ude(){return D8||(D8=1,fM.exports=zde()),fM.exports}var bM={exports:{}},Ms={};var F8;function Bde(){if(F8)return Ms;F8=1;var t=jg();function e(c){var d="https://react.dev/errors/"+c;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),bM.exports=Bde(),bM.exports}var L8;function Hde(){if(L8)return Nv;L8=1;var t=Ude(),e=jg(),n=UY();function r(h){var y="https://react.dev/errors/"+h;if(1oe||(h.current=se[oe],se[oe]=null,oe--)}function fe(h,y){oe++,se[oe]=h.current,h.current=y}var be=W(null),Pe=W(null),q=W(null),Q=W(null);function E(h,y){switch(fe(q,y),fe(Pe,h),fe(be,null),y.nodeType){case 9:case 11:h=(h=y.documentElement)&&(h=h.namespaceURI)?QB(h):0;break;default:if(h=y.tagName,y=y.namespaceURI)y=QB(y),h=ZB(y,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}ne(be),fe(be,h)}function j(){ne(be),ne(Pe),ne(q)}function O(h){h.memoizedState!==null&&fe(Q,h);var y=be.current,S=ZB(y,h.type);y!==S&&(fe(Pe,h),fe(be,S))}function K(h){Pe.current===h&&(ne(be),ne(Pe)),Q.current===h&&(ne(Q),vv._currentValue=le)}var U,me;function I(h){if(U===void 0)try{throw Error()}catch(S){var y=S.stack.trim().match(/\n( *(at )?)/);U=y&&y[1]||"",me=-1r[i]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(i){if(i.ep)return;i.ep=!0;const s=n(i);fetch(i.href,s)}})();var $_=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function bc(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var mM={exports:{}},kv={};var T8;function Rde(){if(T8)return kv;T8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function n(r,i,s){var o=null;if(s!==void 0&&(o=""+s),i.key!==void 0&&(o=""+i.key),"key"in i){s={};for(var l in i)l!=="key"&&(s[l]=i[l])}else s=i;return i=s.ref,{$$typeof:t,type:r,key:o,ref:i!==void 0?i:null,props:s}}return kv.Fragment=e,kv.jsx=n,kv.jsxs=n,kv}var A8;function Lde(){return A8||(A8=1,mM.exports=Rde()),mM.exports}var a=Lde(),hM={exports:{}},Xn={};var j8;function Ode(){if(j8)return Xn;j8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),s=Symbol.for("react.consumer"),o=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),u=Symbol.for("react.lazy"),m=Symbol.for("react.activity"),p=Symbol.iterator;function f(W){return W===null||typeof W!="object"?null:(W=p&&W[p]||W["@@iterator"],typeof W=="function"?W:null)}var x={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},v=Object.assign,b={};function g(W,ne,me){this.props=W,this.context=ne,this.refs=b,this.updater=me||x}g.prototype.isReactComponent={},g.prototype.setState=function(W,ne){if(typeof W!="object"&&typeof W!="function"&&W!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,W,ne,"setState")},g.prototype.forceUpdate=function(W){this.updater.enqueueForceUpdate(this,W,"forceUpdate")};function _(){}_.prototype=g.prototype;function C(W,ne,me){this.props=W,this.context=ne,this.refs=b,this.updater=me||x}var P=C.prototype=new _;P.constructor=C,v(P,g.prototype),P.isPureReactComponent=!0;var N=Array.isArray;function A(){}var T={H:null,A:null,T:null,S:null},F=Object.prototype.hasOwnProperty;function k(W,ne,me){var be=me.ref;return{$$typeof:t,type:W,key:ne,ref:be!==void 0?be:null,props:me}}function D(W,ne){return k(W.type,ne,W.props)}function H(W){return typeof W=="object"&&W!==null&&W.$$typeof===t}function z(W){var ne={"=":"=0",":":"=2"};return"$"+W.replace(/[=:]/g,function(me){return ne[me]})}var Y=/\/+/g;function L(W,ne){return typeof W=="object"&&W!==null&&W.key!=null?z(""+W.key):ne.toString(36)}function te(W){switch(W.status){case"fulfilled":return W.value;case"rejected":throw W.reason;default:switch(typeof W.status=="string"?W.then(A,A):(W.status="pending",W.then(function(ne){W.status==="pending"&&(W.status="fulfilled",W.value=ne)},function(ne){W.status==="pending"&&(W.status="rejected",W.reason=ne)})),W.status){case"fulfilled":return W.value;case"rejected":throw W.reason}}throw W}function ie(W,ne,me,be,Pe){var q=typeof W;(q==="undefined"||q==="boolean")&&(W=null);var Q=!1;if(W===null)Q=!0;else switch(q){case"bigint":case"string":case"number":Q=!0;break;case"object":switch(W.$$typeof){case t:case e:Q=!0;break;case u:return Q=W._init,ie(Q(W._payload),ne,me,be,Pe)}}if(Q)return Pe=Pe(W),Q=be===""?"."+L(W,0):be,N(Pe)?(me="",Q!=null&&(me=Q.replace(Y,"$&/")+"/"),ie(Pe,ne,me,"",function(O){return O})):Pe!=null&&(H(Pe)&&(Pe=D(Pe,me+(Pe.key==null||W&&W.key===Pe.key?"":(""+Pe.key).replace(Y,"$&/")+"/")+Q)),ne.push(Pe)),1;Q=0;var E=be===""?".":be+":";if(N(W))for(var j=0;j>>1,re=ie[fe];if(0>>1;fei(me,oe))bei(Pe,me)?(ie[fe]=Pe,ie[be]=oe,fe=be):(ie[fe]=me,ie[ne]=oe,fe=ne);else if(bei(Pe,oe))ie[fe]=Pe,ie[be]=oe,fe=be;else break e}}return J}function i(ie,J){var oe=ie.sortIndex-J.sortIndex;return oe!==0?oe:ie.id-J.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var s=performance;t.unstable_now=function(){return s.now()}}else{var o=Date,l=o.now();t.unstable_now=function(){return o.now()-l}}var c=[],d=[],u=1,m=null,p=3,f=!1,x=!1,v=!1,b=!1,g=typeof setTimeout=="function"?setTimeout:null,_=typeof clearTimeout=="function"?clearTimeout:null,C=typeof setImmediate<"u"?setImmediate:null;function P(ie){for(var J=n(d);J!==null;){if(J.callback===null)r(d);else if(J.startTime<=ie)r(d),J.sortIndex=J.expirationTime,e(c,J);else break;J=n(d)}}function N(ie){if(v=!1,P(ie),!x)if(n(c)!==null)x=!0,A||(A=!0,z());else{var J=n(d);J!==null&&te(N,J.startTime-ie)}}var A=!1,T=-1,F=5,k=-1;function D(){return b?!0:!(t.unstable_now()-kie&&D());){var fe=m.callback;if(typeof fe=="function"){m.callback=null,p=m.priorityLevel;var re=fe(m.expirationTime<=ie);if(ie=t.unstable_now(),typeof re=="function"){m.callback=re,P(ie),J=!0;break t}m===n(c)&&r(c),P(ie)}else r(c);m=n(c)}if(m!==null)J=!0;else{var W=n(d);W!==null&&te(N,W.startTime-ie),J=!1}}break e}finally{m=null,p=oe,f=!1}J=void 0}}finally{J?z():A=!1}}}var z;if(typeof C=="function")z=function(){C(H)};else if(typeof MessageChannel<"u"){var Y=new MessageChannel,L=Y.port2;Y.port1.onmessage=H,z=function(){L.postMessage(null)}}else z=function(){g(H,0)};function te(ie,J){T=g(function(){ie(t.unstable_now())},J)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(ie){ie.callback=null},t.unstable_forceFrameRate=function(ie){0>ie||125fe?(ie.sortIndex=oe,e(d,ie),n(c)===null&&ie===n(d)&&(v?(_(T),T=-1):v=!0,te(N,oe-fe))):(ie.sortIndex=re,e(c,ie),x||f||(x=!0,A||(A=!0,z()))),ie},t.unstable_shouldYield=D,t.unstable_wrapCallback=function(ie){var J=p;return function(){var oe=p;p=J;try{return ie.apply(this,arguments)}finally{p=oe}}}})(gM)),gM}var D8;function Ude(){return D8||(D8=1,fM.exports=zde()),fM.exports}var bM={exports:{}},Ms={};var F8;function Bde(){if(F8)return Ms;F8=1;var t=jg();function e(c){var d="https://react.dev/errors/"+c;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),bM.exports=Bde(),bM.exports}var L8;function Hde(){if(L8)return Nv;L8=1;var t=Ude(),e=jg(),n=UY();function r(h){var y="https://react.dev/errors/"+h;if(1re||(h.current=fe[re],fe[re]=null,re--)}function me(h,y){re++,fe[re]=h.current,h.current=y}var be=W(null),Pe=W(null),q=W(null),Q=W(null);function E(h,y){switch(me(q,y),me(Pe,h),me(be,null),y.nodeType){case 9:case 11:h=(h=y.documentElement)&&(h=h.namespaceURI)?QB(h):0;break;default:if(h=y.tagName,y=y.namespaceURI)y=QB(y),h=ZB(y,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}ne(be),me(be,h)}function j(){ne(be),ne(Pe),ne(q)}function O(h){h.memoizedState!==null&&me(Q,h);var y=be.current,S=ZB(y,h.type);y!==S&&(me(Pe,h),me(be,S))}function K(h){Pe.current===h&&(ne(be),ne(Pe)),Q.current===h&&(ne(Q),vv._currentValue=oe)}var U,ue;function I(h){if(U===void 0)try{throw Error()}catch(S){var y=S.stack.trim().match(/\n( *(at )?)/);U=y&&y[1]||"",ue=-1)":-1$||nt[M]!==Nt[$]){var Lt=` `+nt[M].replace(" at new "," at ");return h.displayName&&Lt.includes("")&&(Lt=Lt.replace("",h.displayName)),Lt}while(1<=M&&0<=$);break}}}finally{G=!1,Error.prepareStackTrace=S}return(S=h?h.displayName||h.name:"")?I(S):""}function V(h,y){switch(h.tag){case 26:case 27:case 5:return I(h.type);case 16:return I("Lazy");case 13:return h.child!==y&&y!==null?I("Suspense Fallback"):I("Suspense");case 19:return I("SuspenseList");case 0:case 15:return X(h.type,!1);case 11:return X(h.type.render,!1);case 1:return X(h.type,!0);case 31:return I("Activity");default:return""}}function ee(h){try{var y="",S=null;do y+=V(h,S),S=h,h=h.return;while(h);return y}catch(M){return` Error generating stack: `+M.message+` -`+M.stack}}var ie=Object.prototype.hasOwnProperty,ge=t.unstable_scheduleCallback,pe=t.unstable_cancelCallback,ce=t.unstable_shouldYield,B=t.unstable_requestPaint,R=t.unstable_now,re=t.unstable_getCurrentPriorityLevel,ke=t.unstable_ImmediatePriority,Se=t.unstable_UserBlockingPriority,ye=t.unstable_NormalPriority,Te=t.unstable_LowPriority,ve=t.unstable_IdlePriority,Ae=t.log,Re=t.unstable_setDisableYieldValue,Me=null,Le=null;function Oe(h){if(typeof Ae=="function"&&Re(h),Le&&typeof Le.setStrictMode=="function")try{Le.setStrictMode(Me,h)}catch{}}var qe=Math.clz32?Math.clz32:he,Qe=Math.log,tt=Math.LN2;function he(h){return h>>>=0,h===0?32:31-(Qe(h)/tt|0)|0}var Fe=256,we=262144,Ve=4194304;function je(h){var y=h&42;if(y!==0)return y;switch(h&-h){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return h&261888;case 262144:case 524288:case 1048576:case 2097152:return h&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return h&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return h}}function de(h,y,S){var M=h.pendingLanes;if(M===0)return 0;var $=0,Z=h.suspendedLanes,Ne=h.pingedLanes;h=h.warmLanes;var He=M&134217727;return He!==0?(M=He&~Z,M!==0?$=je(M):(Ne&=He,Ne!==0?$=je(Ne):S||(S=He&~h,S!==0&&($=je(S))))):(He=M&~Z,He!==0?$=je(He):Ne!==0?$=je(Ne):S||(S=M&~h,S!==0&&($=je(S)))),$===0?0:y!==0&&y!==$&&(y&Z)===0&&(Z=$&-$,S=y&-y,Z>=S||Z===32&&(S&4194048)!==0)?y:$}function xe(h,y){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&y)===0}function Be(h,y){switch(h){case 1:case 2:case 4:case 8:case 64:return y+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return y+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var h=Ve;return Ve<<=1,(Ve&62914560)===0&&(Ve=4194304),h}function pt(h){for(var y=[],S=0;31>S;S++)y.push(h);return y}function xt(h,y){h.pendingLanes|=y,y!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function yt(h,y,S,M,$,Z){var Ne=h.pendingLanes;h.pendingLanes=S,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=S,h.entangledLanes&=S,h.errorRecoveryDisabledLanes&=S,h.shellSuspendCounter=0;var He=h.entanglements,nt=h.expirationTimes,Nt=h.hiddenUpdates;for(S=Ne&~S;0"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var Dr=/[\n"\\]/g;function En(h){return h.replace(Dr,function(y){return"\\"+y.charCodeAt(0).toString(16)+" "})}function Ea(h,y,S,M,$,Z,Ne,He){h.name="",Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"?h.type=Ne:h.removeAttribute("type"),y!=null?Ne==="number"?(y===0&&h.value===""||h.value!=y)&&(h.value=""+zn(y)):h.value!==""+zn(y)&&(h.value=""+zn(y)):Ne!=="submit"&&Ne!=="reset"||h.removeAttribute("value"),y!=null?na(h,Ne,zn(y)):S!=null?na(h,Ne,zn(S)):M!=null&&h.removeAttribute("value"),$==null&&Z!=null&&(h.defaultChecked=!!Z),$!=null&&(h.checked=$&&typeof $!="function"&&typeof $!="symbol"),He!=null&&typeof He!="function"&&typeof He!="symbol"&&typeof He!="boolean"?h.name=""+zn(He):h.removeAttribute("name")}function Pn(h,y,S,M,$,Z,Ne,He){if(Z!=null&&typeof Z!="function"&&typeof Z!="symbol"&&typeof Z!="boolean"&&(h.type=Z),y!=null||S!=null){if(!(Z!=="submit"&&Z!=="reset"||y!=null)){gn(h);return}S=S!=null?""+zn(S):"",y=y!=null?""+zn(y):S,He||y===h.value||(h.value=y),h.defaultValue=y}M=M??$,M=typeof M!="function"&&typeof M!="symbol"&&!!M,h.checked=He?h.checked:!!M,h.defaultChecked=!!M,Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"&&(h.name=Ne),gn(h)}function na(h,y,S){y==="number"&&gr(h.ownerDocument)===h||h.defaultValue===""+S||(h.defaultValue=""+S)}function qn(h,y,S,M){if(h=h.options,y){y={};for(var $=0;$"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),kl=!1;if(Ns)try{var ns={};Object.defineProperty(ns,"passive",{get:function(){kl=!0}}),window.addEventListener("test",ns,ns),window.removeEventListener("test",ns,ns)}catch{kl=!1}var $o=null,Nl=null,wc=null;function vo(){if(wc)return wc;var h,y=Nl,S=y.length,M,$="value"in $o?$o.value:$o.textContent,Z=$.length;for(h=0;h=ct),ir=" ",aa=!1;function ka(h,y){switch(h){case"keyup":return Ht.indexOf(y.keyCode)!==-1;case"keydown":return y.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Jt(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var vn=!1;function Da(h,y){switch(h){case"compositionend":return Jt(y);case"keypress":return y.which!==32?null:(aa=!0,ir);case"textInput":return h=y.data,h===ir&&aa?null:h;default:return null}}function di(h,y){if(vn)return h==="compositionend"||!Zt&&ka(h,y)?(h=vo(),wc=Nl=$o=null,vn=!1,h):null;switch(h){case"paste":return null;case"keypress":if(!(y.ctrlKey||y.altKey||y.metaKey)||y.ctrlKey&&y.altKey){if(y.char&&1=y)return{node:S,offset:y-h};h=M}e:{for(;S;){if(S.nextSibling){S=S.nextSibling;break e}S=S.parentNode}S=void 0}S=BS(S)}}function b5(h,y){return h&&y?h===y?!0:h&&h.nodeType===3?!1:y&&y.nodeType===3?b5(h,y.parentNode):"contains"in h?h.contains(y):h.compareDocumentPosition?!!(h.compareDocumentPosition(y)&16):!1:!1}function x5(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var y=gr(h.document);y instanceof h.HTMLIFrameElement;){try{var S=typeof y.contentWindow.location.href=="string"}catch{S=!1}if(S)h=y.contentWindow;else break;y=gr(h.document)}return y}function wA(h){var y=h&&h.nodeName&&h.nodeName.toLowerCase();return y&&(y==="input"&&(h.type==="text"||h.type==="search"||h.type==="tel"||h.type==="url"||h.type==="password")||y==="textarea"||h.contentEditable==="true")}var hce=Ns&&"documentMode"in document&&11>=document.documentMode,Gg=null,SA=null,Vy=null,_A=!1;function y5(h,y,S){var M=S.window===S?S.document:S.nodeType===9?S:S.ownerDocument;_A||Gg==null||Gg!==gr(M)||(M=Gg,"selectionStart"in M&&wA(M)?M={start:M.selectionStart,end:M.selectionEnd}:(M=(M.ownerDocument&&M.ownerDocument.defaultView||window).getSelection(),M={anchorNode:M.anchorNode,anchorOffset:M.anchorOffset,focusNode:M.focusNode,focusOffset:M.focusOffset}),Vy&&Um(Vy,M)||(Vy=M,M=A_(SA,"onSelect"),0>=Ne,$-=Ne,md=1<<32-qe(y)+$|S<<$|M,hd=Z+h}else md=1<Zn?(yr=bn,bn=null):yr=bn.sibling;var Ar=Ct(bt,bn,kt[Zn],Ot);if(Ar===null){bn===null&&(bn=yr);break}h&&bn&&Ar.alternate===null&&y(bt,bn),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar,bn=yr}if(Zn===kt.length)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;ZnZn?(yr=bn,bn=null):yr=bn.sibling;var lh=Ct(bt,bn,Ar.value,Ot);if(lh===null){bn===null&&(bn=yr);break}h&&bn&&lh.alternate===null&&y(bt,bn),ut=Z(lh,ut,Zn),Tr===null?Cn=lh:Tr.sibling=lh,Tr=lh,bn=yr}if(Ar.done)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;!Ar.done;Zn++,Ar=kt.next())Ar=zt(bt,Ar.value,Ot),Ar!==null&&(ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return wr&&lu(bt,Zn),Cn}for(bn=M(bn);!Ar.done;Zn++,Ar=kt.next())Ar=Et(bn,bt,Zn,Ar.value,Ot),Ar!==null&&(h&&Ar.alternate!==null&&bn.delete(Ar.key===null?Zn:Ar.key),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return h&&bn.forEach(function(Dde){return y(bt,Dde)}),wr&&lu(bt,Zn),Cn}function Wr(bt,ut,kt,Ot){if(typeof kt=="object"&&kt!==null&&kt.type===v&&kt.key===null&&(kt=kt.props.children),typeof kt=="object"&&kt!==null){switch(kt.$$typeof){case f:e:{for(var Cn=kt.key;ut!==null;){if(ut.key===Cn){if(Cn=kt.type,Cn===v){if(ut.tag===7){S(bt,ut.sibling),Ot=$(ut,kt.props.children),Ot.return=bt,bt=Ot;break e}}else if(ut.elementType===Cn||typeof Cn=="object"&&Cn!==null&&Cn.$$typeof===F&&Yp(Cn)===ut.type){S(bt,ut.sibling),Ot=$(ut,kt.props),Qy(Ot,kt),Ot.return=bt,bt=Ot;break e}S(bt,ut);break}else y(bt,ut);ut=ut.sibling}kt.type===v?(Ot=Vp(kt.props.children,bt.mode,Ot,kt.key),Ot.return=bt,bt=Ot):(Ot=GS(kt.type,kt.key,kt.props,null,bt.mode,Ot),Qy(Ot,kt),Ot.return=bt,bt=Ot)}return Ne(bt);case x:e:{for(Cn=kt.key;ut!==null;){if(ut.key===Cn)if(ut.tag===4&&ut.stateNode.containerInfo===kt.containerInfo&&ut.stateNode.implementation===kt.implementation){S(bt,ut.sibling),Ot=$(ut,kt.children||[]),Ot.return=bt,bt=Ot;break e}else{S(bt,ut);break}else y(bt,ut);ut=ut.sibling}Ot=jA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot}return Ne(bt);case F:return kt=Yp(kt),Wr(bt,ut,kt,Ot)}if(te(kt))return mn(bt,ut,kt,Ot);if(z(kt)){if(Cn=z(kt),typeof Cn!="function")throw Error(r(150));return kt=Cn.call(kt),Fn(bt,ut,kt,Ot)}if(typeof kt.then=="function")return Wr(bt,ut,JS(kt),Ot);if(kt.$$typeof===C)return Wr(bt,ut,XS(bt,kt),Ot);e_(bt,kt)}return typeof kt=="string"&&kt!==""||typeof kt=="number"||typeof kt=="bigint"?(kt=""+kt,ut!==null&&ut.tag===6?(S(bt,ut.sibling),Ot=$(ut,kt),Ot.return=bt,bt=Ot):(S(bt,ut),Ot=AA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot),Ne(bt)):S(bt,ut)}return function(bt,ut,kt,Ot){try{Yy=0;var Cn=Wr(bt,ut,kt,Ot);return rb=null,Cn}catch(bn){if(bn===nb||bn===QS)throw bn;var Tr=Yo(29,bn,null,bt.mode);return Tr.lanes=Ot,Tr.return=bt,Tr}}}var Zp=H5(!0),q5=H5(!1),Vm=!1;function HA(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function qA(h,y){h=h.updateQueue,y.updateQueue===h&&(y.updateQueue={baseState:h.baseState,firstBaseUpdate:h.firstBaseUpdate,lastBaseUpdate:h.lastBaseUpdate,shared:h.shared,callbacks:null})}function Gm(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function Wm(h,y,S){var M=h.updateQueue;if(M===null)return null;if(M=M.shared,(Fr&2)!==0){var $=M.pending;return $===null?y.next=y:(y.next=$.next,$.next=y),M.pending=y,y=VS(h),C5(h,null,S),y}return $S(h,M,y,S),VS(h)}function Zy(h,y,S){if(y=y.updateQueue,y!==null&&(y=y.shared,(S&4194048)!==0)){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}function $A(h,y){var S=h.updateQueue,M=h.alternate;if(M!==null&&(M=M.updateQueue,S===M)){var $=null,Z=null;if(S=S.firstBaseUpdate,S!==null){do{var Ne={lane:S.lane,tag:S.tag,payload:S.payload,callback:null,next:null};Z===null?$=Z=Ne:Z=Z.next=Ne,S=S.next}while(S!==null);Z===null?$=Z=y:Z=Z.next=y}else $=Z=y;S={baseState:M.baseState,firstBaseUpdate:$,lastBaseUpdate:Z,shared:M.shared,callbacks:M.callbacks},h.updateQueue=S;return}h=S.lastBaseUpdate,h===null?S.firstBaseUpdate=y:h.next=y,S.lastBaseUpdate=y}var VA=!1;function Jy(){if(VA){var h=tb;if(h!==null)throw h}}function ev(h,y,S,M){VA=!1;var $=h.updateQueue;Vm=!1;var Z=$.firstBaseUpdate,Ne=$.lastBaseUpdate,He=$.shared.pending;if(He!==null){$.shared.pending=null;var nt=He,Nt=nt.next;nt.next=null,Ne===null?Z=Nt:Ne.next=Nt,Ne=nt;var Lt=h.alternate;Lt!==null&&(Lt=Lt.updateQueue,He=Lt.lastBaseUpdate,He!==Ne&&(He===null?Lt.firstBaseUpdate=Nt:He.next=Nt,Lt.lastBaseUpdate=nt))}if(Z!==null){var zt=$.baseState;Ne=0,Lt=Nt=nt=null,He=Z;do{var Ct=He.lane&-536870913,Et=Ct!==He.lane;if(Et?(xr&Ct)===Ct:(M&Ct)===Ct){Ct!==0&&Ct===eb&&(VA=!0),Lt!==null&&(Lt=Lt.next={lane:0,tag:He.tag,payload:He.payload,callback:null,next:null});e:{var mn=h,Fn=He;Ct=y;var Wr=S;switch(Fn.tag){case 1:if(mn=Fn.payload,typeof mn=="function"){zt=mn.call(Wr,zt,Ct);break e}zt=mn;break e;case 3:mn.flags=mn.flags&-65537|128;case 0:if(mn=Fn.payload,Ct=typeof mn=="function"?mn.call(Wr,zt,Ct):mn,Ct==null)break e;zt=m({},zt,Ct);break e;case 2:Vm=!0}}Ct=He.callback,Ct!==null&&(h.flags|=64,Et&&(h.flags|=8192),Et=$.callbacks,Et===null?$.callbacks=[Ct]:Et.push(Ct))}else Et={lane:Ct,tag:He.tag,payload:He.payload,callback:He.callback,next:null},Lt===null?(Nt=Lt=Et,nt=zt):Lt=Lt.next=Et,Ne|=Ct;if(He=He.next,He===null){if(He=$.shared.pending,He===null)break;Et=He,He=Et.next,Et.next=null,$.lastBaseUpdate=Et,$.shared.pending=null}}while(!0);Lt===null&&(nt=zt),$.baseState=nt,$.firstBaseUpdate=Nt,$.lastBaseUpdate=Lt,Z===null&&($.shared.lanes=0),Zm|=Ne,h.lanes=Ne,h.memoizedState=zt}}function $5(h,y){if(typeof h!="function")throw Error(r(191,h));h.call(y)}function V5(h,y){var S=h.callbacks;if(S!==null)for(h.callbacks=null,h=0;hZ?Z:8;var Ne=ae.T,He={};ae.T=He,dj(h,!1,y,S);try{var nt=$(),Nt=ae.S;if(Nt!==null&&Nt(He,nt),nt!==null&&typeof nt=="object"&&typeof nt.then=="function"){var Lt=Sce(nt,M);rv(h,y,Lt,tl(h))}else rv(h,y,M,tl(h))}catch(zt){rv(h,y,{then:function(){},status:"rejected",reason:zt},tl())}finally{J.p=Z,Ne!==null&&He.types!==null&&(Ne.types=He.types),ae.T=Ne}}function Tce(){}function lj(h,y,S,M){if(h.tag!==5)throw Error(r(476));var $=_U(h).queue;SU(h,$,y,le,S===null?Tce:function(){return kU(h),S(M)})}function _U(h){var y=h.memoizedState;if(y!==null)return y;y={memoizedState:le,baseState:le,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:le},next:null};var S={};return y.next={memoizedState:S,baseState:S,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:S},next:null},h.memoizedState=y,h=h.alternate,h!==null&&(h.memoizedState=y),y}function kU(h){var y=_U(h);y.next===null&&(y=h.alternate.memoizedState),rv(h,y.next.queue,{},tl())}function cj(){return as(vv)}function NU(){return ai().memoizedState}function CU(){return ai().memoizedState}function Ace(h){for(var y=h.return;y!==null;){switch(y.tag){case 24:case 3:var S=tl();h=Gm(S);var M=Wm(y,h,S);M!==null&&(Co(M,y,S),Zy(M,y,S)),y={cache:IA()},h.payload=y;return}y=y.return}}function jce(h,y,S){var M=tl();S={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null},d_(h)?TU(y,S):(S=PA(h,y,S,M),S!==null&&(Co(S,h,M),AU(S,y,M)))}function PU(h,y,S){var M=tl();rv(h,y,S,M)}function rv(h,y,S,M){var $={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null};if(d_(h))TU(y,$);else{var Z=h.alternate;if(h.lanes===0&&(Z===null||Z.lanes===0)&&(Z=y.lastRenderedReducer,Z!==null))try{var Ne=y.lastRenderedState,He=Z(Ne,S);if($.hasEagerState=!0,$.eagerState=He,js(He,Ne))return $S(h,y,$,0),oa===null&&qS(),!1}catch{}if(S=PA(h,y,$,M),S!==null)return Co(S,h,M),AU(S,y,M),!0}return!1}function dj(h,y,S,M){if(M={lane:2,revertLane:Hj(),gesture:null,action:M,hasEagerState:!1,eagerState:null,next:null},d_(h)){if(y)throw Error(r(479))}else y=PA(h,S,M,2),y!==null&&Co(y,h,2)}function d_(h){var y=h.alternate;return h===Yn||y!==null&&y===Yn}function TU(h,y){ib=r_=!0;var S=h.pending;S===null?y.next=y:(y.next=S.next,S.next=y),h.pending=y}function AU(h,y,S){if((S&4194048)!==0){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}var av={readContext:as,use:s_,useCallback:Ba,useContext:Ba,useEffect:Ba,useImperativeHandle:Ba,useLayoutEffect:Ba,useInsertionEffect:Ba,useMemo:Ba,useReducer:Ba,useRef:Ba,useState:Ba,useDebugValue:Ba,useDeferredValue:Ba,useTransition:Ba,useSyncExternalStore:Ba,useId:Ba,useHostTransitionStatus:Ba,useFormState:Ba,useActionState:Ba,useOptimistic:Ba,useMemoCache:Ba,useCacheRefresh:Ba};av.useEffectEvent=Ba;var jU={readContext:as,use:s_,useCallback:function(h,y){return Qs().memoizedState=[h,y===void 0?null:y],h},useContext:as,useEffect:hU,useImperativeHandle:function(h,y,S){S=S!=null?S.concat([h]):null,l_(4194308,4,bU.bind(null,y,h),S)},useLayoutEffect:function(h,y){return l_(4194308,4,h,y)},useInsertionEffect:function(h,y){l_(4,2,h,y)},useMemo:function(h,y){var S=Qs();y=y===void 0?null:y;var M=h();if(Jp){Oe(!0);try{h()}finally{Oe(!1)}}return S.memoizedState=[M,y],M},useReducer:function(h,y,S){var M=Qs();if(S!==void 0){var $=S(y);if(Jp){Oe(!0);try{S(y)}finally{Oe(!1)}}}else $=y;return M.memoizedState=M.baseState=$,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:$},M.queue=h,h=h.dispatch=jce.bind(null,Yn,h),[M.memoizedState,h]},useRef:function(h){var y=Qs();return h={current:h},y.memoizedState=h},useState:function(h){h=rj(h);var y=h.queue,S=PU.bind(null,Yn,y);return y.dispatch=S,[h.memoizedState,S]},useDebugValue:sj,useDeferredValue:function(h,y){var S=Qs();return oj(S,h,y)},useTransition:function(){var h=rj(!1);return h=SU.bind(null,Yn,h.queue,!0,!1),Qs().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,y,S){var M=Yn,$=Qs();if(wr){if(S===void 0)throw Error(r(407));S=S()}else{if(S=y(),oa===null)throw Error(r(349));(xr&127)!==0||Q5(M,y,S)}$.memoizedState=S;var Z={value:S,getSnapshot:y};return $.queue=Z,hU(J5.bind(null,M,Z,h),[h]),M.flags|=2048,ob(9,{destroy:void 0},Z5.bind(null,M,Z,S,y),null),S},useId:function(){var h=Qs(),y=oa.identifierPrefix;if(wr){var S=hd,M=md;S=(M&~(1<<32-qe(M)-1)).toString(32)+S,y="_"+y+"R_"+S,S=a_++,0<\/script>",Z=Z.removeChild(Z.firstChild);break;case"select":Z=typeof M.is=="string"?Ne.createElement("select",{is:M.is}):Ne.createElement("select"),M.multiple?Z.multiple=!0:M.size&&(Z.size=M.size);break;default:Z=typeof M.is=="string"?Ne.createElement($,{is:M.is}):Ne.createElement($)}}Z[at]=y,Z[dt]=M;e:for(Ne=y.child;Ne!==null;){if(Ne.tag===5||Ne.tag===6)Z.appendChild(Ne.stateNode);else if(Ne.tag!==4&&Ne.tag!==27&&Ne.child!==null){Ne.child.return=Ne,Ne=Ne.child;continue}if(Ne===y)break e;for(;Ne.sibling===null;){if(Ne.return===null||Ne.return===y)break e;Ne=Ne.return}Ne.sibling.return=Ne.return,Ne=Ne.sibling}y.stateNode=Z;e:switch(ss(Z,$,M),$){case"button":case"input":case"select":case"textarea":M=!!M.autoFocus;break e;case"img":M=!0;break e;default:M=!1}M&&pu(y)}}return va(y),kj(y,y.type,h===null?null:h.memoizedProps,y.pendingProps,S),null;case 6:if(h&&y.stateNode!=null)h.memoizedProps!==M&&pu(y);else{if(typeof M!="string"&&y.stateNode===null)throw Error(r(166));if(h=q.current,Zg(y)){if(h=y.stateNode,S=y.memoizedProps,M=null,$=rs,$!==null)switch($.tag){case 27:case 5:M=$.memoizedProps}h[at]=y,h=!!(h.nodeValue===S||M!==null&&M.suppressHydrationWarning===!0||XB(h.nodeValue,S)),h||qm(y,!0)}else h=j_(h).createTextNode(M),h[at]=y,y.stateNode=h}return va(y),null;case 31:if(S=y.memoizedState,h===null||h.memoizedState!==null){if(M=Zg(y),S!==null){if(h===null){if(!M)throw Error(r(318));if(h=y.memoizedState,h=h!==null?h.dehydrated:null,!h)throw Error(r(557));h[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),h=!1}else S=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=S),h=!0;if(!h)return y.flags&256?(Zo(y),y):(Zo(y),null);if((y.flags&128)!==0)throw Error(r(558))}return va(y),null;case 13:if(M=y.memoizedState,h===null||h.memoizedState!==null&&h.memoizedState.dehydrated!==null){if($=Zg(y),M!==null&&M.dehydrated!==null){if(h===null){if(!$)throw Error(r(318));if($=y.memoizedState,$=$!==null?$.dehydrated:null,!$)throw Error(r(317));$[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),$=!1}else $=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=$),$=!0;if(!$)return y.flags&256?(Zo(y),y):(Zo(y),null)}return Zo(y),(y.flags&128)!==0?(y.lanes=S,y):(S=M!==null,h=h!==null&&h.memoizedState!==null,S&&(M=y.child,$=null,M.alternate!==null&&M.alternate.memoizedState!==null&&M.alternate.memoizedState.cachePool!==null&&($=M.alternate.memoizedState.cachePool.pool),Z=null,M.memoizedState!==null&&M.memoizedState.cachePool!==null&&(Z=M.memoizedState.cachePool.pool),Z!==$&&(M.flags|=2048)),S!==h&&S&&(y.child.flags|=8192),f_(y,y.updateQueue),va(y),null);case 4:return j(),h===null&&Gj(y.stateNode.containerInfo),va(y),null;case 10:return du(y.type),va(y),null;case 19:if(ne(ri),M=y.memoizedState,M===null)return va(y),null;if($=(y.flags&128)!==0,Z=M.rendering,Z===null)if($)sv(M,!1);else{if(Ha!==0||h!==null&&(h.flags&128)!==0)for(h=y.child;h!==null;){if(Z=n_(h),Z!==null){for(y.flags|=128,sv(M,!1),h=Z.updateQueue,y.updateQueue=h,f_(y,h),y.subtreeFlags=0,h=S,S=y.child;S!==null;)P5(S,h),S=S.sibling;return fe(ri,ri.current&1|2),wr&&lu(y,M.treeForkCount),y.child}h=h.sibling}M.tail!==null&&R()>v_&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304)}else{if(!$)if(h=n_(Z),h!==null){if(y.flags|=128,$=!0,h=h.updateQueue,y.updateQueue=h,f_(y,h),sv(M,!0),M.tail===null&&M.tailMode==="hidden"&&!Z.alternate&&!wr)return va(y),null}else 2*R()-M.renderingStartTime>v_&&S!==536870912&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304);M.isBackwards?(Z.sibling=y.child,y.child=Z):(h=M.last,h!==null?h.sibling=Z:y.child=Z,M.last=Z)}return M.tail!==null?(h=M.tail,M.rendering=h,M.tail=h.sibling,M.renderingStartTime=R(),h.sibling=null,S=ri.current,fe(ri,$?S&1|2:S&1),wr&&lu(y,M.treeForkCount),h):(va(y),null);case 22:case 23:return Zo(y),WA(),M=y.memoizedState!==null,h!==null?h.memoizedState!==null!==M&&(y.flags|=8192):M&&(y.flags|=8192),M?(S&536870912)!==0&&(y.flags&128)===0&&(va(y),y.subtreeFlags&6&&(y.flags|=8192)):va(y),S=y.updateQueue,S!==null&&f_(y,S.retryQueue),S=null,h!==null&&h.memoizedState!==null&&h.memoizedState.cachePool!==null&&(S=h.memoizedState.cachePool.pool),M=null,y.memoizedState!==null&&y.memoizedState.cachePool!==null&&(M=y.memoizedState.cachePool.pool),M!==S&&(y.flags|=2048),h!==null&&ne(Xp),null;case 24:return S=null,h!==null&&(S=h.memoizedState.cache),y.memoizedState.cache!==S&&(y.flags|=2048),du(ui),va(y),null;case 25:return null;case 30:return null}throw Error(r(156,y.tag))}function Rce(h,y){switch(EA(y),y.tag){case 1:return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 3:return du(ui),j(),h=y.flags,(h&65536)!==0&&(h&128)===0?(y.flags=h&-65537|128,y):null;case 26:case 27:case 5:return K(y),null;case 31:if(y.memoizedState!==null){if(Zo(y),y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 13:if(Zo(y),h=y.memoizedState,h!==null&&h.dehydrated!==null){if(y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 19:return ne(ri),null;case 4:return j(),null;case 10:return du(y.type),null;case 22:case 23:return Zo(y),WA(),h!==null&&ne(Xp),h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 24:return du(ui),null;case 25:return null;default:return null}}function eB(h,y){switch(EA(y),y.tag){case 3:du(ui),j();break;case 26:case 27:case 5:K(y);break;case 4:j();break;case 31:y.memoizedState!==null&&Zo(y);break;case 13:Zo(y);break;case 19:ne(ri);break;case 10:du(y.type);break;case 22:case 23:Zo(y),WA(),h!==null&&ne(Xp);break;case 24:du(ui)}}function ov(h,y){try{var S=y.updateQueue,M=S!==null?S.lastEffect:null;if(M!==null){var $=M.next;S=$;do{if((S.tag&h)===h){M=void 0;var Z=S.create,Ne=S.inst;M=Z(),Ne.destroy=M}S=S.next}while(S!==$)}}catch(He){Br(y,y.return,He)}}function Ym(h,y,S){try{var M=y.updateQueue,$=M!==null?M.lastEffect:null;if($!==null){var Z=$.next;M=Z;do{if((M.tag&h)===h){var Ne=M.inst,He=Ne.destroy;if(He!==void 0){Ne.destroy=void 0,$=y;var nt=S,Nt=He;try{Nt()}catch(Lt){Br($,nt,Lt)}}}M=M.next}while(M!==Z)}}catch(Lt){Br(y,y.return,Lt)}}function tB(h){var y=h.updateQueue;if(y!==null){var S=h.stateNode;try{V5(y,S)}catch(M){Br(h,h.return,M)}}}function nB(h,y,S){S.props=ef(h.type,h.memoizedProps),S.state=h.memoizedState;try{S.componentWillUnmount()}catch(M){Br(h,y,M)}}function lv(h,y){try{var S=h.ref;if(S!==null){switch(h.tag){case 26:case 27:case 5:var M=h.stateNode;break;case 30:M=h.stateNode;break;default:M=h.stateNode}typeof S=="function"?h.refCleanup=S(M):S.current=M}}catch($){Br(h,y,$)}}function pd(h,y){var S=h.ref,M=h.refCleanup;if(S!==null)if(typeof M=="function")try{M()}catch($){Br(h,y,$)}finally{h.refCleanup=null,h=h.alternate,h!=null&&(h.refCleanup=null)}else if(typeof S=="function")try{S(null)}catch($){Br(h,y,$)}else S.current=null}function rB(h){var y=h.type,S=h.memoizedProps,M=h.stateNode;try{e:switch(y){case"button":case"input":case"select":case"textarea":S.autoFocus&&M.focus();break e;case"img":S.src?M.src=S.src:S.srcSet&&(M.srcset=S.srcSet)}}catch($){Br(h,h.return,$)}}function Nj(h,y,S){try{var M=h.stateNode;rde(M,h.type,S,y),M[dt]=y}catch($){Br(h,h.return,$)}}function aB(h){return h.tag===5||h.tag===3||h.tag===26||h.tag===27&&rh(h.type)||h.tag===4}function Cj(h){e:for(;;){for(;h.sibling===null;){if(h.return===null||aB(h.return))return null;h=h.return}for(h.sibling.return=h.return,h=h.sibling;h.tag!==5&&h.tag!==6&&h.tag!==18;){if(h.tag===27&&rh(h.type)||h.flags&2||h.child===null||h.tag===4)continue e;h.child.return=h,h=h.child}if(!(h.flags&2))return h.stateNode}}function Pj(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?(S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S).insertBefore(h,y):(y=S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S,y.appendChild(h),S=S._reactRootContainer,S!=null||y.onclick!==null||(y.onclick=qt));else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode,y=null),h=h.child,h!==null))for(Pj(h,y,S),h=h.sibling;h!==null;)Pj(h,y,S),h=h.sibling}function g_(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?S.insertBefore(h,y):S.appendChild(h);else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode),h=h.child,h!==null))for(g_(h,y,S),h=h.sibling;h!==null;)g_(h,y,S),h=h.sibling}function iB(h){var y=h.stateNode,S=h.memoizedProps;try{for(var M=h.type,$=y.attributes;$.length;)y.removeAttributeNode($[0]);ss(y,M,S),y[at]=h,y[dt]=S}catch(Z){Br(h,h.return,Z)}}var fu=!1,pi=!1,Tj=!1,sB=typeof WeakSet=="function"?WeakSet:Set,Hi=null;function Lce(h,y){if(h=h.containerInfo,Xj=O_,h=x5(h),wA(h)){if("selectionStart"in h)var S={start:h.selectionStart,end:h.selectionEnd};else e:{S=(S=h.ownerDocument)&&S.defaultView||window;var M=S.getSelection&&S.getSelection();if(M&&M.rangeCount!==0){S=M.anchorNode;var $=M.anchorOffset,Z=M.focusNode;M=M.focusOffset;try{S.nodeType,Z.nodeType}catch{S=null;break e}var Ne=0,He=-1,nt=-1,Nt=0,Lt=0,zt=h,Ct=null;t:for(;;){for(var Et;zt!==S||$!==0&&zt.nodeType!==3||(He=Ne+$),zt!==Z||M!==0&&zt.nodeType!==3||(nt=Ne+M),zt.nodeType===3&&(Ne+=zt.nodeValue.length),(Et=zt.firstChild)!==null;)Ct=zt,zt=Et;for(;;){if(zt===h)break t;if(Ct===S&&++Nt===$&&(He=Ne),Ct===Z&&++Lt===M&&(nt=Ne),(Et=zt.nextSibling)!==null)break;zt=Ct,Ct=zt.parentNode}zt=Et}S=He===-1||nt===-1?null:{start:He,end:nt}}else S=null}S=S||{start:0,end:0}}else S=null;for(Yj={focusedElem:h,selectionRange:S},O_=!1,Hi=y;Hi!==null;)if(y=Hi,h=y.child,(y.subtreeFlags&1028)!==0&&h!==null)h.return=y,Hi=h;else for(;Hi!==null;){switch(y=Hi,Z=y.alternate,h=y.flags,y.tag){case 0:if((h&4)!==0&&(h=y.updateQueue,h=h!==null?h.events:null,h!==null))for(S=0;S title"))),ss(Z,M,S),Z[at]=h,Ke(Z),M=Z;break e;case"link":var Ne=m8("link","href",$).get(M+(S.href||""));if(Ne){for(var He=0;HeWr&&(Ne=Wr,Wr=Fn,Fn=Ne);var bt=g5(He,Fn),ut=g5(He,Wr);if(bt&&ut&&(Et.rangeCount!==1||Et.anchorNode!==bt.node||Et.anchorOffset!==bt.offset||Et.focusNode!==ut.node||Et.focusOffset!==ut.offset)){var kt=zt.createRange();kt.setStart(bt.node,bt.offset),Et.removeAllRanges(),Fn>Wr?(Et.addRange(kt),Et.extend(ut.node,ut.offset)):(kt.setEnd(ut.node,ut.offset),Et.addRange(kt))}}}}for(zt=[],Et=He;Et=Et.parentNode;)Et.nodeType===1&&zt.push({element:Et,left:Et.scrollLeft,top:Et.scrollTop});for(typeof He.focus=="function"&&He.focus(),He=0;HeS?32:S,ae.T=null,S=Rj,Rj=null;var Z=eh,Ne=vu;if(Ti=0,mb=eh=null,vu=0,(Fr&6)!==0)throw Error(r(331));var He=Fr;if(Fr|=4,bB(Z.current),pB(Z,Z.current,Ne,S),Fr=He,pv(0,!1),Le&&typeof Le.onPostCommitFiberRoot=="function")try{Le.onPostCommitFiberRoot(Me,Z)}catch{}return!0}finally{J.p=$,ae.T=M,RB(h,y)}}function OB(h,y,S){y=Al(S,y),y=pj(h.stateNode,y,2),h=Wm(h,y,2),h!==null&&(xt(h,2),fd(h))}function Br(h,y,S){if(h.tag===3)OB(h,h,S);else for(;y!==null;){if(y.tag===3){OB(y,h,S);break}else if(y.tag===1){var M=y.stateNode;if(typeof y.type.getDerivedStateFromError=="function"||typeof M.componentDidCatch=="function"&&(Jm===null||!Jm.has(M))){h=Al(S,h),S=IU(2),M=Wm(y,S,2),M!==null&&(zU(S,M,y,h),xt(M,2),fd(M));break}}y=y.return}}function zj(h,y,S){var M=h.pingCache;if(M===null){M=h.pingCache=new zce;var $=new Set;M.set(y,$)}else $=M.get(y),$===void 0&&($=new Set,M.set(y,$));$.has(S)||(Mj=!0,$.add(S),h=$ce.bind(null,h,y,S),y.then(h,h))}function $ce(h,y,S){var M=h.pingCache;M!==null&&M.delete(y),h.pingedLanes|=h.suspendedLanes&S,h.warmLanes&=~S,oa===h&&(xr&S)===S&&(Ha===4||Ha===3&&(xr&62914560)===xr&&300>R()-y_?(Fr&2)===0&&hb(h,0):Ej|=S,ub===xr&&(ub=0)),fd(h)}function IB(h,y){y===0&&(y=Ze()),h=$p(h,y),h!==null&&(xt(h,y),fd(h))}function Vce(h){var y=h.memoizedState,S=0;y!==null&&(S=y.retryLane),IB(h,S)}function Gce(h,y){var S=0;switch(h.tag){case 31:case 13:var M=h.stateNode,$=h.memoizedState;$!==null&&(S=$.retryLane);break;case 19:M=h.stateNode;break;case 22:M=h.stateNode._retryCache;break;default:throw Error(r(314))}M!==null&&M.delete(y),IB(h,S)}function Wce(h,y){return ge(h,y)}var C_=null,fb=null,Uj=!1,P_=!1,Bj=!1,nh=0;function fd(h){h!==fb&&h.next===null&&(fb===null?C_=fb=h:fb=fb.next=h),P_=!0,Uj||(Uj=!0,Xce())}function pv(h,y){if(!Bj&&P_){Bj=!0;do for(var S=!1,M=C_;M!==null;){if(h!==0){var $=M.pendingLanes;if($===0)var Z=0;else{var Ne=M.suspendedLanes,He=M.pingedLanes;Z=(1<<31-qe(42|h)+1)-1,Z&=$&~(Ne&~He),Z=Z&201326741?Z&201326741|1:Z?Z|2:0}Z!==0&&(S=!0,HB(M,Z))}else Z=xr,Z=de(M,M===oa?Z:0,M.cancelPendingCommit!==null||M.timeoutHandle!==-1),(Z&3)===0||xe(M,Z)||(S=!0,HB(M,Z));M=M.next}while(S);Bj=!1}}function Kce(){zB()}function zB(){P_=Uj=!1;var h=0;nh!==0&&ide()&&(h=nh);for(var y=R(),S=null,M=C_;M!==null;){var $=M.next,Z=UB(M,y);Z===0?(M.next=null,S===null?C_=$:S.next=$,$===null&&(fb=S)):(S=M,(h!==0||(Z&3)!==0)&&(P_=!0)),M=$}Ti!==0&&Ti!==5||pv(h),nh!==0&&(nh=0)}function UB(h,y){for(var S=h.suspendedLanes,M=h.pingedLanes,$=h.expirationTimes,Z=h.pendingLanes&-62914561;0He)break;var Lt=nt.transferSize,zt=nt.initiatorType;Lt&&YB(zt)&&(nt=nt.responseEnd,Ne+=Lt*(nt"u"?null:document;function l8(h,y,S){var M=gb;if(M&&typeof y=="string"&&y){var $=En(y);$='link[rel="'+h+'"][href="'+$+'"]',typeof S=="string"&&($+='[crossorigin="'+S+'"]'),o8.has($)||(o8.add($),h={rel:h,crossOrigin:S,href:y},M.querySelector($)===null&&(y=M.createElement("link"),ss(y,"link",h),Ke(y),M.head.appendChild(y)))}}function pde(h){wu.D(h),l8("dns-prefetch",h,null)}function fde(h,y){wu.C(h,y),l8("preconnect",h,y)}function gde(h,y,S){wu.L(h,y,S);var M=gb;if(M&&h&&y){var $='link[rel="preload"][as="'+En(y)+'"]';y==="image"&&S&&S.imageSrcSet?($+='[imagesrcset="'+En(S.imageSrcSet)+'"]',typeof S.imageSizes=="string"&&($+='[imagesizes="'+En(S.imageSizes)+'"]')):$+='[href="'+En(h)+'"]';var Z=$;switch(y){case"style":Z=bb(h);break;case"script":Z=xb(h)}Rl.has(Z)||(h=m({rel:"preload",href:y==="image"&&S&&S.imageSrcSet?void 0:h,as:y},S),Rl.set(Z,h),M.querySelector($)!==null||y==="style"&&M.querySelector(xv(Z))||y==="script"&&M.querySelector(yv(Z))||(y=M.createElement("link"),ss(y,"link",h),Ke(y),M.head.appendChild(y)))}}function bde(h,y){wu.m(h,y);var S=gb;if(S&&h){var M=y&&typeof y.as=="string"?y.as:"script",$='link[rel="modulepreload"][as="'+En(M)+'"][href="'+En(h)+'"]',Z=$;switch(M){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":Z=xb(h)}if(!Rl.has(Z)&&(h=m({rel:"modulepreload",href:h},y),Rl.set(Z,h),S.querySelector($)===null)){switch(M){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(S.querySelector(yv(Z)))return}M=S.createElement("link"),ss(M,"link",h),Ke(M),S.head.appendChild(M)}}}function xde(h,y,S){wu.S(h,y,S);var M=gb;if(M&&h){var $=et(M).hoistableStyles,Z=bb(h);y=y||"default";var Ne=$.get(Z);if(!Ne){var He={loading:0,preload:null};if(Ne=M.querySelector(xv(Z)))He.loading=5;else{h=m({rel:"stylesheet",href:h,"data-precedence":y},S),(S=Rl.get(Z))&&rM(h,S);var nt=Ne=M.createElement("link");Ke(nt),ss(nt,"link",h),nt._p=new Promise(function(Nt,Lt){nt.onload=Nt,nt.onerror=Lt}),nt.addEventListener("load",function(){He.loading|=1}),nt.addEventListener("error",function(){He.loading|=2}),He.loading|=4,E_(Ne,y,M)}Ne={type:"stylesheet",instance:Ne,count:1,state:He},$.set(Z,Ne)}}}function yde(h,y){wu.X(h,y);var S=gb;if(S&&h){var M=et(S).hoistableScripts,$=xb(h),Z=M.get($);Z||(Z=S.querySelector(yv($)),Z||(h=m({src:h,async:!0},y),(y=Rl.get($))&&aM(h,y),Z=S.createElement("script"),Ke(Z),ss(Z,"link",h),S.head.appendChild(Z)),Z={type:"script",instance:Z,count:1,state:null},M.set($,Z))}}function vde(h,y){wu.M(h,y);var S=gb;if(S&&h){var M=et(S).hoistableScripts,$=xb(h),Z=M.get($);Z||(Z=S.querySelector(yv($)),Z||(h=m({src:h,async:!0,type:"module"},y),(y=Rl.get($))&&aM(h,y),Z=S.createElement("script"),Ke(Z),ss(Z,"link",h),S.head.appendChild(Z)),Z={type:"script",instance:Z,count:1,state:null},M.set($,Z))}}function c8(h,y,S,M){var $=($=q.current)?M_($):null;if(!$)throw Error(r(446));switch(h){case"meta":case"title":return null;case"style":return typeof S.precedence=="string"&&typeof S.href=="string"?(y=bb(S.href),S=et($).hoistableStyles,M=S.get(y),M||(M={type:"style",instance:null,count:0,state:null},S.set(y,M)),M):{type:"void",instance:null,count:0,state:null};case"link":if(S.rel==="stylesheet"&&typeof S.href=="string"&&typeof S.precedence=="string"){h=bb(S.href);var Z=et($).hoistableStyles,Ne=Z.get(h);if(Ne||($=$.ownerDocument||$,Ne={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},Z.set(h,Ne),(Z=$.querySelector(xv(h)))&&!Z._p&&(Ne.instance=Z,Ne.state.loading=5),Rl.has(h)||(S={rel:"preload",as:"style",href:S.href,crossOrigin:S.crossOrigin,integrity:S.integrity,media:S.media,hrefLang:S.hrefLang,referrerPolicy:S.referrerPolicy},Rl.set(h,S),Z||wde($,h,S,Ne.state))),y&&M===null)throw Error(r(528,""));return Ne}if(y&&M!==null)throw Error(r(529,""));return null;case"script":return y=S.async,S=S.src,typeof S=="string"&&y&&typeof y!="function"&&typeof y!="symbol"?(y=xb(S),S=et($).hoistableScripts,M=S.get(y),M||(M={type:"script",instance:null,count:0,state:null},S.set(y,M)),M):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,h))}}function bb(h){return'href="'+En(h)+'"'}function xv(h){return'link[rel="stylesheet"]['+h+"]"}function d8(h){return m({},h,{"data-precedence":h.precedence,precedence:null})}function wde(h,y,S,M){h.querySelector('link[rel="preload"][as="style"]['+y+"]")?M.loading=1:(y=h.createElement("link"),M.preload=y,y.addEventListener("load",function(){return M.loading|=1}),y.addEventListener("error",function(){return M.loading|=2}),ss(y,"link",S),Ke(y),h.head.appendChild(y))}function xb(h){return'[src="'+En(h)+'"]'}function yv(h){return"script[async]"+h}function u8(h,y,S){if(y.count++,y.instance===null)switch(y.type){case"style":var M=h.querySelector('style[data-href~="'+En(S.href)+'"]');if(M)return y.instance=M,Ke(M),M;var $=m({},S,{"data-href":S.href,"data-precedence":S.precedence,href:null,precedence:null});return M=(h.ownerDocument||h).createElement("style"),Ke(M),ss(M,"style",$),E_(M,S.precedence,h),y.instance=M;case"stylesheet":$=bb(S.href);var Z=h.querySelector(xv($));if(Z)return y.state.loading|=4,y.instance=Z,Ke(Z),Z;M=d8(S),($=Rl.get($))&&rM(M,$),Z=(h.ownerDocument||h).createElement("link"),Ke(Z);var Ne=Z;return Ne._p=new Promise(function(He,nt){Ne.onload=He,Ne.onerror=nt}),ss(Z,"link",M),y.state.loading|=4,E_(Z,S.precedence,h),y.instance=Z;case"script":return Z=xb(S.src),($=h.querySelector(yv(Z)))?(y.instance=$,Ke($),$):(M=S,($=Rl.get(Z))&&(M=m({},S),aM(M,$)),h=h.ownerDocument||h,$=h.createElement("script"),Ke($),ss($,"link",M),h.head.appendChild($),y.instance=$);case"void":return null;default:throw Error(r(443,y.type))}else y.type==="stylesheet"&&(y.state.loading&4)===0&&(M=y.instance,y.state.loading|=4,E_(M,S.precedence,h));return y.instance}function E_(h,y,S){for(var M=S.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),$=M.length?M[M.length-1]:null,Z=$,Ne=0;Ne title"):null)}function Sde(h,y,S){if(S===1||y.itemProp!=null)return!1;switch(h){case"meta":case"title":return!0;case"style":if(typeof y.precedence!="string"||typeof y.href!="string"||y.href==="")break;return!0;case"link":if(typeof y.rel!="string"||typeof y.href!="string"||y.href===""||y.onLoad||y.onError)break;return y.rel==="stylesheet"?(h=y.disabled,typeof y.precedence=="string"&&h==null):!0;case"script":if(y.async&&typeof y.async!="function"&&typeof y.async!="symbol"&&!y.onLoad&&!y.onError&&y.src&&typeof y.src=="string")return!0}return!1}function p8(h){return!(h.type==="stylesheet"&&(h.state.loading&3)===0)}function _de(h,y,S,M){if(S.type==="stylesheet"&&(typeof M.media!="string"||matchMedia(M.media).matches!==!1)&&(S.state.loading&4)===0){if(S.instance===null){var $=bb(M.href),Z=y.querySelector(xv($));if(Z){y=Z._p,y!==null&&typeof y=="object"&&typeof y.then=="function"&&(h.count++,h=F_.bind(h),y.then(h,h)),S.state.loading|=4,S.instance=Z,Ke(Z);return}Z=y.ownerDocument||y,M=d8(M),($=Rl.get($))&&rM(M,$),Z=Z.createElement("link"),Ke(Z);var Ne=Z;Ne._p=new Promise(function(He,nt){Ne.onload=He,Ne.onerror=nt}),ss(Z,"link",M),S.instance=Z}h.stylesheets===null&&(h.stylesheets=new Map),h.stylesheets.set(S,y),(y=S.state.preload)&&(S.state.loading&3)===0&&(h.count++,S=F_.bind(h),y.addEventListener("load",S),y.addEventListener("error",S))}}var iM=0;function kde(h,y){return h.stylesheets&&h.count===0&&L_(h,h.stylesheets),0iM?50:800)+y);return h.unsuspend=S,function(){h.unsuspend=null,clearTimeout(M),clearTimeout($)}}:null}function F_(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)L_(this,this.stylesheets);else if(this.unsuspend){var h=this.unsuspend;this.unsuspend=null,h()}}}var R_=null;function L_(h,y){h.stylesheets=null,h.unsuspend!==null&&(h.count++,R_=new Map,y.forEach(Nde,h),R_=null,F_.call(h))}function Nde(h,y){if(!(y.state.loading&4)){var S=R_.get(h);if(S)var M=S.get(null);else{S=new Map,R_.set(h,S);for(var $=h.querySelectorAll("link[data-precedence],style[data-precedence]"),Z=0;Z<$.length;Z++){var Ne=$[Z];(Ne.nodeName==="LINK"||Ne.getAttribute("media")!=="not all")&&(S.set(Ne.dataset.precedence,Ne),M=Ne)}M&&S.set(null,M)}$=y.instance,Ne=$.getAttribute("data-precedence"),Z=S.get(Ne)||M,Z===M&&S.set(null,$),S.set(Ne,$),this.count++,M=F_.bind(this),$.addEventListener("load",M),$.addEventListener("error",M),Z?Z.parentNode.insertBefore($,Z.nextSibling):(h=h.nodeType===9?h.head:h,h.insertBefore($,h.firstChild)),y.state.loading|=4}}var vv={$$typeof:C,Provider:null,Consumer:null,_currentValue:le,_currentValue2:le,_threadCount:0};function Cde(h,y,S,M,$,Z,Ne,He,nt){this.tag=1,this.containerInfo=h,this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.next=this.pendingContext=this.context=this.cancelPendingCommit=null,this.callbackPriority=0,this.expirationTimes=pt(-1),this.entangledLanes=this.shellSuspendCounter=this.errorRecoveryDisabledLanes=this.expiredLanes=this.warmLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=pt(0),this.hiddenUpdates=pt(null),this.identifierPrefix=M,this.onUncaughtError=$,this.onCaughtError=Z,this.onRecoverableError=Ne,this.pooledCache=null,this.pooledCacheLanes=0,this.formState=nt,this.incompleteTransitions=new Map}function f8(h,y,S,M,$,Z,Ne,He,nt,Nt,Lt,zt){return h=new Cde(h,y,S,Ne,nt,Nt,Lt,zt,He),y=1,Z===!0&&(y|=24),Z=Yo(3,null,null,y),h.current=Z,Z.stateNode=h,y=IA(),y.refCount++,h.pooledCache=y,y.refCount++,Z.memoizedState={element:M,isDehydrated:S,cache:y},HA(Z),h}function g8(h){return h?(h=Xg,h):Xg}function b8(h,y,S,M,$,Z){$=g8($),M.context===null?M.context=$:M.pendingContext=$,M=Gm(y),M.payload={element:S},Z=Z===void 0?null:Z,Z!==null&&(M.callback=Z),S=Wm(h,M,y),S!==null&&(Co(S,h,y),Zy(S,h,y))}function x8(h,y){if(h=h.memoizedState,h!==null&&h.dehydrated!==null){var S=h.retryLane;h.retryLane=S!==0&&S"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),pM.exports=Hde(),pM.exports}var $de=qde();const $n=t=>typeof t=="string",Cv=()=>{let t,e;const n=new Promise((r,i)=>{t=r,e=i});return n.resolve=t,n.reject=e,n},I8=t=>t==null?"":""+t,Vde=(t,e,n)=>{t.forEach(r=>{e[r]&&(n[r]=e[r])})},Gde=/###/g,z8=t=>t&&t.indexOf("###")>-1?t.replace(Gde,"."):t,U8=t=>!t||$n(t),_0=(t,e,n)=>{const r=$n(e)?e.split("."):e;let i=0;for(;i{const{obj:r,k:i}=_0(t,e,Object);if(r!==void 0||e.length===1){r[i]=n;return}let s=e[e.length-1],o=e.slice(0,e.length-1),l=_0(t,o,Object);for(;l.obj===void 0&&o.length;)s=`${o[o.length-1]}.${s}`,o=o.slice(0,o.length-1),l=_0(t,o,Object),l?.obj&&typeof l.obj[`${l.k}.${s}`]<"u"&&(l.obj=void 0);l.obj[`${l.k}.${s}`]=n},Wde=(t,e,n,r)=>{const{obj:i,k:s}=_0(t,e,Object);i[s]=i[s]||[],i[s].push(n)},dN=(t,e)=>{const{obj:n,k:r}=_0(t,e);if(n&&Object.prototype.hasOwnProperty.call(n,r))return n[r]},Kde=(t,e,n)=>{const r=dN(t,n);return r!==void 0?r:dN(e,n)},BY=(t,e,n)=>{for(const r in e)r!=="__proto__"&&r!=="constructor"&&(r in t?$n(t[r])||t[r]instanceof String||$n(e[r])||e[r]instanceof String?n&&(t[r]=e[r]):BY(t[r],e[r],n):t[r]=e[r]);return t},vb=t=>t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");var Xde={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};const Yde=t=>$n(t)?t.replace(/[&<>"'\/]/g,e=>Xde[e]):t;class Qde{constructor(e){this.capacity=e,this.regExpMap=new Map,this.regExpQueue=[]}getRegExp(e){const n=this.regExpMap.get(e);if(n!==void 0)return n;const r=new RegExp(e);return this.regExpQueue.length===this.capacity&&this.regExpMap.delete(this.regExpQueue.shift()),this.regExpMap.set(e,r),this.regExpQueue.push(e),r}}const Zde=[" ",",","?","!",";"],Jde=new Qde(20),eue=(t,e,n)=>{e=e||"",n=n||"";const r=Zde.filter(o=>e.indexOf(o)<0&&n.indexOf(o)<0);if(r.length===0)return!0;const i=Jde.getRegExp(`(${r.map(o=>o==="?"?"\\?":o).join("|")})`);let s=!i.test(t);if(!s){const o=t.indexOf(n);o>0&&!i.test(t.substring(0,o))&&(s=!0)}return s},I3=(t,e,n=".")=>{if(!t)return;if(t[e])return Object.prototype.hasOwnProperty.call(t,e)?t[e]:void 0;const r=e.split(n);let i=t;for(let s=0;s-1&&ct?.replace("_","-"),tue={type:"logger",log(t){this.output("log",t)},warn(t){this.output("warn",t)},error(t){this.output("error",t)},output(t,e){console?.[t]?.apply?.(console,e)}};class uN{constructor(e,n={}){this.init(e,n)}init(e,n={}){this.prefix=n.prefix||"i18next:",this.logger=e||tue,this.options=n,this.debug=n.debug}log(...e){return this.forward(e,"log","",!0)}warn(...e){return this.forward(e,"warn","",!0)}error(...e){return this.forward(e,"error","")}deprecate(...e){return this.forward(e,"warn","WARNING DEPRECATED: ",!0)}forward(e,n,r,i){return i&&!this.debug?null:($n(e[0])&&(e[0]=`${r}${this.prefix} ${e[0]}`),this.logger[n](e))}create(e){return new uN(this.logger,{prefix:`${this.prefix}:${e}:`,...this.options})}clone(e){return e=e||this.options,e.prefix=e.prefix||this.prefix,new uN(this.logger,e)}}var Ed=new uN;let LP=class{constructor(){this.observers={}}on(e,n){return e.split(" ").forEach(r=>{this.observers[r]||(this.observers[r]=new Map);const i=this.observers[r].get(n)||0;this.observers[r].set(n,i+1)}),this}off(e,n){if(this.observers[e]){if(!n){delete this.observers[e];return}this.observers[e].delete(n)}}emit(e,...n){this.observers[e]&&Array.from(this.observers[e].entries()).forEach(([i,s])=>{for(let o=0;o{for(let o=0;o-1&&this.options.ns.splice(n,1)}getResource(e,n,r,i={}){const s=i.keySeparator!==void 0?i.keySeparator:this.options.keySeparator,o=i.ignoreJSONStructure!==void 0?i.ignoreJSONStructure:this.options.ignoreJSONStructure;let l;e.indexOf(".")>-1?l=e.split("."):(l=[e,n],r&&(Array.isArray(r)?l.push(...r):$n(r)&&s?l.push(...r.split(s)):l.push(r)));const c=dN(this.data,l);return!c&&!n&&!r&&e.indexOf(".")>-1&&(e=l[0],n=l[1],r=l.slice(2).join(".")),c||!o||!$n(r)?c:I3(this.data?.[e]?.[n],r,s)}addResource(e,n,r,i,s={silent:!1}){const o=s.keySeparator!==void 0?s.keySeparator:this.options.keySeparator;let l=[e,n];r&&(l=l.concat(o?r.split(o):r)),e.indexOf(".")>-1&&(l=e.split("."),i=n,n=l[1]),this.addNamespaces(n),B8(this.data,l,i),s.silent||this.emit("added",e,n,r,i)}addResources(e,n,r,i={silent:!1}){for(const s in r)($n(r[s])||Array.isArray(r[s]))&&this.addResource(e,n,s,r[s],{silent:!0});i.silent||this.emit("added",e,n,r)}addResourceBundle(e,n,r,i,s,o={silent:!1,skipCopy:!1}){let l=[e,n];e.indexOf(".")>-1&&(l=e.split("."),i=r,r=n,n=l[1]),this.addNamespaces(n);let c=dN(this.data,l)||{};o.skipCopy||(r=JSON.parse(JSON.stringify(r))),i?BY(c,r,s):c={...c,...r},B8(this.data,l,c),o.silent||this.emit("added",e,n,r)}removeResourceBundle(e,n){this.hasResourceBundle(e,n)&&delete this.data[e][n],this.removeNamespaces(n),this.emit("removed",e,n)}hasResourceBundle(e,n){return this.getResource(e,n)!==void 0}getResourceBundle(e,n){return n||(n=this.options.defaultNS),this.getResource(e,n)}getDataByLanguage(e){return this.data[e]}hasLanguageSomeTranslations(e){const n=this.getDataByLanguage(e);return!!(n&&Object.keys(n)||[]).find(i=>n[i]&&Object.keys(n[i]).length>0)}toJSON(){return this.data}}var HY={processors:{},addPostProcessor(t){this.processors[t.name]=t},handle(t,e,n,r,i){return t.forEach(s=>{e=this.processors[s]?.process(e,n,r,i)??e}),e}};const qY=Symbol("i18next/PATH_KEY");function nue(){const t=[],e=Object.create(null);let n;return e.get=(r,i)=>(n?.revoke?.(),i===qY?t:(t.push(i),n=Proxy.revocable(r,e),n.proxy)),Proxy.revocable(Object.create(null),e).proxy}function z3(t,e){const{[qY]:n}=t(nue());return n.join(e?.keySeparator??".")}const q8={},xM=t=>!$n(t)&&typeof t!="boolean"&&typeof t!="number";class mN extends LP{constructor(e,n={}){super(),Vde(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector","i18nFormat","utils"],e,this),this.options=n,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.logger=Ed.create("translator")}changeLanguage(e){e&&(this.language=e)}exists(e,n={interpolation:{}}){const r={...n};if(e==null)return!1;const i=this.resolve(e,r);if(i?.res===void 0)return!1;const s=xM(i.res);return!(r.returnObjects===!1&&s)}extractFromKey(e,n){let r=n.nsSeparator!==void 0?n.nsSeparator:this.options.nsSeparator;r===void 0&&(r=":");const i=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator;let s=n.ns||this.options.defaultNS||[];const o=r&&e.indexOf(r)>-1,l=!this.options.userDefinedKeySeparator&&!n.keySeparator&&!this.options.userDefinedNsSeparator&&!n.nsSeparator&&!eue(e,r,i);if(o&&!l){const c=e.match(this.interpolator.nestingRegexp);if(c&&c.length>0)return{key:e,namespaces:$n(s)?[s]:s};const d=e.split(r);(r!==i||r===i&&this.options.ns.indexOf(d[0])>-1)&&(s=d.shift()),e=d.join(i)}return{key:e,namespaces:$n(s)?[s]:s}}translate(e,n,r){let i=typeof n=="object"?{...n}:n;if(typeof i!="object"&&this.options.overloadTranslationOptionHandler&&(i=this.options.overloadTranslationOptionHandler(arguments)),typeof i=="object"&&(i={...i}),i||(i={}),e==null)return"";typeof e=="function"&&(e=z3(e,{...this.options,...i})),Array.isArray(e)||(e=[String(e)]);const s=i.returnDetails!==void 0?i.returnDetails:this.options.returnDetails,o=i.keySeparator!==void 0?i.keySeparator:this.options.keySeparator,{key:l,namespaces:c}=this.extractFromKey(e[e.length-1],i),d=c[c.length-1];let u=i.nsSeparator!==void 0?i.nsSeparator:this.options.nsSeparator;u===void 0&&(u=":");const m=i.lng||this.language,p=i.appendNamespaceToCIMode||this.options.appendNamespaceToCIMode;if(m?.toLowerCase()==="cimode")return p?s?{res:`${d}${u}${l}`,usedKey:l,exactUsedKey:l,usedLng:m,usedNS:d,usedParams:this.getUsedParamsDetails(i)}:`${d}${u}${l}`:s?{res:l,usedKey:l,exactUsedKey:l,usedLng:m,usedNS:d,usedParams:this.getUsedParamsDetails(i)}:l;const f=this.resolve(e,i);let x=f?.res;const v=f?.usedKey||l,b=f?.exactUsedKey||l,g=["[object Number]","[object Function]","[object RegExp]"],_=i.joinArrays!==void 0?i.joinArrays:this.options.joinArrays,C=!this.i18nFormat||this.i18nFormat.handleAsObject,P=i.count!==void 0&&!$n(i.count),N=mN.hasDefaultValue(i),A=P?this.pluralResolver.getSuffix(m,i.count,i):"",T=i.ordinal&&P?this.pluralResolver.getSuffix(m,i.count,{ordinal:!1}):"",F=P&&!i.ordinal&&i.count===0,k=F&&i[`defaultValue${this.options.pluralSeparator}zero`]||i[`defaultValue${A}`]||i[`defaultValue${T}`]||i.defaultValue;let D=x;C&&!x&&N&&(D=k);const H=xM(D),z=Object.prototype.toString.apply(D);if(C&&D&&H&&g.indexOf(z)<0&&!($n(_)&&Array.isArray(D))){if(!i.returnObjects&&!this.options.returnObjects){this.options.returnedObjectHandler||this.logger.warn("accessing an object - but returnObjects options is not enabled!");const Y=this.options.returnedObjectHandler?this.options.returnedObjectHandler(v,D,{...i,ns:c}):`key '${l} (${this.language})' returned an object instead of string.`;return s?(f.res=Y,f.usedParams=this.getUsedParamsDetails(i),f):Y}if(o){const Y=Array.isArray(D),L=Y?[]:{},te=Y?b:v;for(const ae in D)if(Object.prototype.hasOwnProperty.call(D,ae)){const J=`${te}${o}${ae}`;N&&!x?L[ae]=this.translate(J,{...i,defaultValue:xM(k)?k[ae]:void 0,joinArrays:!1,ns:c}):L[ae]=this.translate(J,{...i,joinArrays:!1,ns:c}),L[ae]===J&&(L[ae]=D[ae])}x=L}}else if(C&&$n(_)&&Array.isArray(x))x=x.join(_),x&&(x=this.extendTranslation(x,e,i,r));else{let Y=!1,L=!1;!this.isValidLookup(x)&&N&&(Y=!0,x=k),this.isValidLookup(x)||(L=!0,x=l);const ae=(i.missingKeyNoValueFallbackToKey||this.options.missingKeyNoValueFallbackToKey)&&L?void 0:x,J=N&&k!==x&&this.options.updateMissing;if(L||Y||J){if(this.logger.log(J?"updateKey":"missingKey",m,d,l,J?k:x),o){const W=this.resolve(l,{...i,keySeparator:!1});W&&W.res&&this.logger.warn("Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.")}let le=[];const se=this.languageUtils.getFallbackCodes(this.options.fallbackLng,i.lng||this.language);if(this.options.saveMissingTo==="fallback"&&se&&se[0])for(let W=0;W{const be=N&&fe!==x?fe:ae;this.options.missingKeyHandler?this.options.missingKeyHandler(W,d,ne,be,J,i):this.backendConnector?.saveMissing&&this.backendConnector.saveMissing(W,d,ne,be,J,i),this.emit("missingKey",W,d,ne,x)};this.options.saveMissing&&(this.options.saveMissingPlurals&&P?le.forEach(W=>{const ne=this.pluralResolver.getSuffixes(W,i);F&&i[`defaultValue${this.options.pluralSeparator}zero`]&&ne.indexOf(`${this.options.pluralSeparator}zero`)<0&&ne.push(`${this.options.pluralSeparator}zero`),ne.forEach(fe=>{oe([W],l+fe,i[`defaultValue${fe}`]||k)})}):oe(le,l,k))}x=this.extendTranslation(x,e,i,f,r),L&&x===l&&this.options.appendNamespaceToMissingKey&&(x=`${d}${u}${l}`),(L||Y)&&this.options.parseMissingKeyHandler&&(x=this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey?`${d}${u}${l}`:l,Y?x:void 0,i))}return s?(f.res=x,f.usedParams=this.getUsedParamsDetails(i),f):x}extendTranslation(e,n,r,i,s){if(this.i18nFormat?.parse)e=this.i18nFormat.parse(e,{...this.options.interpolation.defaultVariables,...r},r.lng||this.language||i.usedLng,i.usedNS,i.usedKey,{resolved:i});else if(!r.skipInterpolation){r.interpolation&&this.interpolator.init({...r,interpolation:{...this.options.interpolation,...r.interpolation}});const c=$n(e)&&(r?.interpolation?.skipOnVariables!==void 0?r.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables);let d;if(c){const m=e.match(this.interpolator.nestingRegexp);d=m&&m.length}let u=r.replace&&!$n(r.replace)?r.replace:r;if(this.options.interpolation.defaultVariables&&(u={...this.options.interpolation.defaultVariables,...u}),e=this.interpolator.interpolate(e,u,r.lng||this.language||i.usedLng,r),c){const m=e.match(this.interpolator.nestingRegexp),p=m&&m.length;ds?.[0]===m[0]&&!r.context?(this.logger.warn(`It seems you are nesting recursively key: ${m[0]} in key: ${n[0]}`),null):this.translate(...m,n),r)),r.interpolation&&this.interpolator.reset()}const o=r.postProcess||this.options.postProcess,l=$n(o)?[o]:o;return e!=null&&l?.length&&r.applyPostProcessor!==!1&&(e=HY.handle(l,e,n,this.options&&this.options.postProcessPassResolved?{i18nResolved:{...i,usedParams:this.getUsedParamsDetails(r)},...r}:r,this)),e}resolve(e,n={}){let r,i,s,o,l;return $n(e)&&(e=[e]),e.forEach(c=>{if(this.isValidLookup(r))return;const d=this.extractFromKey(c,n),u=d.key;i=u;let m=d.namespaces;this.options.fallbackNS&&(m=m.concat(this.options.fallbackNS));const p=n.count!==void 0&&!$n(n.count),f=p&&!n.ordinal&&n.count===0,x=n.context!==void 0&&($n(n.context)||typeof n.context=="number")&&n.context!=="",v=n.lngs?n.lngs:this.languageUtils.toResolveHierarchy(n.lng||this.language,n.fallbackLng);m.forEach(b=>{this.isValidLookup(r)||(l=b,!q8[`${v[0]}-${b}`]&&this.utils?.hasLoadedNamespace&&!this.utils?.hasLoadedNamespace(l)&&(q8[`${v[0]}-${b}`]=!0,this.logger.warn(`key "${i}" for languages "${v.join(", ")}" won't get resolved as namespace "${l}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!")),v.forEach(g=>{if(this.isValidLookup(r))return;o=g;const _=[u];if(this.i18nFormat?.addLookupKeys)this.i18nFormat.addLookupKeys(_,u,g,b,n);else{let P;p&&(P=this.pluralResolver.getSuffix(g,n.count,n));const N=`${this.options.pluralSeparator}zero`,A=`${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;if(p&&(n.ordinal&&P.indexOf(A)===0&&_.push(u+P.replace(A,this.options.pluralSeparator)),_.push(u+P),f&&_.push(u+N)),x){const T=`${u}${this.options.contextSeparator||"_"}${n.context}`;_.push(T),p&&(n.ordinal&&P.indexOf(A)===0&&_.push(T+P.replace(A,this.options.pluralSeparator)),_.push(T+P),f&&_.push(T+N))}}let C;for(;C=_.pop();)this.isValidLookup(r)||(s=C,r=this.getResource(g,b,C,n))}))})}),{res:r,usedKey:i,exactUsedKey:s,usedLng:o,usedNS:l}}isValidLookup(e){return e!==void 0&&!(!this.options.returnNull&&e===null)&&!(!this.options.returnEmptyString&&e==="")}getResource(e,n,r,i={}){return this.i18nFormat?.getResource?this.i18nFormat.getResource(e,n,r,i):this.resourceStore.getResource(e,n,r,i)}getUsedParamsDetails(e={}){const n=["defaultValue","ordinal","context","replace","lng","lngs","fallbackLng","ns","keySeparator","nsSeparator","returnObjects","returnDetails","joinArrays","postProcess","interpolation"],r=e.replace&&!$n(e.replace);let i=r?e.replace:e;if(r&&typeof e.count<"u"&&(i.count=e.count),this.options.interpolation.defaultVariables&&(i={...this.options.interpolation.defaultVariables,...i}),!r){i={...i};for(const s of n)delete i[s]}return i}static hasDefaultValue(e){const n="defaultValue";for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)&&n===r.substring(0,n.length)&&e[r]!==void 0)return!0;return!1}}class $8{constructor(e){this.options=e,this.supportedLngs=this.options.supportedLngs||!1,this.logger=Ed.create("languageUtils")}getScriptPartFromCode(e){if(e=Y0(e),!e||e.indexOf("-")<0)return null;const n=e.split("-");return n.length===2||(n.pop(),n[n.length-1].toLowerCase()==="x")?null:this.formatLanguageCode(n.join("-"))}getLanguagePartFromCode(e){if(e=Y0(e),!e||e.indexOf("-")<0)return e;const n=e.split("-");return this.formatLanguageCode(n[0])}formatLanguageCode(e){if($n(e)&&e.indexOf("-")>-1){let n;try{n=Intl.getCanonicalLocales(e)[0]}catch{}return n&&this.options.lowerCaseLng&&(n=n.toLowerCase()),n||(this.options.lowerCaseLng?e.toLowerCase():e)}return this.options.cleanCode||this.options.lowerCaseLng?e.toLowerCase():e}isSupportedCode(e){return(this.options.load==="languageOnly"||this.options.nonExplicitSupportedLngs)&&(e=this.getLanguagePartFromCode(e)),!this.supportedLngs||!this.supportedLngs.length||this.supportedLngs.indexOf(e)>-1}getBestMatchFromCodes(e){if(!e)return null;let n;return e.forEach(r=>{if(n)return;const i=this.formatLanguageCode(r);(!this.options.supportedLngs||this.isSupportedCode(i))&&(n=i)}),!n&&this.options.supportedLngs&&e.forEach(r=>{if(n)return;const i=this.getScriptPartFromCode(r);if(this.isSupportedCode(i))return n=i;const s=this.getLanguagePartFromCode(r);if(this.isSupportedCode(s))return n=s;n=this.options.supportedLngs.find(o=>{if(o===s)return o;if(!(o.indexOf("-")<0&&s.indexOf("-")<0)&&(o.indexOf("-")>0&&s.indexOf("-")<0&&o.substring(0,o.indexOf("-"))===s||o.indexOf(s)===0&&s.length>1))return o})}),n||(n=this.getFallbackCodes(this.options.fallbackLng)[0]),n}getFallbackCodes(e,n){if(!e)return[];if(typeof e=="function"&&(e=e(n)),$n(e)&&(e=[e]),Array.isArray(e))return e;if(!n)return e.default||[];let r=e[n];return r||(r=e[this.getScriptPartFromCode(n)]),r||(r=e[this.formatLanguageCode(n)]),r||(r=e[this.getLanguagePartFromCode(n)]),r||(r=e.default),r||[]}toResolveHierarchy(e,n){const r=this.getFallbackCodes((n===!1?[]:n)||this.options.fallbackLng||[],e),i=[],s=o=>{o&&(this.isSupportedCode(o)?i.push(o):this.logger.warn(`rejecting language code not found in supportedLngs: ${o}`))};return $n(e)&&(e.indexOf("-")>-1||e.indexOf("_")>-1)?(this.options.load!=="languageOnly"&&s(this.formatLanguageCode(e)),this.options.load!=="languageOnly"&&this.options.load!=="currentOnly"&&s(this.getScriptPartFromCode(e)),this.options.load!=="currentOnly"&&s(this.getLanguagePartFromCode(e))):$n(e)&&s(this.formatLanguageCode(e)),r.forEach(o=>{i.indexOf(o)<0&&s(this.formatLanguageCode(o))}),i}}const V8={zero:0,one:1,two:2,few:3,many:4,other:5},G8={select:t=>t===1?"one":"other",resolvedOptions:()=>({pluralCategories:["one","other"]})};class rue{constructor(e,n={}){this.languageUtils=e,this.options=n,this.logger=Ed.create("pluralResolver"),this.pluralRulesCache={}}addRule(e,n){this.rules[e]=n}clearCache(){this.pluralRulesCache={}}getRule(e,n={}){const r=Y0(e==="dev"?"en":e),i=n.ordinal?"ordinal":"cardinal",s=JSON.stringify({cleanedCode:r,type:i});if(s in this.pluralRulesCache)return this.pluralRulesCache[s];let o;try{o=new Intl.PluralRules(r,{type:i})}catch{if(!Intl)return this.logger.error("No Intl support, please use an Intl polyfill!"),G8;if(!e.match(/-|_/))return G8;const c=this.languageUtils.getLanguagePartFromCode(e);o=this.getRule(c,n)}return this.pluralRulesCache[s]=o,o}needsPlural(e,n={}){let r=this.getRule(e,n);return r||(r=this.getRule("dev",n)),r?.resolvedOptions().pluralCategories.length>1}getPluralFormsOfKey(e,n,r={}){return this.getSuffixes(e,r).map(i=>`${n}${i}`)}getSuffixes(e,n={}){let r=this.getRule(e,n);return r||(r=this.getRule("dev",n)),r?r.resolvedOptions().pluralCategories.sort((i,s)=>V8[i]-V8[s]).map(i=>`${this.options.prepend}${n.ordinal?`ordinal${this.options.prepend}`:""}${i}`):[]}getSuffix(e,n,r={}){const i=this.getRule(e,r);return i?`${this.options.prepend}${r.ordinal?`ordinal${this.options.prepend}`:""}${i.select(n)}`:(this.logger.warn(`no plural rule found for: ${e}`),this.getSuffix("dev",n,r))}}const W8=(t,e,n,r=".",i=!0)=>{let s=Kde(t,e,n);return!s&&i&&$n(n)&&(s=I3(t,n,r),s===void 0&&(s=I3(e,n,r))),s},yM=t=>t.replace(/\$/g,"$$$$");class aue{constructor(e={}){this.logger=Ed.create("interpolator"),this.options=e,this.format=e?.interpolation?.format||(n=>n),this.init(e)}init(e={}){e.interpolation||(e.interpolation={escapeValue:!0});const{escape:n,escapeValue:r,useRawValueToEscape:i,prefix:s,prefixEscaped:o,suffix:l,suffixEscaped:c,formatSeparator:d,unescapeSuffix:u,unescapePrefix:m,nestingPrefix:p,nestingPrefixEscaped:f,nestingSuffix:x,nestingSuffixEscaped:v,nestingOptionsSeparator:b,maxReplaces:g,alwaysFormat:_}=e.interpolation;this.escape=n!==void 0?n:Yde,this.escapeValue=r!==void 0?r:!0,this.useRawValueToEscape=i!==void 0?i:!1,this.prefix=s?vb(s):o||"{{",this.suffix=l?vb(l):c||"}}",this.formatSeparator=d||",",this.unescapePrefix=u?"":m||"-",this.unescapeSuffix=this.unescapePrefix?"":u||"",this.nestingPrefix=p?vb(p):f||vb("$t("),this.nestingSuffix=x?vb(x):v||vb(")"),this.nestingOptionsSeparator=b||",",this.maxReplaces=g||1e3,this.alwaysFormat=_!==void 0?_:!1,this.resetRegExp()}reset(){this.options&&this.init(this.options)}resetRegExp(){const e=(n,r)=>n?.source===r?(n.lastIndex=0,n):new RegExp(r,"g");this.regexp=e(this.regexp,`${this.prefix}(.+?)${this.suffix}`),this.regexpUnescape=e(this.regexpUnescape,`${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`),this.nestingRegexp=e(this.nestingRegexp,`${this.nestingPrefix}((?:[^()"']+|"[^"]*"|'[^']*'|\\((?:[^()]|"[^"]*"|'[^']*')*\\))*?)${this.nestingSuffix}`)}interpolate(e,n,r,i){let s,o,l;const c=this.options&&this.options.interpolation&&this.options.interpolation.defaultVariables||{},d=f=>{if(f.indexOf(this.formatSeparator)<0){const g=W8(n,c,f,this.options.keySeparator,this.options.ignoreJSONStructure);return this.alwaysFormat?this.format(g,void 0,r,{...i,...n,interpolationkey:f}):g}const x=f.split(this.formatSeparator),v=x.shift().trim(),b=x.join(this.formatSeparator).trim();return this.format(W8(n,c,v,this.options.keySeparator,this.options.ignoreJSONStructure),b,r,{...i,...n,interpolationkey:v})};this.resetRegExp();const u=i?.missingInterpolationHandler||this.options.missingInterpolationHandler,m=i?.interpolation?.skipOnVariables!==void 0?i.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables;return[{regex:this.regexpUnescape,safeValue:f=>yM(f)},{regex:this.regexp,safeValue:f=>this.escapeValue?yM(this.escape(f)):yM(f)}].forEach(f=>{for(l=0;s=f.regex.exec(e);){const x=s[1].trim();if(o=d(x),o===void 0)if(typeof u=="function"){const b=u(e,s,i);o=$n(b)?b:""}else if(i&&Object.prototype.hasOwnProperty.call(i,x))o="";else if(m){o=s[0];continue}else this.logger.warn(`missed to pass in variable ${x} for interpolating ${e}`),o="";else!$n(o)&&!this.useRawValueToEscape&&(o=I8(o));const v=f.safeValue(o);if(e=e.replace(s[0],v),m?(f.regex.lastIndex+=o.length,f.regex.lastIndex-=s[0].length):f.regex.lastIndex=0,l++,l>=this.maxReplaces)break}}),e}nest(e,n,r={}){let i,s,o;const l=(c,d)=>{const u=this.nestingOptionsSeparator;if(c.indexOf(u)<0)return c;const m=c.split(new RegExp(`${u}[ ]*{`));let p=`{${m[1]}`;c=m[0],p=this.interpolate(p,o);const f=p.match(/'/g),x=p.match(/"/g);((f?.length??0)%2===0&&!x||x.length%2!==0)&&(p=p.replace(/'/g,'"'));try{o=JSON.parse(p),d&&(o={...d,...o})}catch(v){return this.logger.warn(`failed parsing options string in nesting for key ${c}`,v),`${c}${u}${p}`}return o.defaultValue&&o.defaultValue.indexOf(this.prefix)>-1&&delete o.defaultValue,c};for(;i=this.nestingRegexp.exec(e);){let c=[];o={...r},o=o.replace&&!$n(o.replace)?o.replace:o,o.applyPostProcessor=!1,delete o.defaultValue;const d=/{.*}/.test(i[1])?i[1].lastIndexOf("}")+1:i[1].indexOf(this.formatSeparator);if(d!==-1&&(c=i[1].slice(d).split(this.formatSeparator).map(u=>u.trim()).filter(Boolean),i[1]=i[1].slice(0,d)),s=n(l.call(this,i[1].trim(),o),o),s&&i[0]===e&&!$n(s))return s;$n(s)||(s=I8(s)),s||(this.logger.warn(`missed to resolve ${i[1]} for nesting ${e}`),s=""),c.length&&(s=c.reduce((u,m)=>this.format(u,m,r.lng,{...r,interpolationkey:i[1].trim()}),s.trim())),e=e.replace(i[0],s),this.regexp.lastIndex=0}return e}}const iue=t=>{let e=t.toLowerCase().trim();const n={};if(t.indexOf("(")>-1){const r=t.split("(");e=r[0].toLowerCase().trim();const i=r[1].substring(0,r[1].length-1);e==="currency"&&i.indexOf(":")<0?n.currency||(n.currency=i.trim()):e==="relativetime"&&i.indexOf(":")<0?n.range||(n.range=i.trim()):i.split(";").forEach(o=>{if(o){const[l,...c]=o.split(":"),d=c.join(":").trim().replace(/^'+|'+$/g,""),u=l.trim();n[u]||(n[u]=d),d==="false"&&(n[u]=!1),d==="true"&&(n[u]=!0),isNaN(d)||(n[u]=parseInt(d,10))}})}return{formatName:e,formatOptions:n}},K8=t=>{const e={};return(n,r,i)=>{let s=i;i&&i.interpolationkey&&i.formatParams&&i.formatParams[i.interpolationkey]&&i[i.interpolationkey]&&(s={...s,[i.interpolationkey]:void 0});const o=r+JSON.stringify(s);let l=e[o];return l||(l=t(Y0(r),i),e[o]=l),l(n)}},sue=t=>(e,n,r)=>t(Y0(n),r)(e);class oue{constructor(e={}){this.logger=Ed.create("formatter"),this.options=e,this.init(e)}init(e,n={interpolation:{}}){this.formatSeparator=n.interpolation.formatSeparator||",";const r=n.cacheInBuiltFormats?K8:sue;this.formats={number:r((i,s)=>{const o=new Intl.NumberFormat(i,{...s});return l=>o.format(l)}),currency:r((i,s)=>{const o=new Intl.NumberFormat(i,{...s,style:"currency"});return l=>o.format(l)}),datetime:r((i,s)=>{const o=new Intl.DateTimeFormat(i,{...s});return l=>o.format(l)}),relativetime:r((i,s)=>{const o=new Intl.RelativeTimeFormat(i,{...s});return l=>o.format(l,s.range||"day")}),list:r((i,s)=>{const o=new Intl.ListFormat(i,{...s});return l=>o.format(l)})}}add(e,n){this.formats[e.toLowerCase().trim()]=n}addCached(e,n){this.formats[e.toLowerCase().trim()]=K8(n)}format(e,n,r,i={}){const s=n.split(this.formatSeparator);if(s.length>1&&s[0].indexOf("(")>1&&s[0].indexOf(")")<0&&s.find(l=>l.indexOf(")")>-1)){const l=s.findIndex(c=>c.indexOf(")")>-1);s[0]=[s[0],...s.splice(1,l)].join(this.formatSeparator)}return s.reduce((l,c)=>{const{formatName:d,formatOptions:u}=iue(c);if(this.formats[d]){let m=l;try{const p=i?.formatParams?.[i.interpolationkey]||{},f=p.locale||p.lng||i.locale||i.lng||r;m=this.formats[d](l,f,{...u,...i,...p})}catch(p){this.logger.warn(p)}return m}else this.logger.warn(`there was no format function for ${d}`);return l},e)}}const lue=(t,e)=>{t.pending[e]!==void 0&&(delete t.pending[e],t.pendingCount--)};class cue extends LP{constructor(e,n,r,i={}){super(),this.backend=e,this.store=n,this.services=r,this.languageUtils=r.languageUtils,this.options=i,this.logger=Ed.create("backendConnector"),this.waitingReads=[],this.maxParallelReads=i.maxParallelReads||10,this.readingCalls=0,this.maxRetries=i.maxRetries>=0?i.maxRetries:5,this.retryTimeout=i.retryTimeout>=1?i.retryTimeout:350,this.state={},this.queue=[],this.backend?.init?.(r,i.backend,i)}queueLoad(e,n,r,i){const s={},o={},l={},c={};return e.forEach(d=>{let u=!0;n.forEach(m=>{const p=`${d}|${m}`;!r.reload&&this.store.hasResourceBundle(d,m)?this.state[p]=2:this.state[p]<0||(this.state[p]===1?o[p]===void 0&&(o[p]=!0):(this.state[p]=1,u=!1,o[p]===void 0&&(o[p]=!0),s[p]===void 0&&(s[p]=!0),c[m]===void 0&&(c[m]=!0)))}),u||(l[d]=!0)}),(Object.keys(s).length||Object.keys(o).length)&&this.queue.push({pending:o,pendingCount:Object.keys(o).length,loaded:{},errors:[],callback:i}),{toLoad:Object.keys(s),pending:Object.keys(o),toLoadLanguages:Object.keys(l),toLoadNamespaces:Object.keys(c)}}loaded(e,n,r){const i=e.split("|"),s=i[0],o=i[1];n&&this.emit("failedLoading",s,o,n),!n&&r&&this.store.addResourceBundle(s,o,r,void 0,void 0,{skipCopy:!0}),this.state[e]=n?-1:2,n&&r&&(this.state[e]=0);const l={};this.queue.forEach(c=>{Wde(c.loaded,[s],o),lue(c,e),n&&c.errors.push(n),c.pendingCount===0&&!c.done&&(Object.keys(c.loaded).forEach(d=>{l[d]||(l[d]={});const u=c.loaded[d];u.length&&u.forEach(m=>{l[d][m]===void 0&&(l[d][m]=!0)})}),c.done=!0,c.errors.length?c.callback(c.errors):c.callback())}),this.emit("loaded",l),this.queue=this.queue.filter(c=>!c.done)}read(e,n,r,i=0,s=this.retryTimeout,o){if(!e.length)return o(null,{});if(this.readingCalls>=this.maxParallelReads){this.waitingReads.push({lng:e,ns:n,fcName:r,tried:i,wait:s,callback:o});return}this.readingCalls++;const l=(d,u)=>{if(this.readingCalls--,this.waitingReads.length>0){const m=this.waitingReads.shift();this.read(m.lng,m.ns,m.fcName,m.tried,m.wait,m.callback)}if(d&&u&&i{this.read.call(this,e,n,r,i+1,s*2,o)},s);return}o(d,u)},c=this.backend[r].bind(this.backend);if(c.length===2){try{const d=c(e,n);d&&typeof d.then=="function"?d.then(u=>l(null,u)).catch(l):l(null,d)}catch(d){l(d)}return}return c(e,n,l)}prepareLoading(e,n,r={},i){if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),i&&i();$n(e)&&(e=this.languageUtils.toResolveHierarchy(e)),$n(n)&&(n=[n]);const s=this.queueLoad(e,n,r,i);if(!s.toLoad.length)return s.pending.length||i(),null;s.toLoad.forEach(o=>{this.loadOne(o)})}load(e,n,r){this.prepareLoading(e,n,{},r)}reload(e,n,r){this.prepareLoading(e,n,{reload:!0},r)}loadOne(e,n=""){const r=e.split("|"),i=r[0],s=r[1];this.read(i,s,"read",void 0,void 0,(o,l)=>{o&&this.logger.warn(`${n}loading namespace ${s} for language ${i} failed`,o),!o&&l&&this.logger.log(`${n}loaded namespace ${s} for language ${i}`,l),this.loaded(e,o,l)})}saveMissing(e,n,r,i,s,o={},l=()=>{}){if(this.services?.utils?.hasLoadedNamespace&&!this.services?.utils?.hasLoadedNamespace(n)){this.logger.warn(`did not save key "${r}" as the namespace "${n}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!");return}if(!(r==null||r==="")){if(this.backend?.create){const c={...o,isUpdate:s},d=this.backend.create.bind(this.backend);if(d.length<6)try{let u;d.length===5?u=d(e,n,r,i,c):u=d(e,n,r,i),u&&typeof u.then=="function"?u.then(m=>l(null,m)).catch(l):l(null,u)}catch(u){l(u)}else d(e,n,r,i,l,c)}!e||!e[0]||this.store.addResource(e[0],n,r,i)}}}const X8=()=>({debug:!1,initAsync:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,supportedLngs:!1,nonExplicitSupportedLngs:!1,load:"all",preload:!1,simplifyPluralSuffix:!0,keySeparator:".",nsSeparator:":",pluralSeparator:"_",contextSeparator:"_",partialBundledLanguages:!1,saveMissing:!1,updateMissing:!1,saveMissingTo:"fallback",saveMissingPlurals:!0,missingKeyHandler:!1,missingInterpolationHandler:!1,postProcess:!1,postProcessPassResolved:!1,returnNull:!1,returnEmptyString:!0,returnObjects:!1,joinArrays:!1,returnedObjectHandler:!1,parseMissingKeyHandler:!1,appendNamespaceToMissingKey:!1,appendNamespaceToCIMode:!1,overloadTranslationOptionHandler:t=>{let e={};if(typeof t[1]=="object"&&(e=t[1]),$n(t[1])&&(e.defaultValue=t[1]),$n(t[2])&&(e.tDescription=t[2]),typeof t[2]=="object"||typeof t[3]=="object"){const n=t[3]||t[2];Object.keys(n).forEach(r=>{e[r]=n[r]})}return e},interpolation:{escapeValue:!0,format:t=>t,prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",nestingOptionsSeparator:",",maxReplaces:1e3,skipOnVariables:!0},cacheInBuiltFormats:!0}),Y8=t=>($n(t.ns)&&(t.ns=[t.ns]),$n(t.fallbackLng)&&(t.fallbackLng=[t.fallbackLng]),$n(t.fallbackNS)&&(t.fallbackNS=[t.fallbackNS]),t.supportedLngs?.indexOf?.("cimode")<0&&(t.supportedLngs=t.supportedLngs.concat(["cimode"])),typeof t.initImmediate=="boolean"&&(t.initAsync=t.initImmediate),t),V_=()=>{},due=t=>{Object.getOwnPropertyNames(Object.getPrototypeOf(t)).forEach(n=>{typeof t[n]=="function"&&(t[n]=t[n].bind(t))})};class k0 extends LP{constructor(e={},n){if(super(),this.options=Y8(e),this.services={},this.logger=Ed,this.modules={external:[]},due(this),n&&!this.isInitialized&&!e.isClone){if(!this.options.initAsync)return this.init(e,n),this;setTimeout(()=>{this.init(e,n)},0)}}init(e={},n){this.isInitializing=!0,typeof e=="function"&&(n=e,e={}),e.defaultNS==null&&e.ns&&($n(e.ns)?e.defaultNS=e.ns:e.ns.indexOf("translation")<0&&(e.defaultNS=e.ns[0]));const r=X8();this.options={...r,...this.options,...Y8(e)},this.options.interpolation={...r.interpolation,...this.options.interpolation},e.keySeparator!==void 0&&(this.options.userDefinedKeySeparator=e.keySeparator),e.nsSeparator!==void 0&&(this.options.userDefinedNsSeparator=e.nsSeparator);const i=d=>d?typeof d=="function"?new d:d:null;if(!this.options.isClone){this.modules.logger?Ed.init(i(this.modules.logger),this.options):Ed.init(null,this.options);let d;this.modules.formatter?d=this.modules.formatter:d=oue;const u=new $8(this.options);this.store=new H8(this.options.resources,this.options);const m=this.services;m.logger=Ed,m.resourceStore=this.store,m.languageUtils=u,m.pluralResolver=new rue(u,{prepend:this.options.pluralSeparator,simplifyPluralSuffix:this.options.simplifyPluralSuffix}),this.options.interpolation.format&&this.options.interpolation.format!==r.interpolation.format&&this.logger.deprecate("init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting"),d&&(!this.options.interpolation.format||this.options.interpolation.format===r.interpolation.format)&&(m.formatter=i(d),m.formatter.init&&m.formatter.init(m,this.options),this.options.interpolation.format=m.formatter.format.bind(m.formatter)),m.interpolator=new aue(this.options),m.utils={hasLoadedNamespace:this.hasLoadedNamespace.bind(this)},m.backendConnector=new cue(i(this.modules.backend),m.resourceStore,m,this.options),m.backendConnector.on("*",(f,...x)=>{this.emit(f,...x)}),this.modules.languageDetector&&(m.languageDetector=i(this.modules.languageDetector),m.languageDetector.init&&m.languageDetector.init(m,this.options.detection,this.options)),this.modules.i18nFormat&&(m.i18nFormat=i(this.modules.i18nFormat),m.i18nFormat.init&&m.i18nFormat.init(this)),this.translator=new mN(this.services,this.options),this.translator.on("*",(f,...x)=>{this.emit(f,...x)}),this.modules.external.forEach(f=>{f.init&&f.init(this)})}if(this.format=this.options.interpolation.format,n||(n=V_),this.options.fallbackLng&&!this.services.languageDetector&&!this.options.lng){const d=this.services.languageUtils.getFallbackCodes(this.options.fallbackLng);d.length>0&&d[0]!=="dev"&&(this.options.lng=d[0])}!this.services.languageDetector&&!this.options.lng&&this.logger.warn("init: no languageDetector is used and no lng is defined"),["getResource","hasResourceBundle","getResourceBundle","getDataByLanguage"].forEach(d=>{this[d]=(...u)=>this.store[d](...u)}),["addResource","addResources","addResourceBundle","removeResourceBundle"].forEach(d=>{this[d]=(...u)=>(this.store[d](...u),this)});const l=Cv(),c=()=>{const d=(u,m)=>{this.isInitializing=!1,this.isInitialized&&!this.initializedStoreOnce&&this.logger.warn("init: i18next is already initialized. You should call init just once!"),this.isInitialized=!0,this.options.isClone||this.logger.log("initialized",this.options),this.emit("initialized",this.options),l.resolve(m),n(u,m)};if(this.languages&&!this.isInitialized)return d(null,this.t.bind(this));this.changeLanguage(this.options.lng,d)};return this.options.resources||!this.options.initAsync?c():setTimeout(c,0),l}loadResources(e,n=V_){let r=n;const i=$n(e)?e:this.language;if(typeof e=="function"&&(r=e),!this.options.resources||this.options.partialBundledLanguages){if(i?.toLowerCase()==="cimode"&&(!this.options.preload||this.options.preload.length===0))return r();const s=[],o=l=>{if(!l||l==="cimode")return;this.services.languageUtils.toResolveHierarchy(l).forEach(d=>{d!=="cimode"&&s.indexOf(d)<0&&s.push(d)})};i?o(i):this.services.languageUtils.getFallbackCodes(this.options.fallbackLng).forEach(c=>o(c)),this.options.preload?.forEach?.(l=>o(l)),this.services.backendConnector.load(s,this.options.ns,l=>{!l&&!this.resolvedLanguage&&this.language&&this.setResolvedLanguage(this.language),r(l)})}else r(null)}reloadResources(e,n,r){const i=Cv();return typeof e=="function"&&(r=e,e=void 0),typeof n=="function"&&(r=n,n=void 0),e||(e=this.languages),n||(n=this.options.ns),r||(r=V_),this.services.backendConnector.reload(e,n,s=>{i.resolve(),r(s)}),i}use(e){if(!e)throw new Error("You are passing an undefined module! Please check the object you are passing to i18next.use()");if(!e.type)throw new Error("You are passing a wrong module! Please check the object you are passing to i18next.use()");return e.type==="backend"&&(this.modules.backend=e),(e.type==="logger"||e.log&&e.warn&&e.error)&&(this.modules.logger=e),e.type==="languageDetector"&&(this.modules.languageDetector=e),e.type==="i18nFormat"&&(this.modules.i18nFormat=e),e.type==="postProcessor"&&HY.addPostProcessor(e),e.type==="formatter"&&(this.modules.formatter=e),e.type==="3rdParty"&&this.modules.external.push(e),this}setResolvedLanguage(e){if(!(!e||!this.languages)&&!(["cimode","dev"].indexOf(e)>-1)){for(let n=0;n-1)&&this.store.hasLanguageSomeTranslations(r)){this.resolvedLanguage=r;break}}!this.resolvedLanguage&&this.languages.indexOf(e)<0&&this.store.hasLanguageSomeTranslations(e)&&(this.resolvedLanguage=e,this.languages.unshift(e))}}changeLanguage(e,n){this.isLanguageChangingTo=e;const r=Cv();this.emit("languageChanging",e);const i=l=>{this.language=l,this.languages=this.services.languageUtils.toResolveHierarchy(l),this.resolvedLanguage=void 0,this.setResolvedLanguage(l)},s=(l,c)=>{c?this.isLanguageChangingTo===e&&(i(c),this.translator.changeLanguage(c),this.isLanguageChangingTo=void 0,this.emit("languageChanged",c),this.logger.log("languageChanged",c)):this.isLanguageChangingTo=void 0,r.resolve((...d)=>this.t(...d)),n&&n(l,(...d)=>this.t(...d))},o=l=>{!e&&!l&&this.services.languageDetector&&(l=[]);const c=$n(l)?l:l&&l[0],d=this.store.hasLanguageSomeTranslations(c)?c:this.services.languageUtils.getBestMatchFromCodes($n(l)?[l]:l);d&&(this.language||i(d),this.translator.language||this.translator.changeLanguage(d),this.services.languageDetector?.cacheUserLanguage?.(d)),this.loadResources(d,u=>{s(u,d)})};return!e&&this.services.languageDetector&&!this.services.languageDetector.async?o(this.services.languageDetector.detect()):!e&&this.services.languageDetector&&this.services.languageDetector.async?this.services.languageDetector.detect.length===0?this.services.languageDetector.detect().then(o):this.services.languageDetector.detect(o):o(e),r}getFixedT(e,n,r){const i=(s,o,...l)=>{let c;typeof o!="object"?c=this.options.overloadTranslationOptionHandler([s,o].concat(l)):c={...o},c.lng=c.lng||i.lng,c.lngs=c.lngs||i.lngs,c.ns=c.ns||i.ns,c.keyPrefix!==""&&(c.keyPrefix=c.keyPrefix||r||i.keyPrefix);const d=this.options.keySeparator||".";let u;return c.keyPrefix&&Array.isArray(s)?u=s.map(m=>(typeof m=="function"&&(m=z3(m,{...this.options,...o})),`${c.keyPrefix}${d}${m}`)):(typeof s=="function"&&(s=z3(s,{...this.options,...o})),u=c.keyPrefix?`${c.keyPrefix}${d}${s}`:s),this.t(u,c)};return $n(e)?i.lng=e:i.lngs=e,i.ns=n,i.keyPrefix=r,i}t(...e){return this.translator?.translate(...e)}exists(...e){return this.translator?.exists(...e)}setDefaultNamespace(e){this.options.defaultNS=e}hasLoadedNamespace(e,n={}){if(!this.isInitialized)return this.logger.warn("hasLoadedNamespace: i18next was not initialized",this.languages),!1;if(!this.languages||!this.languages.length)return this.logger.warn("hasLoadedNamespace: i18n.languages were undefined or empty",this.languages),!1;const r=n.lng||this.resolvedLanguage||this.languages[0],i=this.options?this.options.fallbackLng:!1,s=this.languages[this.languages.length-1];if(r.toLowerCase()==="cimode")return!0;const o=(l,c)=>{const d=this.services.backendConnector.state[`${l}|${c}`];return d===-1||d===0||d===2};if(n.precheck){const l=n.precheck(this,o);if(l!==void 0)return l}return!!(this.hasResourceBundle(r,e)||!this.services.backendConnector.backend||this.options.resources&&!this.options.partialBundledLanguages||o(r,e)&&(!i||o(s,e)))}loadNamespaces(e,n){const r=Cv();return this.options.ns?($n(e)&&(e=[e]),e.forEach(i=>{this.options.ns.indexOf(i)<0&&this.options.ns.push(i)}),this.loadResources(i=>{r.resolve(),n&&n(i)}),r):(n&&n(),Promise.resolve())}loadLanguages(e,n){const r=Cv();$n(e)&&(e=[e]);const i=this.options.preload||[],s=e.filter(o=>i.indexOf(o)<0&&this.services.languageUtils.isSupportedCode(o));return s.length?(this.options.preload=i.concat(s),this.loadResources(o=>{r.resolve(),n&&n(o)}),r):(n&&n(),Promise.resolve())}dir(e){if(e||(e=this.resolvedLanguage||(this.languages?.length>0?this.languages[0]:this.language)),!e)return"rtl";try{const i=new Intl.Locale(e);if(i&&i.getTextInfo){const s=i.getTextInfo();if(s&&s.direction)return s.direction}}catch{}const n=["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ug","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam","ckb"],r=this.services?.languageUtils||new $8(X8());return e.toLowerCase().indexOf("-latn")>1?"ltr":n.indexOf(r.getLanguagePartFromCode(e))>-1||e.toLowerCase().indexOf("-arab")>1?"rtl":"ltr"}static createInstance(e={},n){const r=new k0(e,n);return r.createInstance=k0.createInstance,r}cloneInstance(e={},n=V_){const r=e.forkResourceStore;r&&delete e.forkResourceStore;const i={...this.options,...e,isClone:!0},s=new k0(i);if((e.debug!==void 0||e.prefix!==void 0)&&(s.logger=s.logger.clone(e)),["store","services","language"].forEach(l=>{s[l]=this[l]}),s.services={...this.services},s.services.utils={hasLoadedNamespace:s.hasLoadedNamespace.bind(s)},r){const l=Object.keys(this.store.data).reduce((c,d)=>(c[d]={...this.store.data[d]},c[d]=Object.keys(c[d]).reduce((u,m)=>(u[m]={...c[d][m]},u),c[d]),c),{});s.store=new H8(l,i),s.services.resourceStore=s.store}return s.translator=new mN(s.services,i),s.translator.on("*",(l,...c)=>{s.emit(l,...c)}),s.init(i,n),s.translator.options=i,s.translator.backendConnector.services.utils={hasLoadedNamespace:s.hasLoadedNamespace.bind(s)},s}toJSON(){return{options:this.options,store:this.store,language:this.language,languages:this.languages,resolvedLanguage:this.resolvedLanguage}}}const xo=k0.createInstance();xo.createInstance;xo.dir;xo.init;xo.loadResources;xo.reloadResources;xo.use;xo.changeLanguage;xo.getFixedT;xo.t;xo.exists;xo.setDefaultNamespace;xo.hasLoadedNamespace;xo.loadNamespaces;xo.loadLanguages;const uue=(t,e,n,r)=>{const i=[n,{code:e,...r||{}}];if(t?.services?.logger?.forward)return t.services.logger.forward(i,"warn","react-i18next::",!0);ng(i[0])&&(i[0]=`react-i18next:: ${i[0]}`),t?.services?.logger?.warn?t.services.logger.warn(...i):console?.warn&&console.warn(...i)},Q8={},$Y=(t,e,n,r)=>{ng(n)&&Q8[n]||(ng(n)&&(Q8[n]=new Date),uue(t,e,n,r))},VY=(t,e)=>()=>{if(t.isInitialized)e();else{const n=()=>{setTimeout(()=>{t.off("initialized",n)},0),e()};t.on("initialized",n)}},U3=(t,e,n)=>{t.loadNamespaces(e,VY(t,n))},Z8=(t,e,n,r)=>{if(ng(n)&&(n=[n]),t.options.preload&&t.options.preload.indexOf(e)>-1)return U3(t,n,r);n.forEach(i=>{t.options.ns.indexOf(i)<0&&t.options.ns.push(i)}),t.loadLanguages(e,VY(t,r))},mue=(t,e,n={})=>!e.languages||!e.languages.length?($Y(e,"NO_LANGUAGES","i18n.languages were undefined or empty",{languages:e.languages}),!0):e.hasLoadedNamespace(t,{lng:n.lng,precheck:(r,i)=>{if(n.bindI18n&&n.bindI18n.indexOf("languageChanging")>-1&&r.services.backendConnector.backend&&r.isLanguageChangingTo&&!i(r.isLanguageChangingTo,t))return!1}}),ng=t=>typeof t=="string",hue=t=>typeof t=="object"&&t!==null,pue=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,fue={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},gue=t=>fue[t],bue=t=>t.replace(pue,gue);let B3={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:bue,transDefaultProps:void 0};const xue=(t={})=>{B3={...B3,...t}},yue=()=>B3;let GY;const vue=t=>{GY=t},wue=()=>GY,Sue={type:"3rdParty",init(t){xue(t.options.react),vue(t)}},_ue=w.createContext();class kue{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach(n=>{this.usedNamespaces[n]||(this.usedNamespaces[n]=!0)})}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}var vM={exports:{}},wM={};var J8;function Nue(){if(J8)return wM;J8=1;var t=jg();function e(m,p){return m===p&&(m!==0||1/m===1/p)||m!==m&&p!==p}var n=typeof Object.is=="function"?Object.is:e,r=t.useState,i=t.useEffect,s=t.useLayoutEffect,o=t.useDebugValue;function l(m,p){var f=p(),x=r({inst:{value:f,getSnapshot:p}}),v=x[0].inst,b=x[1];return s(function(){v.value=f,v.getSnapshot=p,c(v)&&b({inst:v})},[m,f,p]),i(function(){return c(v)&&b({inst:v}),m(function(){c(v)&&b({inst:v})})},[m]),o(f),f}function c(m){var p=m.getSnapshot;m=m.value;try{var f=p();return!n(m,f)}catch{return!0}}function d(m,p){return p()}var u=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?d:l;return wM.useSyncExternalStore=t.useSyncExternalStore!==void 0?t.useSyncExternalStore:u,wM}var eH;function WY(){return eH||(eH=1,vM.exports=Nue()),vM.exports}var cO=WY();const Cue=(t,e)=>ng(e)?e:hue(e)&&ng(e.defaultValue)?e.defaultValue:Array.isArray(t)?t[t.length-1]:t,Pue={t:Cue,ready:!1},Tue=()=>()=>{},Dt=(t,e={})=>{const{i18n:n}=e,{i18n:r,defaultNS:i}=w.useContext(_ue)||{},s=n||r||wue();s&&!s.reportNamespaces&&(s.reportNamespaces=new kue),s||$Y(s,"NO_I18NEXT_INSTANCE","useTranslation: You will need to pass in an i18next instance by using initReactI18next");const o=w.useMemo(()=>({...yue(),...s?.options?.react,...e}),[s,e]),{useSuspense:l,keyPrefix:c}=o,d=i||s?.options?.defaultNS,u=ng(d)?[d]:d||["translation"],m=w.useMemo(()=>u,u);s?.reportNamespaces?.addUsedNamespaces?.(m);const p=w.useRef(0),f=w.useCallback(k=>{if(!s)return Tue;const{bindI18n:D,bindI18nStore:H}=o,z=()=>{p.current+=1,k()};return D&&s.on(D,z),H&&s.store.on(H,z),()=>{D&&D.split(" ").forEach(Y=>s.off(Y,z)),H&&H.split(" ").forEach(Y=>s.store.off(Y,z))}},[s,o]),x=w.useRef(),v=w.useCallback(()=>{if(!s)return Pue;const k=!!(s.isInitialized||s.initializedStoreOnce)&&m.every(te=>mue(te,s,o)),D=e.lng||s.language,H=p.current,z=x.current;if(z&&z.ready===k&&z.lng===D&&z.keyPrefix===c&&z.revision===H)return z;const L={t:s.getFixedT(D,o.nsMode==="fallback"?m:m[0],c),ready:k,lng:D,keyPrefix:c,revision:H};return x.current=L,L},[s,m,c,o,e.lng]),[b,g]=w.useState(0),{t:_,ready:C}=cO.useSyncExternalStore(f,v,v);w.useEffect(()=>{if(s&&!C&&!l){const k=()=>g(D=>D+1);e.lng?Z8(s,e.lng,m,k):U3(s,m,k)}},[s,e.lng,m,C,l,b]);const P=s||{},N=w.useRef(null),A=w.useRef(),T=k=>{const D=Object.getOwnPropertyDescriptors(k);D.__original&&delete D.__original;const H=Object.create(Object.getPrototypeOf(k),D);if(!Object.prototype.hasOwnProperty.call(H,"__original"))try{Object.defineProperty(H,"__original",{value:k,writable:!1,enumerable:!1,configurable:!1})}catch{}return H},F=w.useMemo(()=>{const k=P,D=k?.language;let H=k;k&&(N.current&&N.current.__original===k?A.current!==D?(H=T(k),N.current=H,A.current=D):H=N.current:(H=T(k),N.current=H,A.current=D));const z=[_,H,C];return z.t=_,z.i18n=H,z.ready=C,z},[_,P,C,P.resolvedLanguage,P.language,P.languages]);if(s&&l&&!C)throw new Promise(k=>{const D=()=>k();e.lng?Z8(s,e.lng,m,D):U3(s,m,D)});return F},{slice:Aue,forEach:jue}=[];function Mue(t){return jue.call(Aue.call(arguments,1),e=>{if(e)for(const n in e)t[n]===void 0&&(t[n]=e[n])}),t}function Eue(t){return typeof t!="string"?!1:[/<\s*script.*?>/i,/<\s*\/\s*script\s*>/i,/<\s*img.*?on\w+\s*=/i,/<\s*\w+\s*on\w+\s*=.*?>/i,/javascript\s*:/i,/vbscript\s*:/i,/expression\s*\(/i,/eval\s*\(/i,/alert\s*\(/i,/document\.cookie/i,/document\.write\s*\(/i,/window\.location/i,/innerHTML/i].some(n=>n.test(t))}const tH=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/,Due=function(t,e){const r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{path:"/"},i=encodeURIComponent(e);let s=`${t}=${i}`;if(r.maxAge>0){const o=r.maxAge-0;if(Number.isNaN(o))throw new Error("maxAge should be a Number");s+=`; Max-Age=${Math.floor(o)}`}if(r.domain){if(!tH.test(r.domain))throw new TypeError("option domain is invalid");s+=`; Domain=${r.domain}`}if(r.path){if(!tH.test(r.path))throw new TypeError("option path is invalid");s+=`; Path=${r.path}`}if(r.expires){if(typeof r.expires.toUTCString!="function")throw new TypeError("option expires is invalid");s+=`; Expires=${r.expires.toUTCString()}`}if(r.httpOnly&&(s+="; HttpOnly"),r.secure&&(s+="; Secure"),r.sameSite)switch(typeof r.sameSite=="string"?r.sameSite.toLowerCase():r.sameSite){case!0:s+="; SameSite=Strict";break;case"lax":s+="; SameSite=Lax";break;case"strict":s+="; SameSite=Strict";break;case"none":s+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}return r.partitioned&&(s+="; Partitioned"),s},nH={create(t,e,n,r){let i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:{path:"/",sameSite:"strict"};n&&(i.expires=new Date,i.expires.setTime(i.expires.getTime()+n*60*1e3)),r&&(i.domain=r),document.cookie=Due(t,e,i)},read(t){const e=`${t}=`,n=document.cookie.split(";");for(let r=0;r-1&&(r=window.location.hash.substring(window.location.hash.indexOf("?")));const s=r.substring(1).split("&");for(let o=0;o0&&s[o].substring(0,l)===e&&(n=s[o].substring(l+1))}}return n}},Lue={name:"hash",lookup(t){let{lookupHash:e,lookupFromHashIndex:n}=t,r;if(typeof window<"u"){const{hash:i}=window.location;if(i&&i.length>2){const s=i.substring(1);if(e){const o=s.split("&");for(let l=0;l0&&o[l].substring(0,c)===e&&(r=o[l].substring(c+1))}}if(r)return r;if(!r&&n>-1){const o=i.match(/\/([a-zA-Z-]*)/g);return Array.isArray(o)?o[typeof n=="number"?n:0]?.replace("/",""):void 0}}}return r}};let wb=null;const rH=()=>{if(wb!==null)return wb;try{if(wb=typeof window<"u"&&window.localStorage!==null,!wb)return!1;const t="i18next.translate.boo";window.localStorage.setItem(t,"foo"),window.localStorage.removeItem(t)}catch{wb=!1}return wb};var Oue={name:"localStorage",lookup(t){let{lookupLocalStorage:e}=t;if(e&&rH())return window.localStorage.getItem(e)||void 0},cacheUserLanguage(t,e){let{lookupLocalStorage:n}=e;n&&rH()&&window.localStorage.setItem(n,t)}};let Sb=null;const aH=()=>{if(Sb!==null)return Sb;try{if(Sb=typeof window<"u"&&window.sessionStorage!==null,!Sb)return!1;const t="i18next.translate.boo";window.sessionStorage.setItem(t,"foo"),window.sessionStorage.removeItem(t)}catch{Sb=!1}return Sb};var Iue={name:"sessionStorage",lookup(t){let{lookupSessionStorage:e}=t;if(e&&aH())return window.sessionStorage.getItem(e)||void 0},cacheUserLanguage(t,e){let{lookupSessionStorage:n}=e;n&&aH()&&window.sessionStorage.setItem(n,t)}},zue={name:"navigator",lookup(t){const e=[];if(typeof navigator<"u"){const{languages:n,userLanguage:r,language:i}=navigator;if(n)for(let s=0;s0?e:void 0}},Uue={name:"htmlTag",lookup(t){let{htmlTag:e}=t,n;const r=e||(typeof document<"u"?document.documentElement:null);return r&&typeof r.getAttribute=="function"&&(n=r.getAttribute("lang")),n}},Bue={name:"path",lookup(t){let{lookupFromPathIndex:e}=t;if(typeof window>"u")return;const n=window.location.pathname.match(/\/([a-zA-Z-]*)/g);return Array.isArray(n)?n[typeof e=="number"?e:0]?.replace("/",""):void 0}},Hue={name:"subdomain",lookup(t){let{lookupFromSubdomainIndex:e}=t;const n=typeof e=="number"?e+1:1,r=typeof window<"u"&&window.location?.hostname?.match(/^(\w{2,5})\.(([a-z0-9-]{1,63}\.[a-z]{2,6})|localhost)/i);if(r)return r[n]}};let KY=!1;try{document.cookie,KY=!0}catch{}const XY=["querystring","cookie","localStorage","sessionStorage","navigator","htmlTag"];KY||XY.splice(1,1);const que=()=>({order:XY,lookupQuerystring:"lng",lookupCookie:"i18next",lookupLocalStorage:"i18nextLng",lookupSessionStorage:"i18nextLng",caches:["localStorage"],excludeCacheFor:["cimode"],convertDetectedLanguage:t=>t});class YY{constructor(e){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};this.type="languageDetector",this.detectors={},this.init(e,n)}init(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{languageUtils:{}},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};this.services=e,this.options=Mue(n,this.options||{},que()),typeof this.options.convertDetectedLanguage=="string"&&this.options.convertDetectedLanguage.indexOf("15897")>-1&&(this.options.convertDetectedLanguage=i=>i.replace("-","_")),this.options.lookupFromUrlIndex&&(this.options.lookupFromPathIndex=this.options.lookupFromUrlIndex),this.i18nOptions=r,this.addDetector(Fue),this.addDetector(Rue),this.addDetector(Oue),this.addDetector(Iue),this.addDetector(zue),this.addDetector(Uue),this.addDetector(Bue),this.addDetector(Hue),this.addDetector(Lue)}addDetector(e){return this.detectors[e.name]=e,this}detect(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:this.options.order,n=[];return e.forEach(r=>{if(this.detectors[r]){let i=this.detectors[r].lookup(this.options);i&&typeof i=="string"&&(i=[i]),i&&(n=n.concat(i))}}),n=n.filter(r=>r!=null&&!Eue(r)).map(r=>this.options.convertDetectedLanguage(r)),this.services&&this.services.languageUtils&&this.services.languageUtils.getBestMatchFromCodes?n:n.length>0?n[0]:null}cacheUserLanguage(e){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:this.options.caches;n&&(this.options.excludeCacheFor&&this.options.excludeCacheFor.indexOf(e)>-1||n.forEach(r=>{this.detectors[r]&&this.detectors[r].cacheUserLanguage(e,this.options)}))}}YY.type="languageDetector";const $ue={nav:{printers:"Printers",archives:"Archives",queue:"Queue",stats:"Statistics",profiles:"Profiles",maintenance:"Maintenance",projects:"Projects",inventory:"Filament",files:"File Manager",notifications:"Notifications",settings:"Settings",system:"System",collapseSidebar:"Collapse sidebar",expandSidebar:"Expand sidebar",update:"Update",updateAvailable:"Update available: v{{version}}",updateAvailableBanner:"Version {{version}} is available!",viewUpdate:"View update",viewOnGithub:"View on GitHub",keyboardShortcuts:"Keyboard shortcuts (?)",switchToLight:"Switch to light mode",switchToDark:"Switch to dark mode",smartSwitches:"Smart Switches",logout:"Logout"},common:{save:"Save",saving:"Saving...",cancel:"Cancel",delete:"Delete",edit:"Edit",add:"Add",close:"Close",confirm:"Confirm",loading:"Loading...",error:"Error",success:"Success",warning:"Warning",enabled:"Enabled",disabled:"Disabled",yes:"Yes",no:"No",on:"On",off:"Off",all:"All",none:"None",search:"Search",filter:"Filter",sort:"Sort",refresh:"Refresh",download:"Download",upload:"Upload",uploading:"Uploading...",uploadFailed:"Upload failed",actions:"Actions",status:"Status",name:"Name",description:"Description",date:"Date",time:"Time",hours:"hours",minutes:"minutes",seconds:"seconds",days:"days",enable:"Enable",disable:"Disable",permissions:"Permissions",noPrinters:"No printers configured",noData:"No data available",linkNotFound:"Link not found",required:"Required",optional:"Optional",dismiss:"Dismiss",apply:"Apply",reset:"Reset",export:"Export",import:"Import",clear:"Clear",selectAll:"Select All",deselectAll:"Deselect All",noChange:"— No change —",unchanged:"Unchanged",unassigned:"Unassigned",unknown:"Unknown",unknownError:"Unknown error",today:"Today",tomorrow:"Tomorrow",asap:"ASAP",overdue:"Overdue",now:"Now",collapse:"Collapse",expand:"Expand",viewArchive:"View archive",viewInFileManager:"View in File Manager",addedBy:"Added by {{username}}",prints:"prints",more:"+{{count}} more",ascending:"Ascending",descending:"Descending",back:"Back",copy:"Copy",copied:"Copied!",printer:"Printer",remove:"Remove",type:"Type",print:"Print",rename:"Rename",move:"Move",create:"Create",duplicate:"Duplicate",left:"Left",right:"Right"},printers:{title:"Printers",addPrinter:"Add Printer",editPrinter:"Edit Printer",deletePrinter:"Delete Printer",printerName:"Printer Name",serialNumber:"Serial Number",ipAddress:"IP Address / Hostname",accessCode:"Access Code",model:"Model",nozzleCount:"Nozzle Count",autoArchive:"Auto Archive",status:{available:"Available",idle:"Idle",printing:"Printing",paused:"Paused",offline:"Offline",problem:"Problem",error:"Error",finished:"Finished",unknown:"Unknown"},temperatures:{nozzle:"Nozzle",bed:"Bed",chamber:"Chamber"},progress:"{{percent}}% complete",timeRemaining:"{{time}} remaining",deleteConfirm:'Are you sure you want to delete "{{name}}"?',maintenanceOk:"Maintenance OK",maintenanceWarning:"{{count}} warning",maintenanceWarning_plural:"{{count}} warnings",maintenanceDue:"{{count}} due",maintenanceDue_plural:"{{count}} due",sort:{name:"Name",status:"Status",model:"Model",location:"Location",ascending:"Sort ascending",descending:"Sort descending"},cardSize:{small:"Small cards",medium:"Medium cards",large:"Large cards",extraLarge:"Extra large cards"},hideOffline:"Hide offline",nextAvailable:"Next available",powerOn:"Power On",offlinePrintersWithPlugs:"Offline printers with smart plugs",noPrintersConfigured:"No printers configured yet",search:"Search printers...",noSearchResults:"No printers match your search or filters",filter:{allStatuses:"All statuses",allLocations:"All locations"},readyToPrint:"Ready to print",external:"External",extL:"Ext-L",extR:"Ext-R",deleteArchives:"Delete print archives",noLabel:"No label",printPreview:"Print preview",width:"Width",height:"Height",noObjectsFound:"No objects found",objectsLoadedOnPrintStart:"Objects are loaded when a print starts",willBeSkipped:"Will be skipped",name:"Name",serialCannotBeChanged:"Serial number cannot be changed",locationHelp:"Used to group printers and filter queue jobs",wifiSignal:{veryWeak:"Very weak",weak:"Weak",fair:"Fair",good:"Good",excellent:"Excellent"},maintenanceUpToDate:"All maintenance up to date - Click to view",chamberLightOn:"Turn on chamber light",chamberLightOff:"Turn off chamber light",files:"Files",browseFiles:"Browse printer files",autoOffAfterPrint:"Auto power-off after print",autoOffExecuted:"Auto-off was executed - turn printer on to reset",hmsErrors:"HMS Errors",viewHmsErrors:"View {{count}} HMS error(s)",resume:"Resume",pause:"Pause",stop:"Stop",camera:"Camera",skipObject:"Skip Object",reconnect:"Reconnect",forceRefresh:"Force Refresh",forceRefreshSuccess:"Refresh requested",mqttDebug:"MQTT Debug",printerInformation:"Printer Information",copyToClipboard:"Copy",copied:"Copied!",state:"State",wifiSignalLabel:"WiFi Signal",developerMode:"Developer Mode",enabled:"Enabled",disabled:"Disabled",addedOn:"Added",sdCard:"SD Card",inserted:"Inserted",notInserted:"Not inserted",totalPrintHours:"Print Hours",activeNozzle:"Active: {{nozzle}} nozzle",nozzleRack:"Nozzle Rack",nozzleDocked:"Docked",nozzleMounted:"Mounted",nozzleActive:"Active",nozzleIdle:"Idle",nozzleDiameter:"Diameter",nozzleType:"Type",nozzleStatus:"Status",nozzleFilament:"Filament",nozzleWear:"Wear",nozzleMaxTemp:"Max Temp",nozzleSerial:"Serial",nozzleHardenedSteel:"Hardened Steel",nozzleStainlessSteel:"Stainless Steel",nozzleTungstenCarbide:"Tungsten Carbide",nozzleFlow:"Flow",nozzleHighFlow:"High Flow",nozzleStandardFlow:"Standard",firmwareUpdate:"Firmware Update",firmwareInstructions:"On the printer's touchscreen, go to",firmwareNav:"Navigate to",settings:"Settings",firmware:"Firmware",discoverPrinters:"Discover Printers",searching:"Searching...",manualEntry:"Manual Entry",addFromCloud:"Add from Cloud",toast:{printerDeleted:"Printer deleted",missingSpoolAssignment:"Print started on {{printer}}. Missing spool assignment for: {{slots}}",printerAdded:"Printer added",printerUpdated:"Printer updated",failedToDelete:"Failed to delete printer",failedToAdd:"Failed to add printer",failedToUpdate:"Failed to update printer",commandSent:"Command sent",failedToSendCommand:"Failed to send command",turnedOn:"{{name}} turned on",failedToPowerOn:"Failed to power on {{name}}",scriptTriggered:"Script triggered",printStopped:"Print stopped",printPaused:"Print paused",printResumed:"Print resumed",referenceDeleted:"Reference deleted",detectionAreaSaved:"Detection area saved",failedToRunScript:"Failed to run script",failedToStopPrint:"Failed to stop print",failedToPausePrint:"Failed to pause print",failedToResumePrint:"Failed to resume print",failedToControlChamberLight:"Failed to control chamber light",failedToSetSpeed:"Failed to set print speed",failedToUpdateSetting:"Failed to update setting",failedToSkipObjects:"Failed to skip objects",failedToRereadRfid:"Failed to re-read RFID",failedToCheckPlate:"Failed to check plate",failedToUpdateLabel:"Failed to update label",failedToDeleteReference:"Failed to delete reference",failedToSaveDetectionArea:"Failed to save detection area",plateCheckEnabled:"Plate check enabled",plateCheckDisabled:"Plate check disabled",calibrationSaved:"Calibration saved!",calibrationFailed:"Calibration failed",rfidRereadInitiated:"RFID re-read initiated"},connection:{connected:"Connected",offline:"Offline"},plateStatus:{markCleared:"Mark plate as cleared",cleared:"Plate Clear",notCleared:"Plate not Clear",inUse:"Plate in Use"},queue:{inQueue:"{{count}} print in queue",inQueue_plural:"{{count}} prints in queue"},controls:"Controls",rfid:{reread:"Re-read RFID"},bedJog:{title:"Move build plate",bed:"Bed",step:"Step (mm)",up:"Move plate up",down:"Move plate down",disabledWhilePrinting:"Disabled while printing",notHomedTitle:"Printer is not homed",notHomedMessage:"The Z axis has not been homed since the last print. Home Z first for safe positioning, or move anyway — soft endstops will be bypassed.",homeZ:"Home Z",moveAnyway:"Move anyway",homingStarted:"Homing Z axis…"},permission:{noAdd:"You do not have permission to add printers",noEdit:"You do not have permission to edit printers",noDelete:"You do not have permission to delete printers",noControl:"You do not have permission to control printers",noFiles:"You do not have permission to access printer files",noAmsRfid:"You do not have permission to re-read AMS RFID",noSmartPlugControl:"You do not have permission to control smart plugs",noCamera:"You do not have permission to view cameras"},modal:{addTitle:"Add Printer",editTitle:"Edit Printer",myPrinter:"My Printer",selectModel:"Select model...",locationGroup:"Location / Group (optional)",locationPlaceholder:"e.g., Workshop, Office, Basement",autoArchiveLabel:"Auto-archive completed prints",fromPrinterSettings:"From printer settings",modelOptional:"Model (optional)",saveChanges:"Save Changes"},skipObjects:{tooltip:"Skip objects",onlyWhilePrinting:"Skip objects (only while printing)",requiresMultiple:"Skip objects (requires 2+ objects)",title:"Skip Objects",matchIdsInfo:"Match IDs with your printer display",printerShowsIds:"The printer screen shows object IDs on the build plate",skipSelected:"Skip Selected",skipping:"Skipping...",noObjectsSelected:"No objects selected",selectObjectsToSkip:"Select objects you want to skip from the current print",skipped:"skipped",objectsSkipped:"Objects skipped",activeCount:"{{count}} active",waitForLayer:"Wait for layer 2+ to skip objects (currently layer {{layer}})",skip:"Skip",confirmTitle:"Skip Object?",confirmMessage:'Are you sure you want to skip "{{name}}"? This cannot be undone.'},confirm:{deleteTitle:"Delete Printer",deleteMessage:'Are you sure you want to delete "{{name}}"? This will remove all connection settings.',deleteArchivesNote:"All print history for this printer will be permanently deleted.",keepArchivesNote:"Print history will be kept but no longer associated with this printer.",stopTitle:"Stop Print",stopMessage:'Are you sure you want to stop the current print on "{{name}}"? This will cancel the print job.',stopButton:"Stop Print",pauseTitle:"Pause Print",pauseMessage:'Are you sure you want to pause the current print on "{{name}}"?',pauseButton:"Pause Print",resumeTitle:"Resume Print",resumeMessage:'Are you sure you want to resume the print on "{{name}}"?',resumeButton:"Resume Print",powerOnTitle:"Power On Printer",powerOnMessage:'Are you sure you want to turn ON the power for "{{name}}"?',powerOnButton:"Power On",powerOffTitle:"Power Off Printer",powerOffMessage:'Are you sure you want to turn OFF the power for "{{name}}"?',powerOffWarning:'WARNING: "{{name}}" is currently printing! Are you sure you want to turn OFF the power? This will interrupt the print and may damage the printer.',powerOffButton:"Power Off"},bulk:{select:"Select",selectAll:"Select All",selectByLocation:"Select by Location",selected:"{{count}} selected",actions:{stop:"Stop",pause:"Pause",resume:"Resume",clearPlate:"Clear Bed",clearHMS:"Clear Notifications"},confirm:{stopTitle:"Stop {{count}} Prints",stopMessage:"This will cancel active prints on {{count}} printer(s). This action cannot be undone.",stopButton:"Stop All",pauseTitle:"Pause {{count}} Prints",pauseMessage:"This will pause active prints on {{count}} printer(s).",pauseButton:"Pause All",clearPlateTitle:"Clear {{count}} Print Beds",clearPlateMessage:"This will clear the print bed on {{count}} printer(s) and may trigger queued jobs.",clearPlateButton:"Clear All"},success:"{{action}} completed on {{count}} printer(s)",partial:"{{succeeded}} succeeded, {{failed}} failed",noneApplicable:"No selected printers are in the right state for this action",selectByState:"Select by State"},discovery:{title:"Discover Printers",searching:"Searching...",scanning:"Scanning...",scanProgress:"Scanning... {{scanned}}/{{total}}",foundPrinters:"Found {{count}} printer(s)",noPrintersFound:"No printers found",noPrintersFoundSubnet:"No printers found in the specified subnet.",noPrintersFoundNetwork:"No printers found on the network.",allConfigured:"All discovered printers are already configured.",alreadyAdded:"Already added",select:"Select",manualEntry:"Manual Entry",addFromCloud:"Add from Cloud",subnetToScan:"Subnet to scan",dockerNote:"Docker detected. Enter your printer's subnet in CIDR notation. Requires network_mode: host in docker-compose.yml.",scanSubnet:"Scan Subnet for Printers",discoverNetwork:"Discover Printers on Network",scanningSubnet:"Scanning subnet for Bambu printers...",scanningNetwork:"Scanning network...",serialRequired:"Serial required",unknown:"Unknown",failedToStart:"Failed to start discovery"},drying:{start:"Start Drying",stop:"Stop Drying",temperature:"Temperature",duration:"Duration",hours:"hours",timeRemaining:"{{time}} left",active:"Drying",notSupported:"Drying not supported",powerRequired:"Connect AMS power adapter to enable drying",startingDrying:"Starting drying...",stoppingDrying:"Stopping drying...",rotateTray:"Rotate spool during drying"},filaments:"Filaments",openCameraOverlay:"Open camera overlay",openCameraWindow:"Open camera in new window",firmwareUpdateAvailable:"Firmware update available: {{current}} → {{latest}}",firmwareUpToDate:"Firmware {{version}} — Up to date",firmwareUpdateButton:"Update",plateDetection:{noPermission:"You do not have permission to update printers",enabledClick:"Plate check enabled - Click to disable",disabledClick:"Plate check disabled - Click to enable",manageCalibration:"Manage plate detection calibration",calibrationRequired:"Calibration Required",calibrationInstructions:"Please ensure the build plate is completely empty, then click Calibrate.",calibrationDescription:"Calibration captures a reference image of the empty plate. Future checks will compare against this reference to detect objects.",calibrationTip:"Tip: You can store up to 5 calibrations for different plates. The system automatically uses the best match when checking.",plateEmpty:"Plate appears empty",objectsDetected:"Objects detected on plate",confidence:"Confidence",difference:"Difference",analysisPreview:"Analysis preview:",analysisLegend:"Green box = detection area, Red overlay = differences from calibration",savedReferences:"Saved References ({{count}}/{{max}})",deleteReference:"Delete reference",labelPlaceholder:"Label...",clickToEdit:"{{label}} - Click to edit",clickToAddLabel:"Click to add label"},speed:{title:"Print Speed",silent:"Silent (50%)",standard:"Standard (100%)",sport:"Sport (124%)",ludicrous:"Ludicrous (166%)"},airduct:{title:"Airduct Mode",cooling:"Cooling",heating:"Heating"},noSdCard:"No SD",door:{open:"Open",closed:"Closed"},fans:{partCooling:"Part Cooling Fan",auxiliary:"Auxiliary Fan",chamber:"Chamber Fan"},clickToViewHmsErrors:"Click to view HMS errors",estimatedCompletion:"Estimated completion time",plateNumber:"Plate {{number}}",slotOptions:"Slot options",amsPopup:{friendlyName:"AMS Name",friendlyNamePlaceholder:"e.g. AMS Friendly Name",serialNumber:"Serial Number",firmwareVersion:"Firmware",save:"Save",clear:"Clear",noEditPermission:"You do not have permission to rename AMS units"},firmwareModal:{title:"Firmware Update",titleUpToDate:"Firmware Info",currentVersion:"Current:",latestVersion:"Latest:",releaseNotes:"Release Notes",checkingPrereqs:"Checking prerequisites...",sdCardReady:"SD card ready. Click below to upload firmware.",uploadedSuccess:"Firmware uploaded to SD card!",applyInstructions:"To apply the update on your printer:",step1:"On the printer's touchscreen, go to Settings",step2:"Navigate to Firmware",step3:"Select Update from SD card",step4:"The update will take 10-20 minutes",done:"Done",starting:"Starting...",uploadFirmware:"Upload Firmware",uploadFailed:"Failed to start upload: {{error}}",uploadedToast:"Firmware uploaded! Trigger update from printer screen.",availableVersions:"Available versions",usable:"Usable",unavailable:"Unavailable",installed:"Installed",newerBadge:"newer",olderBadge:"older",currentBadge:"current"},accessCodePlaceholder:"Leave empty to keep current",roi:{title:"Detection Area (ROI)",xStart:"X Start",yStart:"Y Start",width:"Width",height:"Height",instruction:"Adjust the detection area to focus on the build plate. The green box in the preview shows the current area."},developerModeWarning:"Developer LAN mode is not enabled on: {{names}}. Some features may not work.",howToEnable:"How to enable",incompatibleFile:"This file was sliced for {{slicedFor}}, but this printer is a {{printerModel}}",dropNotPrintable:"Only .gcode and .gcode.3mf files can be printed",dropToPrint:"Drop to print",cannotPrint:"Printer busy"},archives:{title:"Print Archives",searchPlaceholder:"Search archives...",filterByPrinter:"Filter by printer",filterByStatus:"Filter by status",sortBy:"Sort by",sortNewest:"Newest first",sortOldest:"Oldest first",sortName:"Name",sortDuration:"Duration",sortLargest:"Largest first",sortSmallest:"Smallest first",sortSize:"Size",noArchives:"No archives found",noArchivesSearch:"No archives match your search",originalPrintNotVisible:"Original print not visible - try clearing filters",noArchivesYet:"No archives yet",prints:"prints",pagination:{showing:"Showing",to:"to",of:"of",show:"Show",page:"Page",all:"All"},loadingArchives:"Loading archives...",releaseToUpload:"Release to upload",showAll:"Show all",showFavoritesOnly:"Show favorites only",gridView:"Grid view",listView:"List view",calendarView:"Calendar view",logView:"Print Log",manageTags:"Manage Tags",showFailedPrints:"Show failed prints",hideFailedPrints:"Hide failed prints",hideDuplicates:"Hide Duplicates",viewOriginalPrint:"Click to view original print (#{{id}})",printTime:"Print Time",filamentUsed:"Filament Used",cost:"Cost",reprint:"Reprint",preview:"Preview",deleteArchive:"Delete Archive",deleteConfirm:"Are you sure you want to delete this archive?",favorite:"Favorite",unfavorite:"Remove from favorites",viewDetails:"View Details",status:{completed:"Completed",failed:"Failed",stopped:"Stopped"},toast:{source3mfAttached:"Source 3MF attached: {{filename}}",failedUploadSource3mf:"Failed to upload source 3MF",source3mfRemoved:"Source 3MF removed",failedRemoveSource3mf:"Failed to remove source 3MF",f3dAttached:"F3D attached: {{filename}}",failedUploadF3d:"Failed to upload F3D",f3dRemoved:"F3D removed",failedRemoveF3d:"Failed to remove F3D",timelapseAttached:"Timelapse attached: {{filename}}",timelapseAlreadyAttached:"Timelapse already attached",noMatchingTimelapse:"No matching timelapse found",failedScanTimelapse:"Failed to scan for timelapse",failedAttachTimelapse:"Failed to attach timelapse",timelapseRemoved:"Timelapse removed",failedRemoveTimelapse:"Failed to remove timelapse",timelapseUploaded:"Timelapse uploaded: {{filename}}",failedUploadTimelapse:"Failed to upload timelapse",archiveDeleted:"Archive deleted",failedDeleteArchive:"Failed to delete archive",addedToFavorites:"Added to favorites",removedFromFavorites:"Removed from favorites",projectUpdated:"Project updated",failedUpdateProject:"Failed to update project",linkCopied:"Link copied to clipboard",failedCopyLink:"Failed to copy link",photoDeleted:"Photo deleted",failedDeletePhoto:"Failed to delete photo",failedDeleteArchives:"Failed to delete archives",failedUpdateFavorites:"Failed to update favorites",exportDownloaded:"Export downloaded",exportFailed:"Export failed"},menu:{print:"Print",schedule:"Schedule",openInBambuStudio:"Open in Slicer",slice:"Slice",externalLink:"External Link",viewOnMakerWorld:"View on MakerWorld",preview3d:"3D Preview",viewTimelapse:"View Timelapse",scanForTimelapse:"Scan for Timelapse",uploadTimelapse:"Upload Timelapse",removeTimelapse:"Remove Timelapse",downloadSource3mf:"Download Source 3MF",uploadSource3mf:"Upload Source 3MF",replaceSource3mf:"Replace Source 3MF",removeSource3mf:"Remove Source 3MF",uploadF3d:"Upload F3D",replaceF3d:"Replace F3D",downloadF3d:"Download F3D",removeF3d:"Remove F3D",download:"Download",copyDownloadLink:"Copy Download Link",qrCode:"QR Code",viewPhotos:"View Photos",viewPhotosCount:"View Photos ({{count}})",projectPage:"Project Page",addToFavorites:"Add to Favorites",removeFromFavorites:"Remove from Favorites",edit:"Edit",goToProject:"Go to Project: {{name}}",addToProject:"Add to Project",removeFromProject:"Remove from Project",loading:"Loading...",noProjectsAvailable:"No projects available",select:"Select",deselect:"Deselect",delete:"Delete"},permission:{noReprint:"You do not have permission to reprint this archive",noAddToQueue:"You do not have permission to add to queue",noUpdateArchives:"You do not have permission to update archives",noUploadFiles:"You do not have permission to upload files",noDownload:"You do not have permission to download archives",noCopyLink:"You do not have permission to copy download links",noDelete:"You do not have permission to delete this archive",noCreate:"You do not have permission to create archives"},card:{previousPlate:"Previous plate",nextPlate:"Next plate",plateNumber:"Plate {{index}}",moreOptions:"Right-click for more options",addToFavorites:"Add to favorites",removeFromFavorites:"Remove from favorites",cancelled:"cancelled",failed:"failed",duplicate:"duplicate",duplicateTitle:"This model has been printed before",openSource3mf:"Open source 3MF in Bambu Studio (right-click for more options)",downloadF3d:"Download Fusion 360 design file",viewTimelapse:"View timelapse",viewPhoto:"View 1 photo",viewPhotos:"View {{count}} photos",openFolder:"Open folder: {{name}}",slicedFile:"Sliced file - ready to print",sourceFile:"Source file only - no AMS mapping available",gcode:"GCODE",source:"SOURCE",project:"Project: {{name}}",estimated:"Estimated: {{time}}",actual:"Actual: {{time}}",accuracy:"Accuracy: {{percent}}%",filament:"{{weight}}g",layer:"{{count}} layer",layers:"{{count}} layers",object:"{{count}} object",objects:"{{count}} objects",slicedFor:"Sliced for {{model}}",uploadedBy:"Uploaded By",noPermissionReprint:"You do not have permission to reprint",noFileForReprint:"No 3MF file available — the file could not be downloaded from the printer when the print was recorded",noPermissionEdit:"You do not have permission to edit archives",noPermissionDelete:"You do not have permission to delete archives",reprint:"Reprint",schedulePrint:"Schedule Print",schedule:"Schedule",openInBambuStudio:"Open in Slicer",openInBambuStudioToSlice:"Open in Slicer to slice",slice:"Slice",externalLink:"External Link",makerWorld:"MakerWorld: {{designer}}",viewProject:"View project",noExternalLink:"No external link",preview3d:"3D Preview",download:"Download",edit:"Edit",delete:"Delete"},modal:{deleteArchive:"Delete Archive",deleteConfirm:'Are you sure you want to delete "{{name}}"? This action cannot be undone.',deleteButton:"Delete",removeSource3mf:"Remove Source 3MF",removeSource3mfConfirm:'Are you sure you want to remove the source 3MF file from "{{name}}"? This will delete the original slicer project file.',removeButton:"Remove",removeF3d:"Remove F3D",removeF3dConfirm:'Are you sure you want to remove the Fusion 360 design file from "{{name}}"?',removeTimelapse:"Remove Timelapse",removeTimelapseConfirm:'Are you sure you want to remove the timelapse video from "{{name}}"?',timelapse:"{{name}} - Timelapse",selectTimelapse:"Select Timelapse",selectTimelapseDesc:"No auto-match found. Select the timelapse for this print:",deleteArchives:"Delete Archives",deleteArchivesConfirm:"Are you sure you want to delete {{count}} archive(s)? This action cannot be undone.",deleteCount:"Delete {{count}}"},page:{title:"Archives",printsCount:"{{filtered}} of {{total}} prints",dropFilesHere:"Drop .3mf files here",releaseToUpload:"Release to upload",only3mfSupported:"Only .3mf files are supported",close:"Close",selected:"{{count}} selected",selectAll:"Select All",tags:"Tags",project:"Project",favorite:"Favorite",delete:"Delete",toggledFavorites:"Toggled favorites for {{count}} archive(s)",failedUpdateFavorites:"Failed to update favorites",archivesDeleted:"{{count}} archive(s) deleted",failedDeleteArchives:"Failed to delete archives",photoDeleted:"Photo deleted",failedDeletePhoto:"Failed to delete photo"},list:{name:"Name",printer:"Printer",date:"Date",size:"Size",actions:"Actions",hasTimelapse:"Has timelapse"},log:{date:"Date",printName:"Print Name",printer:"Printer",user:"User",status:"Status",duration:"Duration",filament:"Filament",allPrinters:"All Printers",allUsers:"All Users",allStatuses:"All Statuses",cancelled:"Cancelled",skipped:"Skipped",dateFrom:"From",dateTo:"To",noEntries:"No print log entries found",showing:"Showing {{count}} of {{total}} entries",rowsPerPage:"Rows",page:"Page",prev:"Prev",next:"Next",clearLog:"Clear Log",clearLogTitle:"Clear Print Log",clearLogConfirm:"All print log entries will be permanently deleted. Archives and queue items are not affected. This action cannot be undone. Are you sure?",clearLogButton:"Clear All",cleared:"{{count}} log entries cleared",clearFailed:"Failed to clear print log"}},queue:{title:"Print Queue",subtitle:"Schedule and manage your print jobs",addToQueue:"Add to Queue",print:"Print",reprint:"Re-print",schedulePrint:"Schedule Print",editQueueItem:"Edit Queue Item",printToPrinters:"Print to {{count}} Printers",queueToPrinters:"Queue to {{count}} Printers",queueSelectedPlates:"Queue {{count}} Plates",selectAllPlates:"Select All {{count}} Plates",deselectAll:"Deselect All",printQueued:"Print queued",itemsQueued:"{{count}} items queued",sending:"Sending...",sendingProgress:"Sending {{current}}/{{total}}...",adding:"Adding...",addingProgress:"Adding {{current}}/{{total}}...",savingProgress:"Saving {{current}}/{{total}}...",clearQueue:"Clear Queue",clearHistory:"Clear History",emptyQueue:"Queue is empty",position:"Position",scheduledTime:"Scheduled Time",moveUp:"Move Up",moveDown:"Move Down",startNow:"Start Now",printingInProgress:"Printing in progress...",viewArchive:"View archive",viewInFileManager:"View in File Manager",itemCount:"{{count}} item",itemCount_plural:"{{count}} items",dragToReorder:"Drag to reorder (ASAP only)",reorderHint:"Position only affects ASAP items. Scheduled items run at their set time.",sjf:{label:"SJF",tooltip:"Shortest Job First — scheduler prioritizes shorter prints"},addedBy:"Added by {{name}}",nextInQueue:"Next in queue",clearPlate:"Clear Plate & Start Next",clearPlateSuccess:"Plate cleared — ready for next print",plateReady:"Plate cleared — ready for next print",plateNumber:"Plate {{index}}",quantity:"Quantity",quantityHint:"Creates {{count}} queue items",activeBatches:"Active Batches",batchProgress:"{{completed}} of {{total}} completed",cancelBatch:"Cancel Remaining",batchCancelled:"Remaining batch items cancelled",cancelBatchConfirmTitle:"Cancel Batch",cancelBatchConfirmMessage:"Cancel all remaining pending items in this batch?",batch:"Batch",sections:{currentlyPrinting:"Currently Printing",queued:"Queued",history:"History"},status:{pending:"Pending",waiting:"Waiting",printing:"Printing",paused:"Paused",completed:"Completed",failed:"Failed",skipped:"Skipped",cancelled:"Cancelled"},summary:{printing:"Printing",queued:"Queued",totalTime:"Total Queue Time",totalWeight:"Total Queue Weight",history:"History"},filter:{allPrinters:"All Printers",unassigned:"Unassigned",allStatus:"All Status",allLocations:"All Locations",any:"Any"},sort:{byPosition:"Sort by Position",byName:"Sort by Name",byPrinter:"Sort by Printer",bySchedule:"Sort by Schedule",byDate:"Sort by Date",ascendingOldest:"Ascending (oldest first)",descendingNewest:"Descending (newest first)"},badges:{staged:"Staged",requiresPrevious:"Requires previous success",autoPowerOff:"Auto power off",gcodeInjection:"G-code"},empty:{title:"No prints scheduled",description:'Schedule a print from the Archives page using the "Schedule" option in the context menu, or drag and drop files to get started.'},time:{asap:"ASAP",overdue:"Overdue",now:"Now",lessThanMinute:"In less than a minute",inMinutes:"In {{count}} min",inHours:"In {{count}} hours"},actions:{stopPrint:"Stop Print",startPrint:"Start Print",requeue:"Re-queue"},bulkEdit:{title:"Edit {{count}} Item",title_plural:"Edit {{count}} Items",description:"Only changed settings will be applied to selected items.",printer:"Printer",noChange:"— No change —",queueOptions:"Queue Options",staged:"Staged (manual start)",autoPowerOff:"Auto power off after print",requirePrevious:"Require previous success",printOptions:"Print Options",bedLevelling:"Bed levelling",flowCalibration:"Flow calibration",vibrationCalibration:"Vibration calibration",layerInspection:"First layer inspection",timelapse:"Timelapse",useAms:"Use AMS",applyChanges:"Apply Changes",selectAll:"Select All",deselectAll:"Deselect All",selected:"{{count}} selected",editSelected:"Edit Selected",cancelSelected:"Cancel Selected"},confirm:{cancelTitle:"Cancel Scheduled Print",cancelMessage:'Are you sure you want to cancel "{{name}}"?',stopTitle:"Stop Print",stopMessage:'Are you sure you want to stop the current print "{{name}}"? This will cancel the print job on the printer.',removeTitle:"Remove from History",removeMessage:'Are you sure you want to remove "{{name}}" from the queue history?',clearHistoryTitle:"Clear History",clearHistoryMessage:"Are you sure you want to remove all {{count}} item(s) from the history?",cancelButton:"Cancel Print",stopButton:"Stop Print",thisPrint:"this print",thisItem:"this item"},toast:{cancelled:"Queue item cancelled",cancelFailed:"Failed to cancel item",removed:"Queue item removed",removeFailed:"Failed to remove item",stopped:"Print stopped",stopFailed:"Failed to stop print",released:"Print released to queue",startFailed:"Failed to start print",reorderFailed:"Failed to reorder queue",historyCleared:"Cleared {{count}} history item(s)",clearHistoryFailed:"Failed to clear history",updateFailed:"Failed to update items",bulkCancelled:"Cancelled {{count}} item(s)",bulkCancelFailed:"Failed to cancel items"},timeline:{listView:"List",timelineView:"Timeline",unassigned:"Unassigned",noData:"No scheduled prints for this day",allDoneBy:"All prints estimated done by {{time}}",staged:"Staged",filterAll:"Show All",filterPrinting:"Printing",filterQueued:"Queued",time:{anyMoment:"any moment",minutesLeft:"{{minutes}}m left",hoursLeft:"{{hours}}h left",hoursMinutesLeft:"{{hours}}h {{minutes}}m left"},day:{previous:"Previous day",next:"Next day",today:"Today"}},permissions:{noStopPrint:"You do not have permission to stop prints",noStartPrint:"You do not have permission to start prints",noEdit:"You do not have permission to edit this queue item",noCancel:"You do not have permission to cancel this queue item",noRequeue:"You do not have permission to re-queue items",noRemove:"You do not have permission to remove this queue item",noClearHistory:"You do not have permission to clear all history",noEditItems:"You do not have permission to edit queue items",noCancelItems:"You do not have permission to cancel queue items"}},backgroundDispatch:{unknownFile:"Unknown file",unknownPrinter:"Unknown printer",startingPrints:"Starting prints",progressSummary:"{{complete}}/{{total}} complete • Dispatched: {{dispatched}} • Processing: {{processing}}",expandDetails:"Expand dispatch details",collapseDetails:"Collapse dispatch details",dismissToast:"Dismiss dispatch toast",cancelDispatchJob:"Cancel dispatch job",cancel:"Cancel",cancelling:"Cancelling…",status:{dispatched:"Dispatched",processing:"Processing",completed:"Completed",failed:"Failed",cancelled:"Cancelled"},toast:{cancellingUpload:"Cancelling upload...",cancelled:"Dispatch cancelled",cancelFailed:"Failed to cancel dispatch",completeWithFailures:"Background dispatch complete: {{completed}} succeeded, {{failed}} failed",completeSuccess:"Background dispatch complete: {{completed}} succeeded",printStartedRemaining:"{{completed}} print(s) started, {{remaining}} more sending..."}},stats:{title:"Dashboard",subtitle:"Drag widgets to rearrange. Click the eye icon to hide.",overview:"Overview",totalPrints:"Total Prints",successRate:"Success Rate",totalPrintTime:"Total Print Time",printTime:"Print Time",totalFilament:"Total Filament Used",filamentUsed:"Filament Used",filamentCost:"Filament Cost",totalCost:"Total Cost",energyUsed:"Energy Used",energyCost:"Energy Cost",energyWarmingUpTooltip:"Energy tracking is still collecting hourly snapshots. Date-range totals will become accurate once at least one snapshot exists before the selected range. Early values may undercount.",averagePrintTime:"Average Print Time",printsPerDay:"Prints per Day",byPrinter:"By Printer",printsByPrinter:"Prints by Printer",byMaterial:"By Material",byMonth:"By Month",last7Days:"Last 7 Days",last30Days:"Last 30 Days",last90Days:"Last 90 Days",allTime:"All Time",quickStats:"Quick Stats",printActivity:"Print Activity",filamentTypes:"Filament Types",filamentTrends:"Filament Trends",failureAnalysis:"Failure Analysis",timeAccuracy:"Time Accuracy",successful:"Successful:",failed:"Failed:",perfectEstimate:"100% = perfect estimate",noTimeAccuracyData:"No time accuracy data yet",noFilamentData:"No filament data available",noPrinterData:"No printer data available",noPrintData:"No print data available",noPrintDataLast30Days:"No print data in the last 30 days",failureReasons:"Failure Reasons",topFailureReasons:"Top Failure Reasons",failedPrintsCount:"{{failed}} / {{total}} prints failed",lastWeekRate:"Last week: {{rate}}%",resetLayout:"Reset Layout",recalculateCosts:"Recalculate Costs",recalculateCostsHint:"Recalculate all archive costs using current filament prices",exportStats:"Export Stats",exportAsCsv:"Export as CSV",exportAsExcel:"Export as Excel",hiddenCount:"{{count}} Hidden",exportDownloaded:"Export downloaded",exportFailed:"Export failed",layoutReset:"Layout reset",recalculatedCosts:"Recalculated costs for {{count}} archives",recalculateFailed:"Failed to recalculate costs",loadingStats:"Loading statistics...",noPermissionResetLayout:"You do not have permission to reset layout",noPermissionRecalculate:"You do not have permission to recalculate costs",noPrintDataInRange:"No print data in selected range",periodFilament:"Period Filament",periodCost:"Period Cost",avgPerPrint:"Avg per Print",usageOverTime:"Usage Over Time",filamentByWeight:"Weight",printDuration:"Print Duration",printerUtilization:"Printer Utilization",filamentSuccess:"Success by Material",printHabits:"Print Habits",printTimeOfDay:"Print Time of Day",colorDistribution:"Color Distribution",noColorData:"No color data available",records:"Records",longestPrint:"Longest Print",heaviestPrint:"Heaviest Print",mostExpensivePrint:"Most Expensive",busiestDay:"Busiest Day",successStreak:"Success Streak",streakPrint:"consecutive print",streakPrints:"{{count}} consecutive prints",printerStats:"Printer Stats",hours:"hours",avgPrints:"Avg. prints",noArchiveData:"No print data available",filamentByTime:"Time",avgWeight:"Avg. weight",avgTime:"Avg. time",filamentByPrints:"Prints",timeframe:{today:"Today","this-week":"This Week","this-month":"This Month","last-7":"Last 7 Days","last-30":"Last 30 Days","last-90":"Last 90 Days","this-year":"This Year","all-time":"All Time",custom:"Custom Range",from:"From",to:"To"},allUsers:"All Users",noUser:"No User (System)",filterByUser:"Filter by User"},maintenance:{title:"Maintenance",overview:"Overview",allOk:"All maintenance up to date",dueCount:"{{count}} item due",dueCount_plural:"{{count}} items due",warningCount:"{{count}} warning",warningCount_plural:"{{count}} warnings",totalPrintTime:"Total Print Time",nextMaintenance:"Next Maintenance",nothingDue:"Nothing due",tasks:"Tasks",lastPerformed:"Last performed",interval:"Interval",hoursRemaining:"{{hours}}h remaining",hoursOverdue:"{{hours}}h overdue",markDone:"Mark as Done",performMaintenance:"Perform Maintenance",history:"History",noHistory:"No maintenance history",editPrintHours:"Edit Print Hours",currentHours:"Current Hours",statusTab:"Status",settingsTab:"Settings",overdueCount:"{{count}} overdue",dueSoonCount:"{{count}} due soon",dueSoon:"Due soon",allGood:"All good",overdueBy:"Overdue by {{duration}}",dueIn:"Due in {{duration}}",timeLeft:"{{duration}} left",day:"1 day",days:"{{count}} days",week:"1 week",weeks:"{{count}} weeks",month:"1 month",months:"{{count}} months",year:"1 year",maintenanceTypes:"Maintenance Types",maintenanceTypesDescription:"System types and your custom maintenance tasks",addCustomType:"Add Custom Type",restoreDefaults:"Restore Default Tasks",intervalType:"Interval Type",intervalValue:"Interval ({{type}})",icon:"Icon",documentationLink:"Documentation Link (optional)",assignToPrinters:"Assign to Printers",selectAtLeastOnePrinter:"Select at least one printer",addType:"Add Type",custom:"Custom",printHours:"Print Hours",calendarDays:"Calendar Days",exampleName:"e.g., Replace HEPA Filter",viewDocumentation:"View documentation",timeBasedInterval:"Time-based interval",intervalOverrides:"Interval Overrides",intervalOverridesDescription:"Customize intervals for specific printers",assignedToPrinters:"Assigned to printers:",noPrintersAssigned:"No printers assigned",addPrinterShort:"Add:",printersAssignedClick:"{{count}} printer(s) assigned - click to manage",removeFromPrinter:"Remove from this printer",types:{lubricateCarbonRods:"Lubricate Carbon Rods",lubricateRails:"Lubricate Linear Rails",cleanNozzle:"Clean Nozzle/Hotend",checkBelts:"Check Belt Tension",cleanBuildPlate:"Clean Build Plate",checkExtruder:"Check Extruder Gears",checkCooling:"Check Cooling Fans",generalInspection:"General Inspection",cleanCarbonRods:"Clean Carbon Rods",lubricateSteelRods:"Lubricate Steel Rods",cleanSteelRods:"Clean Steel Rods",cleanLinearRails:"Clean Linear Rails",checkPtfeTube:"Check PTFE Tube",replaceHepaFilter:"Replace HEPA Filter",replaceCarbonFilter:"Replace Carbon Filter",lubricateLeftNozzleRail:"Lubricate Left Nozzle Rail"},maintenanceComplete:"Maintenance marked as complete",typeUpdated:"Maintenance type updated",typeDeleted:"Maintenance type deleted",defaultsRestored:"Restored {{count}} default task(s)",printHoursUpdated:"Print hours updated",printerAssigned:"Printer assigned",printerRemoved:"Printer removed",deleteTypeConfirm:'Delete "{{name}}"?',deleteSystemTypeTitle:"Delete default maintenance task?",deleteSystemTypeMessage:'Are you sure you want to delete the default maintenance task "{{name}}"?',noPermissionUpdate:"You do not have permission to update maintenance items",noPermissionPerform:"You do not have permission to perform maintenance",noPermissionEditTypes:"You do not have permission to edit maintenance types",noPermissionDeleteTypes:"You do not have permission to delete maintenance types",noPermissionEditHours:"You do not have permission to edit print hours",noPermissionRemovePrinter:"You do not have permission to remove printer assignments",noPermissionAssignPrinter:"You do not have permission to assign printers",noPermissionEditIntervals:"You do not have permission to edit intervals",configureSettings:"Configure maintenance types and intervals"},settings:{title:"Settings",general:"General",tabs:{general:"General",smartPlugs:"Smart Plugs",notifications:"Notifications",queue:"Workflow",filament:"Filament",network:"Network",apiKeys:"API Keys",virtualPrinter:"Virtual Printer",spoolbuddy:"SpoolBuddy",failureDetection:"Failure Detection",users:"Authentication",backup:"Backup",emailAuth:"Email Authentication",ldap:"LDAP",twoFa:"Two-Factor Auth",oidc:"SSO / OIDC"},spoolbuddy:{infoTitle:"SpoolBuddy devices",infoBody:"SpoolBuddy kiosks register themselves automatically via heartbeat. Unregister a device here if it is no longer in use or if a stale duplicate was left behind by a daemon crash.",duplicatesTitle:"{{count}} devices registered",duplicatesBody:"Only the first registered device is used by the kiosk UI. If one of these is a stale duplicate from a crash, unregister it — an online device will re-register itself on its next heartbeat.",empty:"No SpoolBuddy devices registered yet.",online:"Online",offline:"Offline",unregister:"Unregister",unregisterSuccess:"Device unregistered",unregisterError:"Failed to unregister device",confirmTitle:"Unregister SpoolBuddy device?",confirmBody:'This will remove "{{hostname}}" ({{deviceId}}) from the database. If the device is online, it will re-register itself on its next heartbeat.',ipAddress:"IP address",firmware:"Firmware",lastSeen:"Last seen",daemonUptime:"Daemon uptime",systemUptime:"System uptime",never:"never",nfc:"NFC",scale:"Scale",cpuTemp:"CPU temp",memory:"Memory",disk:"Disk",update:"Update",updateConfirmTitle:"Update Spoolbuddy daemon?",updateConfirmBody:'Trigger a software update on "{{hostname}}"? The daemon will restart once the update is applied.',restartBrowser:"Restart Browser",restartBrowserConfirmTitle:"Restart kiosk browser?",restartBrowserConfirmBody:'Restart the kiosk browser on "{{hostname}}"? The display will blank briefly.',restartDaemon:"Restart Daemon",restartDaemonConfirmTitle:"Restart Spoolbuddy daemon?",restartDaemonConfirmBody:'Restart the Spoolbuddy daemon on "{{hostname}}"? The device will go offline for a few seconds.',reboot:"Reboot",rebootConfirmTitle:"Reboot device?",rebootConfirmBody:'Reboot "{{hostname}}"? The device will be offline for around a minute.',shutdown:"Shutdown",shutdownConfirmTitle:"Shutdown device?",shutdownConfirmBody:'Shutdown "{{hostname}}"? You will need physical access to power it back on.',commandConfirm:"Confirm",commandQueued:"Command queued",commandError:"Failed to send command"},ldap:{title:"LDAP Authentication",enabledDesc:"LDAP authentication is enabled",disabledDesc:"LDAP authentication is disabled",disabledHint:"Configure and save LDAP settings below, then enable.",enabled:"LDAP authentication enabled",disabled:"LDAP authentication disabled",feature1:"Users can login with LDAP credentials",feature2:"Local admin account remains as fallback",feature3:"LDAP groups are mapped to BamBuddy groups on login",serverConfig:"LDAP Server Configuration",serverUrl:"Server URL",serverUrlHint:"Use ldaps:// for SSL or ldap:// with StartTLS",security:"Security",securityHint:"StartTLS upgrades a plain connection to TLS. LDAPS uses TLS from the start.",bindDn:"Bind DN (Service Account)",bindPassword:"Bind Password",searchBase:"Search Base DN",userFilter:"User Search Filter",userFilterHint:"{username} is replaced with the login username. Use (uid={username}) for OpenLDAP.",autoProvision:"Auto-provision users",autoProvisionHint:"Automatically create a BamBuddy account on first LDAP login",defaultGroup:"Default group",defaultGroupNone:"— None (no fallback) —",defaultGroupHint:"Fallback group assigned when an LDAP user authenticates but is not listed in any mapped LDAP group. Leave empty to leave unmapped users without permissions.",groupMapping:"Group Mapping (JSON)",groupMappingHint:"Map LDAP group DNs to BamBuddy groups. Available groups: ",testConnection:"Test Connection",settingsSaved:"LDAP settings saved",errors:{serverRequired:"LDAP server URL is required",searchBaseRequired:"Search base DN is required",enableAuthFirst:"Enable authentication first",configureLdapFirst:"Save LDAP settings first"}},email:{smtpSettings:"SMTP Configuration",smtpHost:"SMTP Server",smtpPort:"SMTP Port",security:"Security",authentication:"Authentication",username:"Username",password:"Password",fromEmail:"From Email",fromName:"From Name",testConnection:"Test SMTP Connection",testRecipient:"Test Recipient Email",sendTest:"Send Test Email",sending:"Sending...",save:"Save Settings",saving:"Saving...",advancedAuth:"Advanced Authentication",advancedAuthEnabled:"Advanced Authentication is enabled",advancedAuthEnabledDesc:"Email-based user management features are active. New users will receive auto-generated passwords via email, and users can reset their passwords through the forgot password feature.",advancedAuthDisabled:"Advanced Authentication is disabled",advancedAuthDisabledDesc:"Enable advanced authentication to activate email-based features for user management.",enable:"Enable",disable:"Disable",feature1:"Passwords are auto-generated and emailed to new users",feature2:"Users can login with username or email",feature3:"Forgot password feature is available",feature4:"Admins can reset user passwords via email",errors:{requiredFields:"Please fill in all required fields",usernameRequired:"Username is required when authentication is enabled",enterTestEmail:"Please enter a test email address",smtpServerAndEmail:"Please fill in SMTP Server and From Email before testing",usernamePasswordRequired:"Username and Password are required when authentication is enabled",configureSmtpFirst:"Please configure and test SMTP settings first",enableAuthFirst:"Please enable authentication first to use email-based features."},success:{settingsSaved:"SMTP settings saved successfully"},securityOptions:{starttls:"STARTTLS (Port 587)",ssl:"SSL/TLS (Port 465)",none:"None (Port 25)"},authOptions:{enabled:"Enabled",disabled:"Disabled"}},appearance:"Appearance",notifications:"Notifications",smartPlugs:"Smart Plugs",spoolman:"Spoolman",updates:"Updates",language:"Language",languageDescription:"Select your preferred language",theme:"Theme",themeLight:"Light",themeDark:"Dark",themeSystem:"System",defaultView:"Default View",defaultViewDescription:"Page to show when opening the app",checkForUpdates:"Check for Updates",autoUpdate:"Auto Update",currentVersion:"Current Version",latestVersion:"Latest Version",upToDate:"You are up to date",updateAvailable:"Update available",notificationLanguage:"Notification Language",notificationLanguageDescription:"Language for push notifications",bedCooledThreshold:"Bed Cooled Threshold",bedCooledThresholdDescription:"Temperature below which the bed is considered cooled after a print",userNotificationsEnabled:"User Notifications",userNotificationsEnabledDescription:"Enable the user notifications menu and email notifications for print job events. Requires Advanced Authentication.",userNotificationsDisabledHint:"Enable Advanced Authentication to use user notifications.",notificationProviders:"Notification Providers",addProvider:"Add Provider",editProvider:"Edit Provider",providerType:"Provider Type",testNotification:"Test Notification",testSuccess:"Test notification sent successfully",testFailed:"Failed to send test notification",quietHours:"Quiet Hours",quietHoursDescription:"Do not disturb during these hours",quietHoursStart:"Start",quietHoursEnd:"End",events:{title:"Notification Events",printStart:"Print Started",printComplete:"Print Completed",printFailed:"Print Failed",printStopped:"Print Stopped",printProgress:"Progress Milestones",printProgressDescription:"Notify at 25%, 50%, 75%",printerOffline:"Printer Offline",printerError:"Printer Error",filamentLow:"Low Filament",maintenanceDue:"Maintenance Due",maintenanceDueDescription:"Notify when maintenance is needed"},smartPlug:{title:"Smart Plugs",add:"Add Smart Plug",edit:"Edit Smart Plug",name:"Name",ipAddress:"IP Address",linkedPrinter:"Linked Printer",autoOn:"Auto Power On",autoOnDescription:"Turn on when print starts",autoOff:"Auto Power Off",autoOffDescription:"Turn off after print completes",offDelay:"Off Delay",offDelayMinutes:"Minutes after print",offDelayTemp:"When nozzle below temperature",currentState:"Current State",turnOn:"Turn On",turnOff:"Turn Off"},filamentTracking:"Filament Tracking",filamentTrackingDesc:"Choose how to track your filament spools. You can use the built-in inventory or connect an external Spoolman server.",filamentChecks:"Filament checks",disableFilamentWarnings:"Disable filament warnings",disableFilamentWarningsDesc:"Don't show warnings about insufficient filament when printing or queueing",preferLowestFilament:"Prefer lowest remaining filament",preferLowestFilamentDesc:"When multiple spools match, use the one with the least filament remaining",trackingModeBuiltIn:"Built-in Inventory",trackingModeBuiltInDesc:"RFID auto-matching and usage tracking included",trackingModeSpoolmanDesc:"External filament management server",builtInFeatureRfid:"Automatically detects Bambu Lab RFID spools in AMS",builtInFeatureUsage:"Tracks filament consumption per print",builtInFeatureCatalog:"Manage spools, colors, and K-factor profiles",builtInFeatureThirdParty:"Third-party spools can be assigned to inventory spools",amsSyncButton:"Sync Weights from AMS",amsSyncTitle:"Sync Spool Weights from AMS",amsSyncMessage:"This will overwrite all inventory spool weights with the current AMS remain% values from connected printers. Use this to recover from corrupted weight data. Printers must be online.",amsSyncing:"Syncing...",amsSyncSuccess:"{{synced}} spool(s) synced, {{skipped}} skipped",amsSyncError:"Failed to sync weights from AMS",spoolmanUrl:"Spoolman URL",spoolmanUrlHint:"URL of your Spoolman server (e.g., http://localhost:7912)",spoolmanConnected:"Connected",spoolmanDisconnected:"Disconnected",status:"Status",connect:"Connect",disconnect:"Disconnect",howSyncWorks:"How Sync Works",syncInfoRfidOnly:"Only official Bambu Lab spools with RFID are synced",syncInfoAutoCreate:"New spools are auto-created in Spoolman on first sync",syncInfoThirdPartySkipped:"Non-Bambu Lab spools (third-party, refilled) are skipped",linkingExistingSpools:"Linking Existing Spools",linkingExistingSpoolsDesc:'To link existing Spoolman spools to your AMS, hover over an AMS slot and click "Link to Spoolman".',syncMode:"Sync Mode",syncModeAuto:"Automatic",syncModeManual:"Manual Only",syncModeAutoDesc:"AMS data syncs automatically when changes are detected",syncModeManualDesc:"Only sync when manually triggered",syncAmsData:"Sync AMS Data",syncAmsDataDesc:"Manually sync printer AMS data to Spoolman",allPrinters:"All Printers",noDefaultPrinter:"No default (ask each time)",sidebarOrder:"Sidebar order",saveThumbnails:"Save thumbnails",captureFinishPhoto:"Capture finish photo",noPrintersConfigured:"No printers configured",archiveMode:{always:"Always create archive entry",never:"Never create archive entry",ask:"Ask each time"},checkForUpdatesLabel:"Check for updates",checkPrinterFirmware:"Check printer firmware",includeBetaUpdates:"Include beta versions",includeBetaUpdatesDesc:"Notify about beta and prerelease versions when checking for updates",enableRetry:"Enable retry",homeAssistantDescription:"Control smart plugs via Home Assistant",environmentManagedLabel:"(Environment Managed)",autoEnabledViaEnv:"Automatically enabled via environment variables",urlFromEnvReadOnly:"Value set by HA_URL environment variable (read-only)",tokenFromEnvReadOnly:"Value set by HA_TOKEN environment variable (read-only)",mqttConnectedTo:"Connected to",prometheusDescription:"Expose printer data in Prometheus format",noSmartPlugsTitle:"No smart plugs configured",noSmartPlugsDescription:"Add a Tasmota-based smart plug to track energy usage and automate power control.",noProvidersTitle:"No providers configured",noProvidersDescription:"Add a provider to receive alerts.",noTemplatesAvailable:"No templates available. Restart the backend to seed default templates.",apiPermissionView:"View printer status and queue",apiPermissionEdit:"Add and remove items from print queue",apiKeysEmptyTitle:"No API keys",apiKeysEmptyDescription:"Create an API key to integrate with external services.",noUsersFound:"No users found",noGroupsFound:"No groups found",noGroupsAvailable:"No groups available",passwordsDoNotMatch:"Passwords do not match",systemGroupWarning:"System group names cannot be changed",authDisabledTitle:"Authentication is Disabled",authDisabledFeature1:"Require login to access the system",authDisabledFeature2:"Create multiple users with group-based permissions",authDisabledFeature3:"Control access with 50+ granular permissions",userHasCreated:"This user has created:",userItemsQuestion:"What would you like to do with these items?",deleteUserConfirm:"Are you sure you want to delete this user?",actionCannotBeUndone:"This action cannot be undone.",addFirstSmartPlug:"Add Your First Smart Plug",providers:"Providers",log:"Log",testAll:"Test All",testResults:"Test Results",testPassedCount:"{{count}} passed",testFailedCount:"{{count}} failed",messageTemplates:"Message Templates",messageTemplatesDescription:"Customize notification messages for each event.",apiKeys:"API Keys",apiKeysDescription:"Create API keys for external integrations and webhooks.",createKey:"Create Key",apiKeyCreated:"API Key Created Successfully",apiKeyCopyWarning:"Copy this key now - it won't be shown again!",useInApiBrowser:"Use in API Browser",createNewApiKey:"Create New API Key",keyName:"Key Name",keyNamePlaceholder:"e.g., Home Assistant, OctoPrint",readStatus:"Read Status",readStatusDescription:"View printer status and queue",manageQueue:"Manage Queue",manageQueueDescription:"Add and remove items from print queue",controlPrinter:"Control Printer",controlPrinterDescription:"Pause, resume, and stop prints",unnamedKey:"Unnamed Key",lastUsed:"Last used",read:"Read",control:"Control",createFirstKey:"Create Your First Key",webhookEndpoints:"Webhook Endpoints",webhookApiKeyHint:"Use your API key in the X-API-Key header.",webhook:{getAllStatus:"Get all printer status",getSpecificStatus:"Get specific printer status",addToQueue:"Add to print queue",pausePrint:"Pause print",resumePrint:"Resume print",stopPrint:"Stop print"},apiBrowser:"API Browser",apiBrowserDescription:"Explore and test all available API endpoints.",apiKeyForTesting:"API Key for Testing",apiKeyPlaceholder:"Paste your API key here to test authenticated endpoints...",apiKeyHint:"This key will be sent as X-API-Key header with requests.",deleteApiKeyTitle:"Delete API Key",deleteApiKeyMessage:"Are you sure you want to delete this API key? Any integrations using this key will stop working.",deleteKey:"Delete Key",amsDisplayThresholds:"AMS Display Thresholds",amsThresholdsDescription:"Configure color thresholds for AMS humidity and temperature indicators.",humidity:"Humidity",goodGreen:"Good (green)",fairOrange:"Fair (orange)",aboveFairBad:"Above fair threshold shows as red (bad)",fairAlsoDryingThreshold:"This threshold is also used to trigger auto-drying when enabled",temperature:"Temperature",goodBlue:"Good (blue)",aboveFairHot:"Above fair threshold shows as red (hot)",historyRetention:"History Retention",keepSensorHistory:"Keep sensor history for",historyRetentionDescription:"Older humidity and temperature data will be automatically deleted",defaultPrintOptions:"Default Print Options",defaultPrintOptionsDescription:"Set default values for print options when starting new prints. These can be overridden per print in the print dialog.",defaultBedLevelling:"Bed Levelling",defaultBedLevellingDesc:"Auto-level bed before print",defaultFlowCali:"Flow Calibration",defaultFlowCaliDesc:"Calibrate extrusion flow",defaultVibrationCali:"Vibration Calibration",defaultVibrationCaliDesc:"Reduce ringing artifacts",defaultLayerInspect:"First Layer Inspection",defaultLayerInspectDesc:"AI inspection of first layer",defaultTimelapse:"Timelapse",defaultTimelapseDesc:"Record timelapse video",staggeredStart:"Staggered Start",staggeredStartDescription:"Default group size and interval when staggering multi-printer batch starts. Can be overridden per batch in the print modal.",plateClear:"Plate-Clear Confirmation",requirePlateClear:"Require plate-clear confirmation",requirePlateClearDescription:'When enabled, the scheduler waits for per-printer plate-clear confirmation before starting queued prints on printers with finished jobs. Disabling this also hides the plate status badge and the "Mark plate as cleared" button on printer cards.',gcodeInjection:"G-code Injection",gcodeInjectionDescription:'Configure custom G-code to inject at the start and/or end of prints for auto-print systems like Farmloop, SwapMod, AutoClear, and Printflow 3D. Snippets are configured per printer model and applied when "Inject G-code" is enabled on a queue item.',gcodeInjectionNoPrinters:"No printers found. Add printers to configure G-code snippets.",gcodeStartLabel:"Start G-code",gcodeEndLabel:"End G-code",gcodeStartPlaceholder:"G-code prepended before the print starts...",gcodeEndPlaceholder:"G-code appended after the print ends...",staggerGroupSize:"Group size",staggerGroupSizeHelp:"Printers to start simultaneously per group",staggerInterval:"Interval (minutes)",staggerIntervalHelp:"Delay between each group starting",queueDrying:"Queue Auto-Drying",queueDryingDescription:"Automatically dry AMS filament when printer is idle between queued prints. Uses humidity threshold above to trigger drying.",queueDryingEnabled:"Enable auto-drying",queueDryingEnabledDescription:"Start AMS drying automatically when printer is idle and humidity is above threshold",queueDryingBlock:"Wait for drying to complete",queueDryingBlockDescription:"Block the print queue until drying finishes. When off, prints take priority over drying.",ambientDryingEnabled:"Ambient drying",ambientDryingEnabledDescription:"Automatically dry filament on idle printers when humidity exceeds threshold, even without queued prints.",dryingPresets:"Drying Presets",dryingPresetsDescription:"Temperature and duration per filament type. AMS 2 Pro uses lower temps, AMS-HT supports higher temps.",dryingFilament:"Filament",printModal:"Print Modal",expandCustomMapping:"Expand custom mapping by default",expandCustomMappingDescription:"When printing to multiple printers, show per-printer AMS mapping expanded",authentication:"Authentication",authEnabledDescription:"Your instance is secured with user authentication",authDisabledDescription:"Enable to require login and manage user access",authDisabledMessage:"Enable authentication to create user accounts, manage permissions, and secure your Bambuddy instance.",enableAuthentication:"Enable Authentication",currentUser:"Current User",changePassword:"Change Password",admin:"Admin",users:"Users",addUser:"Add User",groups:"Groups",addGroup:"Add Group",system:"System",noDescription:"No description",userCount:"{{count}} users",permissionCount:"{{count}} permissions",createUser:"Create User",username:"Username",enterUsername:"Enter username",password:"Password",enterPassword:"Enter password (min 6 characters)",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm password",viewReleaseOnGitHub:"View release on GitHub",turnAllPlugsOn:"Turn all plugs on",turnAllPlugsOff:"Turn all plugs off",clearNotificationLogs:"Clear Notification Logs",clearLogsMessage:"This will permanently delete all notification logs older than 30 days. This action cannot be undone.",clearLogs:"Clear Logs",resetUiPreferences:"Reset UI Preferences",resetUiPreferencesMessage:"This will reset all UI preferences to defaults: sidebar order, theme, dashboard layout, view modes, and sorting preferences. Your printers, archives, and server settings will NOT be affected. The page will reload after clearing.",resetPreferences:"Reset Preferences",deleteGroupTitle:"Delete Group",deleteGroupMessage:"Are you sure you want to delete this group? Users in this group will lose these permissions.",deleteGroup:"Delete Group",disableAuthenticationTitle:"Disable Authentication",disableAuthenticationMessage:"Are you sure you want to disable authentication? This will make your Bambuddy instance accessible without login. All users will remain in the database but authentication will be disabled.",disableAuthentication:"Disable Authentication",configureBambuddy:"Configure Bambuddy",systemDefault:"System Default",archiveSettings:"Archive Settings",newWindow:"New Window",embeddedOverlay:"Embedded Overlay",preferredSlicer:"Preferred Slicer",preferredSlicerDescription:"Choose which slicer application to open files with",externalCameras:"External Cameras",costTracking:"Cost Tracking",printsOnly:"Prints Only",totalConsumption:"Total Consumption",dataManagement:"Data Management",storageUsage:"Storage Usage",storageUsageDescription:"Breakdown of data usage by category",storageUsageTotal:"Total",storageUsageErrors:"Errors",storageUsageOtherBreakdown:"Other (includes static assets, scripts, and configuration files)",storageUsageSystem:"System",storageUsageData:"Data",storageUsageUnavailable:"Storage usage information unavailable",clearNotificationLogsDescription:"Delete notification logs older than 30 days",resetUiPreferencesDescription:"Reset sidebar order, theme, view modes, and layout preferences. Printers, archives, and settings are not affected.",enableHomeAssistant:"Enable Home Assistant",enableMqtt:"Enable MQTT",useTls:"Use TLS",enableMetricsEndpoint:"Enable Metrics Endpoint",availableMetrics:"Available Metrics",editUser:"Edit User",deleteUserTitle:"Delete User",groupName:"Group Name",leaveEmptyForAnonymous:"Leave empty for anonymous",leaveEmptyForNoAuth:"Leave empty for no authentication",enterNewPassword:"Enter new password",confirmNewPassword:"Confirm new password",enterGroupName:"Enter group name",enterDescriptionOptional:"Enter description (optional)",enterCurrentPassword:"Enter current password",enterNewPasswordMin6:"Enter new password (min 6 characters)",toast:{keyCopied:"Key copied to clipboard",copyFailed:"Failed to copy key",keyAddedToBrowser:"Key added to API Browser",clearLogsFailed:"Failed to clear logs",uiPreferencesReset:"UI preferences reset. Refreshing...",authDisabled:"Authentication disabled successfully",authDisableFailed:"Failed to disable authentication",apiKeyCreated:"API key created",apiKeyDeleted:"API key deleted",userCreated:"User created successfully",userUpdated:"User updated successfully",userDeleted:"User deleted successfully",groupCreated:"Group created successfully",groupUpdated:"Group updated successfully",groupDeleted:"Group deleted successfully",fillRequiredFields:"Please fill in all required fields",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters",enterGroupName:"Please enter a group name",settingsSaved:"Settings saved",cameraSettingsSaved:"Camera settings saved",enterCameraUrl:"Please enter a camera URL",passwordChanged:"Password changed successfully",connectionFailed:"Connection failed",testFailed:"Test failed",cameraConnected:"Camera connected{{resolution}}"},testConnection:"Test Connection",catalog:{spoolCatalog:"Spool Catalog",spoolCatalogDescription:"Empty spool weights by brand/type. Used for automatic weight lookup when adding spools.",searchCatalog:"Search catalog...",addNewEntry:"Add New Entry",namePlaceholder:"Name (e.g., Bambu Lab - Plastic)",weight:"Weight",type:"Type",default:"Default",custom:"Custom",noMatch:"No entries match your search",empty:"No entries in catalog",deleteEntry:"Delete Entry",deleteConfirm:'Are you sure you want to delete "{{name}}"?',resetCatalog:"Reset Catalog",resetConfirm:"Reset catalog to defaults? This will remove all custom entries.",loadFailed:"Failed to load spool catalog",nameWeightRequired:"Name and weight are required",entryAdded:"Entry added",addFailed:"Failed to add entry",entryUpdated:"Entry updated",updateFailed:"Failed to update entry",entryDeleted:"Entry deleted",deleteFailed:"Failed to delete entry",resetSuccess:"Catalog reset to defaults",resetFailed:"Failed to reset catalog",exported:"Exported {{count}} entries",imported:"Imported {{added}} entries ({{skipped}} skipped)",importFailed:"Failed to import: invalid JSON format",exportTooltip:"Export catalog to JSON",importTooltip:"Import catalog from JSON",resetTooltip:"Reset to defaults",selectedCount:"{{count}} selected",deleteSelected:"Delete Selected",bulkDeleteConfirm:"Are you sure you want to delete {{count}} entries?",bulkDeleted:"Deleted {{count}} entries",bulkDeleteFailed:"Failed to delete entries"},colorCatalog:{title:"Color Catalog",description:"Filament colors by manufacturer/material. Used for automatic color lookup when adding spools.",searchColors:"Search colors...",allManufacturers:"All manufacturers",addNewColor:"Add New Color",manufacturer:"Manufacturer",colorName:"Color Name",hex:"Hex",materialOptional:"Material (optional)",showing:"Showing {{filtered}} of {{total}} colors",noMatch:"No colors match your search",empty:"No colors in catalog",deleteColor:"Delete Color",deleteConfirm:'Are you sure you want to delete "{{name}}"?',resetCatalog:"Reset Color Catalog",resetConfirm:"Reset catalog to defaults? This will remove all custom colors.",sync:"Sync",starting:"Starting...",syncTooltip:"Sync from FilamentColors.xyz (2000+ colors, may take a minute)",loadFailed:"Failed to load color catalog",fieldsRequired:"Manufacturer, color name, and hex color are required",colorAdded:"Color added",addFailed:"Failed to add color",colorUpdated:"Color updated",updateFailed:"Failed to update color",colorDeleted:"Color deleted",deleteFailed:"Failed to delete color",resetSuccess:"Color catalog reset to defaults",resetFailed:"Failed to reset catalog",syncUpToDate:"Already up to date ({{count}} colors checked)",syncComplete:"Added {{added}} new colors ({{skipped}} already existed)",syncError:"Sync error",syncFailed:"Failed to sync from FilamentColors.xyz",exported:"Exported {{count}} colors",imported:"Imported {{added}} colors ({{skipped}} skipped)",importFailed:"Failed to import: invalid JSON format",selectedCount:"{{count}} selected",deleteSelected:"Delete Selected",bulkDeleteConfirm:"Are you sure you want to delete {{count}} colors?",bulkDeleted:"Deleted {{count}} colors",bulkDeleteFailed:"Failed to delete colors"},dateFormat:"Date Format",dateFormatUs:"US (MM/DD/YYYY)",dateFormatEu:"EU (DD/MM/YYYY)",dateFormatIso:"ISO (YYYY-MM-DD)",timeFormat:"Time Format",timeFormat12:"12-hour (3:30 PM)",timeFormat24:"24-hour (15:30)",defaultPrinter:"Default Printer",defaultPrinterDescription:"Pre-select this printer for uploads, reprints, and other operations.",slicerBambuStudio:"Bambu Studio",slicerOrcaSlicer:"OrcaSlicer",sidebarOrderDescription:"Drag items in the sidebar to reorder. Reset to default order here.",setDefault:"Set Default",sidebarOrderSetDefaultHint:"Set default applies the current menu order to users who haven't customized theirs.",sidebarDefaultSet:"Default menu order has been set.",sidebarDefaultCleared:"Default menu order cleared.",sidebarDefaultFailed:"Failed to set default menu order.",reset:"Reset",darkMode:"Dark Mode",lightMode:"Light Mode",active:"(active)",background:"Background",accent:"Accent",style:"Style",bgNeutral:"Neutral",bgWarm:"Warm",bgCool:"Cool",bgOled:"OLED Black",bgSlate:"Slate Blue",bgForest:"Forest Green",accentGreen:"Green",accentTeal:"Teal",accentBlue:"Blue",accentOrange:"Orange",accentPurple:"Purple",accentRed:"Red",styleClassic:"Classic",styleGlow:"Glow",styleVibrant:"Vibrant",themeToggleHint:"Toggle between dark and light mode using the sun/moon icon in the sidebar.",autoArchivePrints:"Auto-archive prints",autoArchiveDescription:"Automatically save 3MF files when prints complete",saveThumbnailsDescription:"Extract and save preview images from 3MF files",captureFinishPhotoDescription:"Take a photo from printer camera when print completes",ffmpegNotInstalled:"ffmpeg not installed",ffmpegRequired:"Camera capture requires ffmpeg. Install it via brew install ffmpeg (macOS) or apt install ffmpeg (Linux).",camera:"Camera",cameraViewMode:"Camera View Mode",cameraOverlayDescription:"Camera opens in a resizable overlay on the main screen",cameraWindowDescription:"Camera opens in a separate browser window",externalCamerasDescription:"Configure external cameras to replace the built-in printer camera. Supports MJPEG streams, RTSP, HTTP snapshots, and USB cameras (V4L2). When enabled, the external camera is used for live view and finish photos.",cameraPlaceholderUsb:"Device path (/dev/video0)",cameraPlaceholderUrl:"Camera URL (rtsp://... or http://...)",cameraTypeMjpeg:"MJPEG Stream",cameraTypeRtsp:"RTSP Stream",cameraTypeSnapshot:"HTTP Snapshot",cameraTypeUsb:"USB Camera (V4L2)",cameraRotation:"Rotation",test:"Test",connected:"Connected",disconnected:"Disconnected",currency:"Currency",defaultFilamentCost:"Default filament cost (per kg)",electricityCost:"Electricity cost per kWh",energyDisplayMode:"Energy display mode",energyModePrintDescription:"Dashboard shows sum of energy used during prints",energyModeTotalDescription:"Dashboard shows lifetime energy from smart plugs",fileManager:"File Manager",createArchiveEntry:"Create Archive Entry When Printing",createArchiveEntryDescription:"When printing from File Manager, optionally create an archive entry",lowDiskSpaceWarning:"Low Disk Space Warning",lowDiskSpaceDescription:"Show warning when free disk space falls below this threshold",printerFirmware:"Printer Firmware",checkFirmwareDescription:"Check for printer firmware updates from Bambu Lab",bambuddySoftware:"Bambuddy Software",autoCheckDescription:"Automatically check for new versions on startup",checkNow:"Check now",updateAvailableVersion:"Update available: v{{version}}",releaseNotes:"Release Notes",updateViaDocker:"Update via Docker Compose:",installUpdate:"Install Update",latestVersionRunning:"You're running the latest version",failedToCheckUpdates:"Failed to check for updates: {{error}}",backupRestore:"Backup & Restore",backupRestoreDescription:"Export/import settings and configure GitHub backup",goToBackup:"Go to Backup",externalUrl:"External URL",externalUrlDescription:"The external URL where Bambuddy is accessible. Used for notification images and external integrations.",bambuddyUrl:"Bambuddy URL",externalUrlHint:"Include protocol and port (e.g., http://192.168.1.100:8000)",ftpRetry:"FTP Retry",ftpRetryDescription:"Retry FTP operations when printer WiFi is unreliable. Applies to 3MF downloads, print uploads, timelapse downloads, and firmware updates.",autoRetryDescription:"Automatically retry failed FTP operations",retryAttempts:"Retry attempts",retryDelay:"Retry delay",connectionTimeout:"Connection timeout",time_one:"{{count}} time",time_other:"{{count}} times",second_one:"{{count}} second",second_other:"{{count}} seconds",nSeconds:"{{count}} seconds",increaseForWeakWifi:"Increase for printers with weak WiFi",homeAssistant:"Home Assistant",homeAssistantFullDescription:"Connect to Home Assistant to control smart plugs via HA's REST API. Supports switch, light, input_boolean, and script entities.",homeAssistantUrl:"Home Assistant URL",longLivedAccessToken:"Long-Lived Access Token",haTokenHint:"Create a token in HA: Profile → Long-Lived Access Tokens → Create Token",connectionSuccessful:"Connection Successful",connectionFailed:"Connection Failed",haConnectionSuccess:"Successfully connected to Home Assistant.",haConnectionFailed:"Failed to connect to Home Assistant.",mqttPublishing:"MQTT Publishing",mqttDescription:"Publish BamBuddy events to an external MQTT broker for integration with Node-RED, Home Assistant, and other automation systems.",mqttEnableDescription:"Publish events to external MQTT broker",brokerHostname:"Broker hostname",port:"Port",usernameOptional:"Username (optional)",passwordOptional:"Password (optional)",topicPrefix:"Topic prefix",topicPrefixHint:"Topics will be: {{prefix}}/printers//status, etc.",prometheusMetrics:"Prometheus Metrics",prometheusEndpointDescription:"Expose printer metrics at /api/v1/metrics for Prometheus/Grafana monitoring.",bearerTokenOptional:"Bearer Token (optional)",bearerTokenHint:"If set, requests must include Authorization: Bearer ",metricsConnectionStatus:"Connection status",metricsPrinterState:"Printer state (idle/printing/etc)",metricsPrintProgress:"Print progress 0-100%",metricsBedTemp:"Bed temperature",metricsNozzleTemp:"Nozzle temperature",metricsPrintsTotal:"Total prints by result",metricsMore:"...and more (layers, fans, queue, filament usage)",smartPlugsDescription:"Connect smart plugs (Tasmota or Home Assistant) to automate power control and track energy usage for your printers.",allOn:"All On",allOff:"All Off",addSmartPlug:"Add Smart Plug",energySummary:"Energy Summary",currentPower:"Current Power",plugsOnline:"{{reachable}}/{{total}} plugs online",today:"Today",yesterday:"Yesterday",total:"Total",enablePlugsForSummary:"Enable plugs to see energy summary",addNotificationProvider:"Add",systemBadge:"(System)",creating:"Creating...",changing:"Changing...",deleteUserAndItems:"Delete user AND their items",deleteUserKeepItems:"Delete user, keep items (become ownerless)",ok:"OK",twoFa:{totpTitle:"Authenticator App (TOTP)",totpDesc:"Use an authenticator app like Google Authenticator, Aegis or Authy.",emailOtpTitle:"Email OTP",emailOtpDesc:"Send a one-time code to {{email}} when you log in.",emailOtpNoEmail:"Add an email address to your account to enable this method.",addEmailFirst:"Your account has no email address. Ask an admin to add one before enabling Email OTP.",setupTotp:"Set up Authenticator App",setupAuthApp:"Set up Authenticator App",setupInstructions:"Scan the QR code below with your authenticator app, then confirm with a code.",manualEntry:"Can't scan? Enter this secret manually:",scannedContinue:"I've scanned the code — continue",enterCodeToConfirm:"Enter the 6-digit code from your authenticator app to confirm setup.",activate:"Activate",disableTotp:"Disable Authenticator",disableConfirmHint:"Enter a valid TOTP code or a backup code to disable the authenticator.",totpDisabled:"Authenticator app disabled.",emailOtpEnabled:"Email OTP enabled.",emailOtpDisabled:"Email OTP disabled.",smtpRequired:"Please configure and test SMTP settings first.",invalidCode:"Invalid code. Please try again.",enableEmailOtp:"Enable Email OTP",disableEmailOtp:"Disable Email OTP",emailSetupEnterCode:"A verification code has been sent to your email address. Enter it below to confirm you own this inbox.",verifyAndEnable:"Verify & Enable",emailDisablePasswordHint:"Enter your account password to confirm disabling email OTP.",passwordPlaceholder:"Enter your password",backupCodesTitle:"Save your backup codes",backupCodesWarning:"Save these codes somewhere safe. Each code can only be used once and they will not be shown again.",backupCodesRemaining:"{{count}} backup codes remaining",savedCodes:"I've saved my codes",regenBackup:"Regenerate Backup Codes",regenBackupHint:"Enter your current TOTP code to generate 10 new backup codes. All existing backup codes will be invalidated.",newBackupCodes:"New backup codes",linkedAccounts:"Linked SSO Accounts",linkedAccountsDesc:"These external identity providers are linked to your account.",oidcUnlinked:"Account unlinked."},oidc:{title:"SSO / OIDC Providers",desc:"Configure OpenID Connect providers to allow single sign-on via external identity providers.",addProvider:"Add Provider",newProvider:"New Provider",empty:"No OIDC providers configured yet.",created:"Provider created.",updated:"Provider updated.",deleted:"Provider deleted.",deleteTitle:"Delete Provider",deleteMessage:'Delete "{{name}}"? All linked user accounts will be disconnected.',form:{name:"Display Name",issuerUrl:"Issuer URL",clientId:"Client ID",clientSecret:"Client Secret",scopes:"Scopes",iconUrl:"Icon URL (optional)",enabled:"Enabled",autoCreate:"Auto-create users",autoCreateDesc:"Automatically create a local account on first login.",autoLink:"Auto-link existing accounts",autoLinkDesc:"Link existing local accounts by matching email on first login.",secretHint:"leave blank to keep current",secretPlaceholder:"new secret"}}},notification:{printStarted:{title:"Print Started",body:"{{printer}}: {{filename}} has started printing"},printCompleted:{title:"Print Completed",body:"{{printer}}: {{filename}} completed successfully"},printFailed:{title:"Print Failed",body:"{{printer}}: {{filename}} has failed"},printStopped:{title:"Print Stopped",body:"{{printer}}: {{filename}} was stopped"},printProgress:{title:"Print Progress",body:"{{printer}}: {{filename}} is {{percent}}% complete"},printerOffline:{title:"Printer Offline",body:"{{printer}} is offline"},printerError:{title:"Printer Error",body:"{{printer}}: {{error}}"},filamentLow:{title:"Low Filament",body:"{{printer}}: Filament is running low"},maintenanceDue:{title:"Maintenance Due",body:"{{printer}}: {{items}} need attention"}},errors:{generic:"Something went wrong",networkError:"Network error. Please check your connection.",notFound:"Not found",unauthorized:"Unauthorized",serverError:"Server error",validationError:"Please check your input",printerConnectionFailed:"Failed to connect to printer",saveFailed:"Failed to save changes",deleteFailed:"Failed to delete",loadFailed:"Failed to load data"},hmsErrors:{title:"Errors - {{name}}",noErrors:"No errors",viewOnWiki:"View on Bambu Lab Wiki",clearInstructions:"Clear errors on the printer to dismiss them here.",clearErrors:"Clear Errors",clearSuccess:"HMS errors cleared",clearFailed:"Failed to clear HMS errors"},mqttDebug:{title:"MQTT Debug Log",searchPlaceholder:"Search topic or payload...",noMessages:"No messages logged yet",startLoggingHint:'Click "Start Logging" to begin capturing MQTT messages',noMessagesMatch:"No messages match your filter",adjustFilterHint:"Try adjusting your search or filter criteria",incoming:"Incoming",outgoing:"Outgoing",loggingStopped:"Logging stopped",loggingActive:"Logging active - messages will auto-refresh",startLogging:"Start Logging",stopLogging:"Stop Logging",clearLog:"Clear Log",topic:"Topic",timestamp:"Timestamp",direction:"Direction",all:"All"},printerFiles:{title:"File Manager",storageUsed:"Used:",storageFree:"Free:",filterPlaceholder:"Filter files...",deleteButton:"Delete",deleteFiles:"Delete {{count}} Files",deleteFileConfirm:'Delete "{{name}}"? This cannot be undone.',deleteFilesConfirm:"Delete {{count}} selected files? This cannot be undone.",noFiles:"No files on printer",loadingFiles:"Loading files...",failedToLoad:"Failed to load files",toast:{filesDeleted:"Deleted {{count}} file(s)",deleteFailed:"Delete failed: {{error}}"}},confirm:{delete:"Are you sure you want to delete this?",unsavedChanges:"You have unsaved changes. Are you sure you want to leave?",clearQueue:"Are you sure you want to clear the queue?"},login:{title:"Bambuddy Login",subtitle:"Sign in to your account",username:"Username",usernamePlaceholder:"Enter your username",usernameOrEmail:"Username or Email",usernameOrEmailPlaceholder:"Username or @ Email",password:"Password",passwordPlaceholder:"Enter your password",signIn:"Sign in",signingIn:"Logging in...",forgotPassword:"Forgot your password?",loginSuccess:"Logged in successfully",loginFailed:"Login failed",enterCredentials:"Please enter username and password",enterEmail:"Please enter your email address",oidcLoginFailed:"OIDC login failed",oidcErrors:{providerError:"The identity provider returned an error",missingParameters:"OIDC callback is missing required parameters",invalidState:"OIDC state is invalid or has already been used",stateExpired:"OIDC login session expired — please try again",providerNotFound:"OIDC provider not found",discoveryFailed:"Failed to fetch OIDC discovery document",invalidDiscovery:"OIDC discovery document is invalid",networkError:"Network error during OIDC token exchange",badResponse:"Unexpected response during OIDC token exchange",noIdToken:"OIDC provider did not return an ID token",validationFailed:"OIDC token validation failed",nonceMismatch:"OIDC nonce mismatch — possible replay attack",missingSubClaim:"OIDC token is missing the sub claim",noLinkedAccount:"No local account is linked to this OIDC identity",accountInactive:"Your account is inactive",userResolutionFailed:"Failed to resolve your account",internalError:"An internal error occurred during OIDC login",tokenExchangeFailed:"OIDC token exchange failed"},forgotPasswordTitle:"Forgot Password",forgotPasswordMessage:"If you've forgotten your password, please contact your system administrator to reset it.",forgotPasswordEmailMessage:"Enter your email address and we'll send you a new password.",emailAddress:"Email Address",emailPlaceholder:"your.email@example.com",cancel:"Cancel",sending:"Sending...",sendResetEmail:"Send Reset Email",howToReset:"How to reset your password:",resetStep1:"Contact your Bambuddy administrator",resetStep2:"Ask them to reset your password in User Management",resetStep3:"They can set a new temporary password for you",resetStep4:"Log in with the new password and change it in Settings",gotIt:"Got it",resetPassword:{title:"Set New Password",subtitle:"Enter and confirm your new password below.",newPassword:"New Password",newPasswordPlaceholder:"At least 8 characters",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Repeat new password",saving:"Saving…",submit:"Set New Password",backToLogin:"Back to login",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 8 characters",resetFailed:"Password reset failed. The link may have expired."},twoFA:{title:"Two-Factor Authentication",subtitle:"Your account is protected with 2FA. Enter the verification code below.",methodAuthenticator:"Authenticator App",methodEmail:"Email Code",methodBackup:"Backup Code",instructionsTotp:"Open your authenticator app and enter the 6-digit code for Bambuddy.",instructionsEmail:"A 6-digit code has been sent to your email address. It expires in 10 minutes.",instructionsEmailNotSent:"Click the button below to receive a verification code via email.",instructionsBackup:"Enter one of your 8-character backup recovery codes. Each code can only be used once.",sendCodeButton:"Send Code via Email",sendingCode:"Sending...",resendCode:"Resend code",codeLabel:"Verification Code",backupCodeLabel:"Backup Code",codePlaceholder:"000000",backupCodePlaceholder:"XXXXXXXX",verifyButton:"Verify",verifyingButton:"Verifying...",backToLogin:"← Back to login",orContinueWith:"or continue with",signInWith:"Sign in with {{provider}}",enterCode:"Please enter the verification code",sendCodeFailed:"Failed to send verification code",invalidCode:"Invalid code. Please try again."}},setup:{title:"Bambuddy Setup",subtitle:"Configure authentication for your Bambuddy instance",enableAuth:"Enable Authentication",adminAccount:"Admin Account",adminAccountDesc:"If admin users already exist, authentication will be enabled using the existing admin accounts. Leave the fields below empty to use existing admins, or enter new credentials to create a new admin user.",adminUsername:"Admin Username",adminPassword:"Admin Password",optionalIfAdminExists:"(optional if admin users exist)",adminUsernamePlaceholder:"Enter admin username (optional)",adminPasswordPlaceholder:"Enter admin password (optional)",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm admin password",settingUp:"Setting up...",completeSetup:"Complete Setup",toast:{authEnabledAdminCreated:"Authentication enabled and admin user created",authEnabledExistingAdmins:"Authentication enabled using existing admin users",setupCompleted:"Setup completed",enterBothCredentials:"Please enter both admin username and password, or leave both empty to use existing admin users",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters"}},changePassword:{title:"Change Password",currentPassword:"Current Password",currentPasswordPlaceholder:"Enter current password",newPassword:"New Password",newPasswordPlaceholder:"Enter new password (min 6 characters)",confirmPassword:"Confirm New Password",confirmPasswordPlaceholder:"Confirm new password",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters",changing:"Changing...",success:"Password changed successfully",failed:"Failed to change password"},plateAlert:{title:"Print Paused!",message:"Objects detected on build plate. The print has been automatically paused. Please clear the plate and resume the print.",understand:"I Understand"},camera:{title:"Camera View",invalidPrinterId:"Invalid printer ID",live:"Live",snapshot:"Snapshot",restartStream:"Restart stream",refreshSnapshot:"Refresh snapshot",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",connectingToCamera:"Connecting to camera...",capturingSnapshot:"Capturing snapshot...",connectionLost:"Connection lost",connectionFailed:"Camera connection failed",reconnecting:"Reconnecting in {{countdown}}s... (attempt {{attempt}}/{{max}})",reconnectNow:"Reconnect now",cameraUnavailable:"Camera unavailable",cameraUnavailableDesc:"Make sure the printer is powered on and connected.",noCamera:"No camera available",retry:"Retry",cameraStream:"Camera stream",zoomOut:"Zoom out",zoomIn:"Zoom in",resetZoom:"Reset zoom",recording:"Recording",startRecording:"Start Recording",stopRecording:"Stop Recording",chamberLight:"Toggle chamber light"},groups:{title:"Group Management",subtitle:"Manage permission groups for access control",backToSettings:"Back to Settings",createGroup:"Create Group",noPermission:"You do not have permission to access this page.",system:"System",noDescription:"No description",usersCount:"{{count}} users",permissionsCount:"{{count}} permissions",edit:"Edit",delete:"Delete",toast:{created:"Group created successfully",updated:"Group updated successfully",deleted:"Group deleted successfully",enterGroupName:"Please enter a group name"},modal:{editGroup:"Edit Group",createGroup:"Create Group",cancel:"Cancel",saving:"Saving...",creating:"Creating...",saveChanges:"Save Changes"},form:{groupName:"Group Name",groupNamePlaceholder:"Enter group name",systemGroupWarning:"System group names cannot be changed",description:"Description",descriptionPlaceholder:"Enter description (optional)",permissions:"Permissions ({{count}} selected)"},deleteModal:{title:"Delete Group",message:"Are you sure you want to delete this group? Users in this group will lose these permissions.",confirm:"Delete Group"},editor:{title:"Edit Group",createTitle:"Create Group",search:"Search permissions...",selectAll:"Select All",clearAll:"Clear All",permissionsSelected:"{{count}} selected",noResults:"No permissions match your search"}},users:{title:"User Management",subtitle:"Manage users and their access to your Bambuddy instance",backToSettings:"Back to Settings",createUser:"Create User",noPermission:"You do not have permission to access this page.",admin:"Admin",noGroups:"No groups",active:"Active",inactive:"Inactive",edit:"Edit",delete:"Delete",system:"System",noGroupsAvailable:"No groups available",table:{username:"Username",groups:"Groups",status:"Status",actions:"Actions"},toast:{created:"User created successfully",updated:"User updated successfully",deleted:"User deleted successfully",fillRequired:"Please fill in all required fields",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters"},modal:{createUser:"Create User",editUser:"Edit User",cancel:"Cancel",creating:"Creating...",saving:"Saving...",saveChanges:"Save Changes",advancedAuthSubtitle:"with Advanced Authentication"},form:{username:"Username",usernamePlaceholder:"Enter username",email:"Email",emailPlaceholder:"user@example.com",password:"Password",passwordPlaceholder:"Enter password",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm password",newPasswordPlaceholder:"Enter new password",confirmNewPasswordPlaceholder:"Confirm new password",leaveBlankToKeep:"leave blank to keep current",groups:"Groups",optional:"optional",autoGeneratedPassword:"A secure password will be automatically generated and emailed to the user.",passwordManagedByAdvancedAuth:'Password is managed by Advanced Authentication. Use "Reset Password" to send a new password to the user via email.',resetPassword:"Reset Password",resettingPassword:"Resetting Password..."},deleteModal:{title:"Delete User",message:"Are you sure you want to delete this user? This action cannot be undone.",confirm:"Delete User"}},streamOverlay:{title:"Stream Overlay",invalidPrinterId:"Invalid printer ID",cameraStream:"Camera stream",progress:"Progress",eta:"ETA",printerIdle:"Printer is idle",printerOffline:"Printer offline",status:{printing:"Printing",paused:"Paused",finished:"Finished",failed:"Failed",idle:"Idle",unknown:"Unknown"}},profiles:{title:"Profiles",subtitle:"Manage your slicer presets and pressure advance calibrations",tabs:{cloud:"Cloud Profiles",local:"Local Profiles",kprofiles:"K-Profiles"},localProfiles:{title:"Local Profiles",subtitle:"Import and manage slicer presets from OrcaSlicer",import:"Import Profiles",importDesc:"Drop .bbscfg, .bbsflmt, .orca_filament, .zip, or .json files here",importing:"Importing...",search:"Search local presets...",noPresets:"No local presets yet",badge:"Local",edit:"Edit",delete:"Delete",cancel:"Cancel",deleteConfirmTitle:"Delete Preset",deleteConfirm:"Are you sure you want to delete this preset? This cannot be undone.",source:"Source",inheritsFrom:"Inherits",filamentType:"Type",vendor:"Vendor",compatiblePrinters:"Printers",nozzleTemp:"Nozzle Temp",cost:"Cost",density:"Density",pressureAdvance:"Pressure Advance",filament:"Filament",process:"Process",printer:"Printer",toast:{importSuccess:"{{count}} preset(s) imported",importSkipped:"{{count}} preset(s) skipped (duplicates)",importError:"{{count}} error(s) during import",deleted:"Preset deleted",updated:"Preset updated"}},connectedAs:"Connected as",logout:"Logout",noLogoutPermission:"You do not have permission to logout",failedToLoad:"Failed to load profiles",retry:"Retry",time:{justNow:"Just now",minsAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",daysAgo:"{{count}}d ago"},toast:{loggedOut:"Logged out"},login:{title:"Connect to Bambu Cloud",subtitle:"Sync your slicer presets across devices",email:"Email",password:"Password",region:"Region",regionGlobal:"Global",regionChina:"China",verificationCode:"Verification Code",totpCode:"Authenticator Code",checkEmail:"Check your email ({{email}}) for a 6-digit code",enterTotpHint:"Enter the 6-digit code from your authenticator app",accessToken:"Access Token",accessTokenHint:"Paste your Bambu Lab access token (from Bambu Studio)",back:"Back",loginButton:"Login",verifyButton:"Verify",setTokenButton:"Set Token",useToken:"Use access token instead",useEmail:"Login with email instead",toast:{loggedIn:"Logged in successfully",codeSent:"Verification code sent to your email",enterTotp:"Enter code from your authenticator app",tokenSet:"Token set successfully"}},presets:{myPreset:"My preset (editable)",duplicate:"Duplicate",editable:"Editable",failedToLoadDetails:"Failed to load preset details",deleteConfirm:"Delete this preset?",deleteWarning:'This will permanently delete "{{name}}" from Bambu Cloud. This cannot be undone.',noDuplicatePermission:"You do not have permission to duplicate presets",noEditPermission:"You do not have permission to edit presets",noDeletePermission:"You do not have permission to delete presets",types:{filament:"Filament preset",printer:"Printer preset",process:"Process preset"},toast:{deleted:"Preset deleted",created:"Preset created",updated:"Preset updated",duplicated:"Preset duplicated",fieldAdded:'Field "{{key}}" added',exported:"Preset exported"},baseLabel:"Base: {{name}}",currentLabel:"Current: {{name}}",newPreset:"New Preset",editPreset:"Edit Preset",duplicatePreset:"Duplicate Preset",createNewPreset:"Create New Preset",customizeSettings:"Customize settings for your new preset",compareWithBase:"Compare with base preset",compare:"Compare",basePreset:"Base Preset",selectBasePreset:"Select base preset...",presetName:"Preset Name",myCustomPreset:"My custom preset",inheritsFrom:"Inherits from",dropJsonToImport:"Drop JSON to import",tabs:{common:"Common",allFields:"All Fields"},availableFields:"Available Fields",searchFieldsPlaceholder:"Search fields...",noMatchingFields:"No matching fields",allFieldsAdded:"All fields added",addCustomField:"Add custom field",yourOverrides:"Your Overrides",noOverridesYet:"No overrides yet",clickFieldsToAdd:"Click fields on the left to add them",saveAsTemplate:"Save as template",jsonTip:"Tip: Drag & drop a .json file anywhere on this modal to import settings"},cloudView:{searchPlaceholder:"Search presets...",templates:"Templates",refresh:"Refresh",newPreset:"New Preset",clearFilters:"Clear filters",compareMode:"Compare Mode",selectAnotherPreset:"Select another {{type}} preset",clickTwoPresets:"Click two presets of the same type to compare",selectFirst:"1. Select first",selectSecond:"2. Select second",compareNow:"Compare Now",lastSynced:"Last synced:",showingCount:"Showing {{showing}} of {{total}} presets",noPresetsFound:"No presets found",columns:{filament:"Filament",process:"Process",printer:"Printer"},noFilamentPresets:"No filament presets",noProcessPresets:"No process presets",noPrinterPresets:"No printer presets",filters:{type:"Type",owner:"Owner",printer:"Printer",nozzle:"Nozzle",filament:"Filament",layer:"Layer",all:"All",myPresets:"My Presets",builtIn:"Built-in",process:"Process"},noTemplatesPermission:"You do not have permission to manage templates",noRefreshPermission:"You do not have permission to refresh profiles",noCreatePermission:"You do not have permission to create presets"},templates:{title:"Quick Templates",noTemplates:"No templates yet",createFirst:"Create templates from the preset editor",typeFilter:"Type:",deleteTitle:"Delete Template",deleteWarning:"This action cannot be undone",deleteConfirm:'Are you sure you want to delete "{{name}}"?',namePlaceholder:"Template name",descriptionPlaceholder:"Description",settingsJson:"Settings (JSON)",fieldsCount:"{{count}} fields",shownInModals:"Shown in modals",hiddenInModals:"Hidden in modals",apply:"Apply",toast:{deleted:"Template deleted",updated:"Template updated",created:"Template created",applied:"Template applied"}}},support:{debugLoggingActive:"Debug logging is active",manageLogs:"Manage",collectItem7:"Printer connectivity and firmware versions",collectItem8:"Integration status (Spoolman, MQTT, HA)",collectItem9:"Network interfaces (subnets only)",collectItem10:"Python package versions",collectItem11:"Database health checks",collectItem12:"Docker environment details"},fileManager:{title:"File Manager",subtitle:"Organize and manage your print files",uploadFiles:"Upload Files",newFolder:"New Folder",folderName:"Folder Name",folderNamePlaceholder:"e.g., Functional Parts",renameFile:"Rename File",renameFolder:"Rename Folder",moveFiles:"Move {{count}} File(s)",rootNoFolder:"Root (No Folder)",current:"current",linkFolder:"Link Folder",linkFolderDescription:'Link "{{name}}" to a project or archive for quick access.',project:"Project",archive:"Archive",noProjectsFound:"No projects found",noArchivesFound:"No archives found",unlink:"Unlink",link:"Link",dragDropFiles:"Drag & drop files here",dropFilesHere:"Drop files here",orClickToBrowse:"or click to browse",allFileTypesSupported:"All file types supported. ZIP files will be extracted.",zipFilesDetected:"ZIP files detected",zipExtractOptions:"ZIP files will be extracted. Choose how to handle folder structure:",preserveZipStructure:"Preserve folder structure from ZIP",createFolderFromZip:"Create folder from ZIP filename",stlThumbnailGeneration:"STL thumbnail generation",zipMayContainStl:"ZIP files may contain STL files. Thumbnails can be generated during extraction.",thumbnailsCanBeGenerated:"Thumbnails can be generated for STL files. Large models may take longer to process.",generateThumbnailsForStl:"Generate thumbnails for STL files",threemfDetected:"3MF files detected",threemfExtractionInfo:"Printer model, material, color, and print settings will be automatically extracted from 3MF files.",willBeExtracted:"Will be extracted",filesExtracted:"{{count}} files extracted",uploadComplete:"Upload complete: {{succeeded}} succeeded",uploadFailed:"Upload failed",zipFilesFailed:"{{count}} files failed",uploading:"Uploading...",changeLink:"Change Link...",linkTo:"Link to...",linkToProjectOrArchive:"Link to project or archive",addToQueue:"Add to Queue",schedulePrint:"Schedule",generateThumbnail:"Generate Thumbnail",generateThumbnails:"Generate Thumbnails",generateThumbnailsForMissing:"Generate thumbnails for STL files missing them",gridView:"Grid view",listView:"List view",lowDiskSpaceWarning:"Low disk space warning",lowDiskSpaceDetails:"Only {{free}} free of {{total}} total. Threshold is set to {{threshold}} GB in settings.",files:"Files",folders:"Folders",size:"Size",free:"Free",allFiles:"All Files",wrap:"Wrap",enableTextWrapping:"Enable text wrapping",disableTextWrapping:"Disable text wrapping",collapse:"Collapse",collapseFoldersByDefault:"Collapse folders by default",expandFoldersByDefault:"Expand folders by default",dragToResizeTooltip:"Drag to resize, double-click to reset",searchFiles:"Search files...",allTypes:"All types",prints:"Prints",ascending:"Ascending",descending:"Descending",resultsCount:"{{showing}} of {{total}} files",selectAll:"Select All",deselectAll:"Deselect All",selected:"{{count}} selected",adding:"Adding...",loadingFiles:"Loading files...",folderIsEmpty:"Folder is empty",noFilesYet:"No files yet",folderEmptyDescription:"Upload files or move files into this folder to get started.",noFilesDescription:"Upload files to start organizing your print-related files.",noMatchingFiles:"No matching files",noMatchingFilesDescription:"No files match your current search or filter criteria.",clearFilters:"Clear filters",printedCount:"Printed {{count}}x",uploadedBy:"Uploaded By",deleteFolder:"Delete Folder",deleteFile:"Delete File",deleteFilesCount:"Delete {{count}} Files",deleteFolderConfirm:"Are you sure you want to delete this folder? All files inside will also be deleted.",deleteFileConfirm:"Are you sure you want to delete this file?",deleteFilesConfirm:"Are you sure you want to delete {{count}} selected files? This action cannot be undone.",deleting:"Deleting...",noPermissionRenameFolder:"You do not have permission to rename folders",noPermissionLinkFolder:"You do not have permission to link folders",noPermissionDeleteFolder:"You do not have permission to delete folders",noPermissionPrint:"You do not have permission to print",noPermissionAddToQueue:"You do not have permission to add to queue",noPermissionDownload:"You do not have permission to download files",noPermissionRenameFile:"You do not have permission to rename this file",noPermissionGenerateThumbnail:"You do not have permission to generate thumbnails",noPermissionDeleteFile:"You do not have permission to delete this file",noPermissionCreateFolder:"You do not have permission to create folders",noPermissionUpload:"You do not have permission to upload files",noPermissionMoveFiles:"You do not have permission to move files",noPermissionDeleteFiles:"You do not have permission to delete files",linkExternal:"Link External",linkExternalFolder:"Link External Folder",linkExternalFolderDescription:"Mount a host directory (NAS, USB, network share) into the File Manager. Files are not copied — they are accessed directly from the original path.",externalFolderNamePlaceholder:"e.g., NAS Prints",externalPath:"Host Path",externalPathHelp:"Absolute path to the directory on the Docker host. Must be bind-mounted into the container.",readOnly:"Read Only",readOnlyHelp:"prevents uploads and deletions",showHiddenFiles:"Show hidden files (dotfiles)",externalFolder:"External Folder",scanFolder:"Scan",toast:{folderCreated:"Folder created",folderDeleted:"Folder deleted",fileDeleted:"File deleted",filesDeleted:"Deleted {{count}} files",filesMoved:"Files moved",folderLinked:"Folder linked",folderUnlinked:"Folder unlinked",externalFolderLinked:"External folder linked and scanned",folderScanned:"Scan complete: {{added}} added, {{removed}} removed",addedToQueue:"Added {{count}} file(s) to queue",addedToQueuePartial:"Added {{added}} file(s), {{failed}} failed",failedToAddToQueue:"Failed to add files: {{error}}",fileRenamed:"File renamed",folderRenamed:"Folder renamed",thumbnailsGenerated:"Generated {{count}} thumbnail(s)",thumbnailsGeneratedPartial:"Generated {{succeeded}} thumbnail(s), {{failed}} failed",noStlMissingThumbnails:"No STL files missing thumbnails",failedToGenerateThumbnails:"Failed to generate thumbnails: {{error}}",thumbnailGenerated:"Thumbnail generated",failedToGenerateThumbnail:"Failed to generate thumbnail: {{error}}"}},projects:{title:"Projects",subtitle:"Organize and track your 3D printing projects",newProject:"New Project",editProject:"Edit Project",deleteProject:"Delete Project",projectName:"Project Name",description:"Description",noProjects:"No projects yet",noProjectsFiltered:"No {{status}} projects",noProjectsFilteredHelp:"You don't have any {{status}} projects. Projects will appear here when their status changes.",createFirst:"Create your first project to start organizing related prints, tracking progress, and managing your builds.",createFirstButton:"Create Your First Project",create:"Create",files:"Files",prints:"Prints",plates:"plates",parts:"parts",lastModified:"Last Modified",deleteConfirm:"Are you sure you want to delete this project? Archives and queue items will be unlinked but not deleted.",addFiles:"Add Files",removeFile:"Remove File",viewDetails:"View Details",namePlaceholder:"e.g., Voron 2.4 Build",descriptionPlaceholder:"Optional description...",color:"Color",targetPlates:"Target Plates",targetPlatesPlaceholder:"e.g., 25",targetPlatesHelp:"Number of print jobs",targetParts:"Target Parts",targetPartsPlaceholder:"e.g., 150",targetPartsHelp:"Total objects needed",tagsLabel:"Tags (comma-separated)",tagsPlaceholder:"e.g., voron, functional, gift",dueDate:"Due Date",priority:"Priority",priorityLow:"Low",priorityNormal:"Normal",priorityHigh:"High",priorityUrgent:"Urgent",statusActive:"Active",statusCompleted:"Completed",statusArchived:"Archived",done:"Done",completed:"completed",failed:"failed",inQueue:"in queue",noPrintsYet:"No prints yet",printJobs:"Print jobs (plates)",partsPrinted:"Parts printed",failedParts:"Failed parts",import:"Import",export:"Export",importProject:"Import project",exportAll:"Export all projects",loading:"Loading projects...",noEditPermission:"You do not have permission to edit projects",noDeletePermission:"You do not have permission to delete projects",noCreatePermission:"You do not have permission to create projects",noImportPermission:"You do not have permission to import projects",noExportPermission:"You do not have permission to export projects",toast:{created:"Project created",updated:"Project updated",deleted:"Project deleted",imported:"Project imported",multipleImported:"{{count}} projects imported",importFailed:"Import failed",exported:"Projects exported (metadata only)"}},projectDetail:{notFound:"Project not found",backToProjects:"Back to Projects",export:"Export",exportProject:"Export project",noExportPermission:"You do not have permission to export projects",noEditPermission:"You do not have permission to edit projects",partOf:"Part of:",priorityLabel:"Priority:",noPrints:"No prints in this project yet",status:{active:"Active",completed:"Completed",archived:"Archived"},priority:{low:"Low",normal:"Normal",high:"High",urgent:"Urgent"},dueDate:{overdue:"Overdue",today:"Due today",daysLeft:"{{count}} days left"},progress:{platesProgress:"Plates Progress",partsProgress:"Parts Progress",printJobs:"print jobs",parts:"parts",percentComplete:"{{percent}}% complete",remaining:"{{count}} remaining"},stats:{printJobs:"Print Jobs",total:"total",failed:"{{count}} failed",partsPrinted:"{{count}} parts printed",printTime:"Print Time",filamentUsed:"Filament Used"},cost:{title:"Cost Tracking",filamentCost:"Filament Cost",energy:"Energy",totalCost:"Total Cost",total:"Total",includesBom:"incl. BOM",budget:"Budget",remaining:"Remaining"},subProjects:{title:"Sub-projects ({{count}})"},notes:{title:"Notes",noEditPermission:"You do not have permission to edit notes",placeholder:"Add notes about this project...",empty:"No notes yet. Click Edit to add notes."},files:{title:"Files",linkFolders:"Link folders from the File Manager",forQuickAccess:"to this project for quick access.",fileCount:"{{count}} file(s)",empty:"No folders linked. Go to File Manager and link a folder to this project.",noFiles:"No files in this folder.",print:"Print Now",addToQueue:"Add to Queue"},bom:{title:"Bill of Materials",acquired:"{{completed}}/{{total}} acquired",showAll:"Show all",hideDone:"Hide done",addPart:"Add Part",noAddPermission:"You do not have permission to add parts",partNamePlaceholder:"Part name (e.g., M3x8 screws)",partName:"Part name",qty:"Qty",price:"Price ({{currency}})",sourcingUrlPlaceholder:"Sourcing URL (optional)",remarksPlaceholder:"Remarks (optional)",deletePart:"Delete Part",deleteConfirm:'Are you sure you want to delete "{{name}}"?',noUpdatePermission:"You do not have permission to update parts",noEditPermission:"You do not have permission to edit parts",noDeletePermission:"You do not have permission to delete parts",totalCost:"Total cost:",empty:"No parts in the bill of materials. Add hardware, electronics, or other components to track what needs to be sourced."},timeline:{title:"Activity Timeline",empty:"No activity yet."},template:{saveAsTemplate:"Save as Template",noCreatePermission:"You do not have permission to create templates"},queue:{title:"Queue",viewAll:"View all",printing:"{{count}} printing",queued:"{{count}} queued"},prints:{title:"Prints ({{count}})"},toast:{projectUpdated:"Project updated",partAdded:"Part added",partRemoved:"Part removed",exportFailed:"Export failed",projectExported:"Project exported",templateCreated:"Template created"}},system:{title:"System Information",version:"Version",uptime:"Uptime",cpuUsage:"CPU Usage",memoryUsage:"Memory Usage",diskUsage:"Disk Usage",networkInfo:"Network Info",logs:"Logs",debugMode:"Debug Mode",enableDebug:"Enable Debug Logging",disableDebug:"Disable Debug Logging",downloadLogs:"Download Logs",clearLogs:"Clear Logs",dockerInfo:"Docker Info",containerName:"Container Name",imageName:"Image Name",platform:"Platform",architecture:"Architecture"},library:{title:"Filament Library",addFilament:"Add Filament",editFilament:"Edit Filament",deleteFilament:"Delete Filament",vendor:"Vendor",material:"Material",color:"Color",kFactor:"K Factor",temperature:"Temperature",noFilaments:"No filaments in library",deleteConfirm:"Are you sure you want to delete this filament?",importFromPrinter:"Import from Printer",exportToFile:"Export to File"},spoolman:{title:"Spoolman Integration",enabled:"Spoolman Enabled",url:"Spoolman URL",connected:"Connected",disconnected:"Not Connected",testConnection:"Test Connection",sync:"Sync",syncing:"Syncing...",lastSync:"Last Sync",linkToSpoolman:"Link to Spoolman",openInSpoolman:"Open in Spoolman",unlinkSpool:"Unlink Spool",unlinkConfirmTitle:"Unlink Spool?",unlinkConfirmMessage:"This will disconnect the spool from Spoolman. The spool data in Spoolman will remain unchanged.",selectSpool:"Select Spool",noUnlinkedSpools:"No unlinked spools available",linkSuccess:"Spool linked to Spoolman successfully",linkFailed:"Failed to link spool",unlinkSuccess:"Spool unlinked from Spoolman successfully",unlinkFailed:"Failed to unlink spool",spoolId:"Spool ID",fillSourceLabel:"(Spoolman)",weight:"Weight",remaining:"Remaining",disableWeightSync:"Disable AMS Estimated Weight Sync",disableWeightSyncDesc:"Don't update remaining capacity from AMS estimates. Use this if you prefer Spoolman's usage tracking over AMS percentage-based estimates. New spools will still use the AMS estimate as their initial weight.",reportPartialUsage:"Report Partial Usage for Failed Prints",reportPartialUsageDesc:"When a print fails or is cancelled, report the estimated filament used up to that point based on layer progress."},inventory:{title:"Spool Inventory",addSpool:"Add Spool",editSpool:"Edit Spool",material:"Material",selectMaterial:"Select material...",subtype:"Subtype",brand:"Brand",searchBrand:"Search brand...",useCustomBrand:'Use "{{brand}}"',useCustomMaterial:"Use custom material: {{material}}",colorName:"Color Name",colorNamePlaceholder:"Jade White, Fire Red...",color:"Color",hexColor:"Hex Color",pickColor:"Pick custom color",labelWeight:"Label Weight",coreWeight:"Empty Spool Weight",searchSpoolWeight:"Search spool weight...",weightUsed:"Used",currentWeight:"Remaining Weight",measuredWeight:"Measured Weight",spoolName:"Spool",costPerKg:"Cost per kg",measuredWeightError:"Measured weight must be between {{min}}g and {{max}}g.",slicerFilament:"Slicer Filament",slicerFilamentName:"Slicer Preset Name",slicerPreset:"Slicer Preset",searchPresets:"Search filament presets...",selectedPreset:"Selected",noPresetsFound:"No presets found",tempOverrides:"Temperature Overrides",note:"Note",notePlaceholder:"Any additional notes about this spool...",archive:"Archive",restore:"Restore",noSpools:"No spools yet. Add your first spool to get started.",noManualSpools:"No manually added spools available. Add a spool to your inventory first.",kProfiles:"K-Profiles",addKProfile:"Add K-Profile",assignSpool:"Assign Spool",unassignSpool:"Unassign",assignSuccess:"Spool assigned and AMS slot configured",assignFailed:"Failed to assign spool",selectSpool:"Select a spool to assign to this slot",assigned:"Assigned",assigning:"Assigning...",searchSpools:"Search spools...",showAllSpools:"Show all spools",allMaterials:"All Materials",filterByBrand:"Filter by brand...",showArchived:"Show archived",quickAdd:"Quick Add (Stock)",quantity:"Quantity",stock:"Stock",configured:"Configured",spoolsCreated:"{{count}} spools created",spoolCreated:"Spool created",spoolUpdated:"Spool updated",spoolDeleted:"Spool deleted",spoolArchived:"Spool archived",spoolRestored:"Spool restored",deleteConfirm:"Are you sure you want to delete this spool? This cannot be undone.",archiveConfirm:"Are you sure you want to archive this spool?",advancedSettings:"Advanced Settings",filamentInfoTab:"Filament Info",paProfileTab:"PA Profile",filamentInfo:"Filament",additional:"Additional",loadingPresets:"Loading cloud presets...",cloudConnected:"Cloud connected",cloudNotConnected:"Cloud not connected (using defaults)",recentColors:"Recent",searchColors:"Search colors...",searchResults:"Search results",allColors:"All colors",commonColors:"Common colors",showLess:"Show less",showAll:"Show all",noColorsFound:"No colors match your search",noResults:"No matches found",selectMaterialFirst:"Please select a material first in the Filament Info tab.",noPrintersConfigured:"No printers configured. Add printers to use PA profiles.",matchingFilter:"Matching",anyBrand:"Any brand",anyVariant:"Any variant",autoSelect:"Auto-select",matches:"matches",match:"match",noMatches:"No matches",connected:"Connected",offline:"Offline",printerOffline:"Printer is offline. Connect to view calibration profiles.",noKProfilesMatch:"No K-profiles match the selected filament.",leftNozzle:"Left Nozzle",rightNozzle:"Right Nozzle",profilesSelected:"calibration profile(s) selected",totalInventory:"Total Inventory",totalConsumed:"Total Consumed",byMaterial:"By Material",inPrinter:"In Printer",lowStock:"Low Stock",sinceTracking:"Since tracking started",loadedInAms:"Loaded in AMS/Ext",remaining:"Remaining",weightCheck:"Weight Check",lastWeighed:"Last weighed",neverWeighed:"Never weighed",search:"Search spools...",showing:"Showing",to:"to",of:"of",show:"Show",spools:"spools",spool:"spool",page:"Page",noSpoolsMatch:"No results found",noSpoolsMatchDesc:"Try adjusting your search or filters to find what you're looking for.",active:"Active",archived:"Archived",all:"All",used:"Used",new:"New",clearFilters:"Clear filters",table:"Table",cards:"Cards",net:"Net",groupSimilar:"Group",groupedSpools:"{{count}} identical spools",groupedRows:"rows",columns:"Columns",configureColumns:"Configure Columns",configureColumnsDesc:"Drag to reorder columns or use arrows. Toggle visibility with the eye icon.",visible:"visible",reset:"Reset",cancel:"Cancel",applyChanges:"Apply Changes",moveUp:"Move up",moveDown:"Move down",hideColumn:"Hide column",showColumn:"Show column",linkToSpool:"Link to Spool",tagLinked:"Tag linked to spool",tagLinkFailed:"Failed to link tag",tagAlreadyLinked:"Tag already linked to another spool",unknownTag:"Unknown RFID tag detected",usageHistory:"Usage History",noUsageHistory:"No usage recorded yet",printName:"Print Name",weightConsumed:"Weight Consumed",clearHistory:"Clear",historyCleared:"Usage history cleared",fillSourceLabel:"(Inv)",lowStockThresholdError:"Threshold must be between 0.1 and 99.9",assignMismatchTitle:"Material mismatch",assignMismatchMessage:'The selected spool material "{{spoolMaterial}}" does not match the tray material "{{trayMaterial}}" for {{location}}. Assign anyway?',assignMismatchConfirm:"Assign Anyway",assignPartialMismatchMessage:'The spool material "{{spoolMaterial}}" is similar to but not exactly matching "{{trayMaterial}}" in {{location}}. Do you want to proceed?',assignProfileMismatchMessage:'The spool profile "{{spoolProfile}}" does not match the tray profile "{{trayProfile}}" in {{location}}. Do you want to proceed?'},timelapse:{title:"Timelapse",create:"Create Timelapse",download:"Download",delete:"Delete",preview:"Preview",frameRate:"Frame Rate",quality:"Quality",processing:"Processing...",noTimelapses:"No timelapses available"},ams:{title:"AMS",slot:"Slot",empty:"Empty",emptySlot:"Empty slot",unknown:"Unknown",humidity:"Humidity",temperature:"Temperature",filamentType:"Filament Type",filamentColor:"Color",remaining:"Remaining",history:"AMS History",noHistory:"No history available",configureSlot:"Configure Slot",externalSpool:"External Spool",profile:"Profile",kFactor:"K Factor",fill:"Fill",configure:"Configure",used:"used",remainingUnit:"remaining"},printModal:{title:"Start Print",selectPrinter:"Select Printer",selectPlate:"Select Plate",filamentMapping:"Filament Mapping",totalCost:"Total cost:",slotRemainingShort:" - {{grams}}g left",printSettings:"Print Settings",bedLeveling:"Bed Leveling",flowCalibration:"Flow Calibration",vibrationCalibration:"Vibration Calibration",layerInspection:"First Layer Inspection",timelapse:"Timelapse",startPrint:"Start Print",addToQueue:"Add to Queue",cancel:"Cancel",noPrintersAvailable:"No printers available",printerBusy:"Printer is busy",printerOffline:"Printer is offline",sameTypeDifferentColor:"Same type, different color",filamentTypeNotLoaded:"Filament type not loaded",openCalendar:"Open calendar",leftNozzle:"L",rightNozzle:"R",leftNozzleTooltip:"Left nozzle",rightNozzleTooltip:"Right nozzle",filamentOverride:"Filament Override",filamentOverrideHint:"Optionally override filaments for model-based assignment. The scheduler will match against your selected filaments instead of the original 3MF values.",originalFilament:"Original",overrideWith:"Override with",resetToOriginal:"Reset to original",insufficientFilamentTitle:"Not enough filament",insufficientFilamentMessage:"Some assigned spools have less filament remaining than this print needs:",insufficientFilamentLine:"{{printer}} - {{slot}}: needs {{required}}g, remaining {{remaining}}g",printAnyway:"Print anyway",forceColorMatch:"Force color match",staggerPrinterStarts:"Stagger printer starts",staggerGroupSize:"Group size",staggerInterval:"Interval (min)",staggerPreview:"{{printers}} printers → {{groups}} groups of {{size}}, starting every {{interval}} min",staggerLastGroup:"last group: {{count}}",staggerTotal:"total: {{minutes}} min",staggerToPrinters:"Stagger to {{count}} printers",gcodeInjection:"Inject auto-print G-code"},backup:{title:"Backup & Restore",createBackup:"Create Backup",restoreBackup:"Restore Backup",restoreDescription:"Replace all data from a backup file",downloadBackup:"Download Backup",uploadBackup:"Upload Backup",lastBackup:"Last Backup",autoBackup:"Auto Backup",backupNow:"Backup Now",restoreWarning:"Warning: Restoring a backup will overwrite all current data.",includeArchives:"Include Archives",includeSettings:"Include Settings",includeProfiles:"Include Profiles",backupSuccess:"Backup created successfully",restoreSuccess:"Backup restored successfully",backupFailed:"Backup failed",restoreFailed:"Restore failed",restoreNote:"Virtual Printer will be stopped during restore",githubBackup:"GitHub Backup",enabled:"Enabled",cloudLoginRequired:"Bambu Cloud login required. Sign in under Profiles → Cloud Profiles to enable GitHub backup.",cloudLoginRequiredShort:"Cloud login required",githubDescription:"Automatically sync your profiles to a private GitHub repository for backup and version history.",repositoryUrl:"Repository URL",personalAccessToken:"Personal Access Token",tokenSaved:"(saved)",enterNewToken:"Enter new token to update",tokenHint:"Fine-grained token with Contents read/write permission",branch:"Branch",manualOnly:"Manual only",hourly:"Hourly",daily:"Daily",weekly:"Weekly",includeInBackup:"Include in backup",kProfiles:"K-Profiles",kProfilesDescription:"Pressure advance calibration from connected printers",noPrintersConnected:"No printers connected",printersConnected:"{{connected}}/{{total}} connected",cloudProfiles:"Cloud Profiles",cloudProfilesDescription:"Filament, printer, and process presets from Bambu Cloud",appSettings:"App Settings",appSettingsDescription:"Bambuddy configuration (complete database)",spoolInventory:"Spool Inventory",spoolInventoryDescription:"Filament spools, usage history, and cost tracking",printArchives:"Print Archives",printArchivesDescription:"Print history metadata (no gcode/3MF files)",lastBackupAt:"Last backup:",noBackupsYet:"No backups yet",next:"Next:",startingBackup:"Starting backup...",test:"Test",enableBackup:"Enable Backup",testConnection:"Test Connection",enterRepoUrl:"Enter repository URL",enterRepoAndToken:"Enter repository URL and access token",repoRequired:"Repository URL is required",tokenRequired:"Access token is required",githubBackupEnabled:"GitHub backup enabled",tokenUpdated:"Token updated",settingsSaved:"Settings saved",failedToSave:"Failed to save: {{message}}",backupCompleteFiles:"Backup complete - {{count}} files updated",backupSkippedNoChanges:"Backup skipped - no changes",backupFailed2:"Backup failed: {{message}}",clearedLogs:"Cleared {{count}} logs",failedToClearLogs:"Failed to clear logs: {{message}}",history:"History",clear:"Clear",date:"Date",status:"Status",commit:"Commit",localBackup:"Local Backup",localBackupDescription:"Create a complete backup of your Bambuddy data including the database, archives, uploads, and all files.",downloadBackupLabel:"Download Backup",completeBackupZip:"Complete backup: database + all files (ZIP)",download:"Download",preparingBackup:"Preparing backup...",creatingArchive:"Creating backup archive... This may take a while for large archives.",downloadingFile:"Downloading backup file...",backupDownloaded:"Backup downloaded successfully",failedToCreateBackup:"Failed to create backup: {{message}}",restore:"Restore",restoreReplacesAll:"Restore replaces all data.",restoreReplacesAllDetail:"Your current database and files will be completely replaced. A restart is required after restore.",restoreConfirmTitle:"Restore Backup",restoreConfirmMessage:'Are you sure you want to restore from "{{filename}}"? This will completely replace your current database and all files. The application will need to be restarted after restore.',restoreConfirmButton:"Restore Backup",uploadingFile:"Uploading backup file...",backupRestoredRestart:"Backup restored. Please restart Bambuddy.",failedToRestore:"Failed to restore backup. Please check the file format.",reloadNow:"Reload Now",creatingBackup:"Creating Backup",restoringBackup:"Restoring Backup",preparing:"Preparing...",processing:"Processing...",doNotClosePage:"Please do not close this page or navigate away. This operation may take several minutes for large backups.",restoring:"Restoring...",restoreComplete:"Restore Complete",restoreFailed2:"Restore Failed",importSettings:"Import settings from a backup file",pleaseWaitRestoring:"Please wait while your data is being restored",selectBackupFile:"Click to select backup file (.json or .zip)",duplicateHandling:"How duplicate handling works:",matchPrinters:"Printers",matchPrintersBy:"matched by serial number",matchSmartPlugs:"Smart Plugs",matchSmartPlugsBy:"matched by IP address",matchNotificationProviders:"Notification Providers",matchNotificationProvidersBy:"matched by name",matchFilaments:"Filaments",matchFilamentsBy:"matched by name + type + brand",matchArchives:"Archives",matchArchivesBy:"matched by content hash (always skipped)",matchPendingUploads:"Pending Uploads",matchPendingUploadsBy:"matched by filename",matchSettingsTemplates:"Settings & Templates",matchSettingsTemplatesBy:"always overwritten",replaceExisting:"Replace existing data",keepExisting:"Keep existing data",overwriteDescription:"Overwrite items that already exist with backup data",keepDescription:"Only restore items that don't already exist",overwriteCaution:"Caution:",overwriteWarning:"Overwriting will replace your current configurations with data from the backup. Printer access codes are never overwritten for security.",cancel:"Cancel",processingBackup:"Processing backup file...",itemsRestored:"Items Restored",itemsSkipped:"Items Skipped",restored:"Restored",skippedAlreadyExist:"Skipped (already exist)",filesCategory:"Files (3MF, thumbnails, etc.)",andMore:"...and {{count}} more",newApiKeysGenerated:"New API Keys Generated",keysShownOnce:"These keys are only shown once. Copy them now!",copy:"Copy",noDataFound:"No data was found to restore in the backup file.",close:"Close",scheduledBackup:"Scheduled Backups",scheduledBackupDescription:"Automatically create backup snapshots on a schedule. Output directory can be mounted to a NAS or external storage.",frequency:"Frequency",backupTime:"Time",retention:"Retention",retentionDescription:"Number of backups to keep",outputPath:"Output Path",outputPathPlaceholder:"Default: {{path}}",outputPathDescription:"Leave empty for default location",runNow:"Run Now",backupFiles:"Backup Files",noScheduledBackups:"No backups yet",deleteBackup:"Delete",deleteBackupConfirm:"Delete this backup file?",backupRunning:"Backup in progress...",scheduledBackupComplete:"Backup completed successfully",scheduledBackupFailed:"Backup failed",nextBackup:"Next backup",backupSize:"Size",utc:"UTC",defaultPathLabel:"Default:",categories:{settings:"Settings",notification_providers:"Notification Providers",notification_templates:"Notification Templates",smart_plugs:"Smart Plugs",printers:"Printers",filaments:"Filaments",maintenance_types:"Maintenance Types",archives:"Archives",projects:"Projects",pending_uploads:"Pending Uploads",external_links:"External Links",api_keys:"API Keys"}},tags:{title:"Tags",addTag:"Add Tag",editTag:"Edit Tag",deleteTag:"Delete Tag",tagName:"Tag Name",tagColor:"Tag Color",noTags:"No tags",deleteConfirm:"Are you sure you want to delete this tag?",manageTags:"Manage Tags"},uploadModal:{title:"Upload 3MF Files",dragDrop:"Drag & drop .3mf files here",or:"or",browseFiles:"Browse Files",extractionInfo:"The printer model will be automatically extracted from the 3MF file metadata.",uploaded:"uploaded",failed:"failed",uploading:"Uploading...",upload:"Upload",uploadFailed:"Upload failed"},editArchive:{title:"Edit Archive",name:"Name",namePlaceholder:"Print name",printer:"Printer",noPrinter:"No printer",project:"Project",noProject:"No project",itemsPrinted:"Items Printed",itemsPrintedHelp:"Number of items produced in this print job",notes:"Notes",notesPlaceholder:"Add notes about this print...",externalLink:"External Link",externalLinkPlaceholder:"https://printables.com/model/...",externalLinkHelp:"Link to Printables, Thingiverse, or other source",tags:"Tags",tagsPlaceholder:"Add tags...",addMoreTags:"Add more tags...",matchingTags:'Matching "{{query}}"',existingTags:"Existing tags",clickToAdd:"(click to add)",status:"Status",failureReason:"Failure Reason",selectReason:"Select reason...",photos:"Photos of Printed Result",photosHelp:"Click + to add photos of your printed result",printResult:"Print result",saving:"Saving...",failureReasons:{adhesionFailure:"Adhesion failure",spaghettiDetached:"Spaghetti / Detached",layerShift:"Layer shift",cloggedNozzle:"Clogged nozzle",filamentRunout:"Filament runout",warping:"Warping",stringing:"Stringing",underExtrusion:"Under-extrusion",powerFailure:"Power failure",userCancelled:"User cancelled",other:"Other"},statuses:{completed:"Completed",failed:"Failed",aborted:"Cancelled",printing:"Printing"}},kProfiles:{title:"K-Profiles",noPrintersConfigured:"No Printers Configured",addPrinterInSettings:"Add a printer in Settings to manage K-profiles",noActivePrinters:"No Active Printers",enablePrinterConnection:"Enable a printer connection to view its K-profiles",loadingProfiles:"Loading K-Profiles...",printerOffline:"Printer Offline",printerOfflineDesc:"The selected printer is not connected. Power it on to view K-profiles.",noMatchingProfiles:"No Matching Profiles",noMatchingProfilesDesc:"No profiles match your search criteria",noKProfiles:"No K-Profiles",noKProfilesDesc:"No pressure advance profiles found for {{diameter}}mm nozzle",createFirstProfile:"Create First Profile",printer:"Printer",nozzle:"Nozzle",refresh:"Refresh",addProfile:"Add Profile",export:"Export",import:"Import",select:"Select",selectAll:"Select All",delete:"Delete",searchPlaceholder:"Search by name or filament...",allExtruders:"All Extruders",leftOnly:"Left Only",rightOnly:"Right Only",allFlow:"All Flow",hfOnly:"HF Only",sOnly:"S Only",sortName:"Sort: Name",sortKValue:"Sort: K-Value",sortFilament:"Sort: Filament",leftExtruder:"Left Extruder",rightExtruder:"Right Extruder",modal:{addTitle:"Add K-Profile",editTitle:"Edit K-Profile",profileName:"Profile Name",profileNamePlaceholder:"My PLA Profile",kValue:"K-Value",kValuePlaceholder:"0.020",kValueHelp:"Typical range: 0.01 - 0.06 for PLA, 0.02 - 0.10 for PETG",filament:"Filament",selectFilament:"Select filament...",noFilamentsHelp:"No filaments found. Create a K-profile in Bambu Studio first.",flowType:"Flow Type",highFlow:"High Flow",standard:"Standard",nozzleSize:"Nozzle Size",extruder:"Extruder",extruders:"Extruders",left:"Left",right:"Right",notes:"Notes (stored locally)",notesPlaceholder:"Add notes about this profile...",notesHelp:"Notes are saved in Bambuddy, not on the printer",syncing:"Syncing with printer...",savingExtruder:"Saving to extruder {{current}}/{{total}}...",pleaseWait:"Please wait"},deleteConfirm:{title:"Delete Profile",cannotUndo:"This cannot be undone",message:'Are you sure you want to delete "{{name}}" from the printer?'},bulkDelete:{title:"Delete Profiles",cannotUndo:"This cannot be undone",message:"Are you sure you want to delete {{count}} selected profiles from the printer?"},toast:{profileSaved:"K-profile saved",profilesSaved:"K-profile saved to {{count}} extruders",selectAtLeastOneExtruder:"Please select at least one extruder",profileDeleted:"K-profile deleted",profilesDeleted:"Deleted {{count}} profiles",exportedProfiles:"Exported {{count}} profiles",importedProfiles:"Imported {{count}} of {{total}} profiles",noProfilesToExport:"No profiles to export",invalidFileFormat:"Invalid file format",failedToParseImport:"Failed to parse import file",failedToSaveBatch:"Failed to save K-profiles",noteSaved:"Note saved",failedToSaveNote:"Failed to save note"},permission:{noRead:"You do not have permission to refresh profiles",noCreate:"You do not have permission to add profiles",noUpdate:"You do not have permission to update K-profiles",noDelete:"You do not have permission to delete K-profiles",noExport:"You do not have permission to export profiles",noImport:"You do not have permission to import profiles"}},virtualPrinter:{title:"Virtual Printer",running:"Running",stopped:"Stopped",description:{default:"Enable a virtual printer that appears in Bambu Studio and OrcaSlicer. Files sent to this printer will be archived directly without printing.",proxy:"Enable a proxy that relays slicer traffic to a real printer, allowing remote printing over any network."},enable:{title:"Enable Virtual Printer",visibleInSlicer:'Visible as "Bambuddy" in slicer discovery',proxyingTo:"Proxying to {{name}}",notActive:"Not active"},model:{title:"Printer Model",description:"Select which printer model to emulate.",restartWarning:"Changing the model will restart the virtual printer"},accessCode:{title:"Access Code",isSet:"Access code is set",notSet:"No access code set - required to enable",placeholder:"Enter 8-char code",placeholderChange:"Enter new code to change",hint:"Must be exactly 8 characters. Used by slicers to authenticate.",charCount:"({{count}}/8)"},targetPrinter:{title:"Target Printer",configured:"Proxy target configured",notConfigured:"No target printer selected - required for proxy mode",placeholder:"Select a printer...",hint:"Select the printer to proxy slicer traffic to. The printer must be in LAN mode.",noPrinters:"No printers configured. Add a printer first to use proxy mode."},remoteInterface:{title:"Network Interface Override",configured:"Interface override active",optional:"Optional - use if auto-detected IP is wrong (e.g. multiple NICs, Docker, VPN)",placeholder:"Auto-detect (default)...",hint:"Override the IP address advertised via SSDP and used in the TLS certificate. Useful when Bambuddy has multiple network interfaces."},mode:{title:"Mode",archive:"Archive",archiveDesc:"Archive files immediately",review:"Review",reviewDesc:"Review before archiving",queue:"Queue",queueDesc:"Archive and add to queue",proxy:"Proxy",proxyDesc:"Relay to real printer"},autoDispatch:{title:"Auto-dispatch",description:"Automatically start prints when added to queue. When off, prints wait for manual dispatch."},setupRequired:{title:"Setup Required",description:"The virtual printer feature requires additional system configuration before it will work. This includes port forwarding, firewall rules, and platform-specific settings.",readGuide:"Read the setup guide before enabling"},howItWorks:{title:"How it works",step1:"On the same LAN, virtual printers appear in your slicer (Bambu Studio / OrcaSlicer) automatically via discovery. From other networks, add them manually by IP address and access code.",step2:'In Archive, Review, and Queue modes, use the "Send" button in your slicer to upload 3MF files to Bambuddy. The slicer will show "Print success" — the file is stored, not printed.',step3:"In Proxy mode, the virtual printer relays all traffic to a real printer — prints start immediately as if connected directly."},status:{title:"Status Details",printerName:"Printer Name",model:"Model",serialNumber:"Serial Number",mode:"Mode",pendingFiles:"Pending Files",targetPrinter:"Target Printer",ftpPort:"FTP Port",mqttPort:"MQTT Port",ftpConnections:"FTP Connections",mqttConnections:"MQTT Connections"},toast:{updated:"Virtual printer settings updated",failedToUpdate:"Failed to update settings",accessCodeRequired:"Please set an access code first",targetPrinterRequired:"Please select a target printer first",bindIpRequired:"Please set a bind IP first",accessCodeEmpty:"Access code cannot be empty",accessCodeLength:"Access code must be exactly 8 characters",created:"Virtual printer created",failedToCreate:"Failed to create virtual printer",deleted:"Virtual printer deleted",failedToDelete:"Failed to delete virtual printer"},list:{title:"Virtual Printers",add:"Add",addFirst:"Add Virtual Printer",empty:"No virtual printers configured. Add one to get started."},bindIp:{title:"Bind Interface",placeholder:"Select interface...",hint:"Network interface for this virtual printer to bind to. Must be unique per printer."},proxy:{accessCodeHint:"In proxy mode, use your target printer's access code in the slicer. The connection is forwarded transparently to the real printer."},addDialog:{title:"Add Virtual Printer",name:"Name",hint:"You can configure access code, target printer, and other settings after creating.",create:"Create"},deleteConfirm:{title:"Delete Virtual Printer",message:'Are you sure you want to delete "{{name}}"? This will stop all services for this printer.'}},modelViewer:{openInSlicer:"Open in Slicer",tabs:{model:"3D Model",gcode:"G-code Preview"},notAvailable:"not available",notSliced:"not sliced",plates:"Plates",allPlates:"All Plates",plateNumber:"Plate {{number}}",plateCount:"{{count}} plate",plateCount_other:"{{count}} plates",objectCount:"{{count}} object",objectCount_other:"{{count}} objects",filamentCount:"{{count}} filament",filamentCount_other:"{{count}} filaments",eta:"ETA {{minutes}} min",noPreview:"No preview available for this file",pagination:{pageOf:"Page {{current}} of {{total}}",prev:"Prev",next:"Next"},errors:{failedToLoad:"Failed to load file",noMeshes:"No meshes found in 3MF file",unsupportedFormat:"Unsupported file format"}},maintenanceDescriptions:{lubricateCarbonRods:"Apply lubricant to carbon rods for smooth motion",lubricateRails:"Apply lubricant to linear rails for smooth motion",cleanNozzle:"Clean hotend and nozzle to prevent clogs",checkBelts:"Verify belt tension for accurate prints",cleanBuildPlate:"Clean build plate for better adhesion",checkExtruder:"Inspect extruder gears for wear",checkCooling:"Ensure cooling fans are working properly",generalInspection:"General printer inspection",cleanCarbonRods:"Clean carbon rods to reduce friction",lubricateSteelRods:"Apply lubricant to steel rods for smooth motion",cleanSteelRods:"Clean steel rods to reduce friction",cleanLinearRails:"Wipe linear rails to remove dust and debris",checkPtfeTube:"Inspect PTFE tube for wear or damage",replaceHepaFilter:"Replace HEPA filter for air quality",replaceCarbonFilter:"Replace activated carbon filter",lubricateLeftNozzleRail:"Lubricate left nozzle rail (H2 series)"},smartPlugs:{offline:"Offline",admin:"Admin",openPlugAdminPage:"Open plug admin page",deleteSmartPlug:"Delete Smart Plug",turnOnSmartPlug:"Turn On Smart Plug",turnOffSmartPlug:"Turn Off Smart Plug",turnOn:"Turn On",turnOff:"Turn Off",addSmartPlug:{scanningNetwork:"Scanning network...",chooseEntity:"Choose an entity...",connectionFailed:"Connection failed",searchEntities:"Search entities...",searchPowerSensors:"Search power sensors...",searchEnergySensors:"Search energy sensors...",placeholders:{plugName:"Living Room Plug",mqttStateOnValue:"ON, true, 1",mqttSameAsPower:"Same as power topic, or different"}},linkedTo:"Linked to:",monitorOnly:"Monitor Only",alerts:"Alerts",scheduleOn:"On {{time}}",scheduleOff:"Off {{time}}",on:"On",off:"Off",power:"Power",kwhToday:"kWh Today",settings:"Settings",automationSettings:"Automation Settings",showInSwitchbar:"Show in Switchbar",quickAccessSidebar:"Quick access from sidebar",enabled:"Enabled",enableAutomation:"Enable automation for this plug",autoOn:"Auto On",autoOnDescription:"Turn on when print starts",autoOff:"Auto Off",autoOffDescription:"Turn off when print completes (one-shot)",autoOffPersistent:"Keep Enabled",autoOffPersistentDescription:"Stay enabled between prints instead of one-shot",turnOffDelayMode:"Turn Off Delay Mode",time:"Time",temp:"Temp",delayMinutes:"Delay (minutes)",tempThreshold:"Temperature threshold (°C)",tempThresholdDescription:"Turns off when nozzle cools below this temperature",edit:"Edit",deleteConfirm:'Are you sure you want to delete "{{name}}"? This cannot be undone.',turnOnConfirm:'Are you sure you want to turn on "{{name}}"?',turnOffConfirm:'Are you sure you want to turn off "{{name}}"? This will cut power to the connected device.',failedToTurn:'Failed to turn {{action}} "{{name}}"',unknown:"Unknown",addTitle:"Add Smart Plug",editTitle:"Edit Smart Plug",stopScanning:"Stop Scanning",discoverTasmota:"Discover Tasmota Devices",foundDevices:"Found {{count}} device(s) - click to select:",noDevicesFound:"No Tasmota devices found on your network",haNotConfigured:"Home Assistant is not configured. Set it up in",haSettingsPath:"Settings → Network → Home Assistant",selectEntity:"Select Entity *",ipAddress:"IP Address *",nameLabel:"Name *",username:"Username",password:"Password",authHint:"Leave empty if your Tasmota device doesn't require authentication",linkToPrinter:"Link to Printer",noPrinter:"No printer (manual control only)",linkingDescription:"Linking enables automatic on/off when prints start/complete",powerAlerts:"Power Alerts",alertAbove:"Alert if above (W)",alertBelow:"Alert if below (W)",alertDescription:"Get notified when power consumption crosses these thresholds. Leave empty to disable that direction.",dailySchedule:"Daily Schedule",turnOnAt:"Turn On at",turnOffAt:"Turn Off at",scheduleDescription:"Automatically turn the plug on/off at these times daily. Leave empty to skip that action.",showOnPrinterCard:"Show on Printer Card",displayOnPrinterCard:"Display button on printer card",connectedResult:"Connected!",deviceLabel:"Device: {{name}} - ",stateLabel:"State: {{state}}",test:"Test",delete:"Delete",save:"Save",add:"Add",cancel:"Cancel",failedToStartScan:"Failed to start scan",nameRequired:"Name is required",entityRequired:"Entity is required for Home Assistant plugs",mqttTopicRequired:"At least one MQTT topic must be configured for power, energy, or state monitoring",loadingEntities:"Loading entities...",loading:"Loading...",failedToLoadEntities:"Failed to load entities: {{error}}",noEntitiesMatching:'No entities found matching "{{search}}"',noEntitiesAvailable:"No entities available",searchingEntities:"Searching all entities ({{count}} found)",showingEntities:"Showing switch, light, input_boolean ({{count}} available)",energyMonitoringOptional:"Energy Monitoring (Optional)",energyMonitoringHint:"Search and select sensors that provide power/energy data.",powerSensorW:"Power Sensor (W)",energyTodayKwh:"Energy Today (kWh)",totalEnergyKwh:"Total Energy (kWh)",noMatchingSensors:"No matching sensors",none:"None",mqttNotConfigured:"MQTT broker not configured. Set broker address in",mqttSettingsPath:"Settings → Network → MQTT Publishing",mqttNotConfiguredSuffix:"(you don't need to enable publishing, just fill in the broker details).",mqttMonitorOnlyDescription:"MQTT plugs receive power/energy data via MQTT subscription. On/off control is not available - use your MQTT broker or home automation system.",powerMonitoring:"Power Monitoring",energyMonitoring:"Energy Monitoring",stateMonitoring:"State Monitoring",optional:"optional",topic:"Topic",jsonPath:"JSON Path",multiplier:"Multiplier",onValue:"ON Value",mqttPowerHint:`JSON path extracts value from JSON payload (e.g., "power_l1"). Leave empty if topic publishes raw numeric values. +`+M.stack}}var se=Object.prototype.hasOwnProperty,ge=t.unstable_scheduleCallback,pe=t.unstable_cancelCallback,le=t.unstable_shouldYield,B=t.unstable_requestPaint,R=t.unstable_now,ae=t.unstable_getCurrentPriorityLevel,ke=t.unstable_ImmediatePriority,Se=t.unstable_UserBlockingPriority,ye=t.unstable_NormalPriority,Te=t.unstable_LowPriority,ve=t.unstable_IdlePriority,Ae=t.log,Re=t.unstable_setDisableYieldValue,Me=null,Le=null;function Oe(h){if(typeof Ae=="function"&&Re(h),Le&&typeof Le.setStrictMode=="function")try{Le.setStrictMode(Me,h)}catch{}}var qe=Math.clz32?Math.clz32:he,Qe=Math.log,tt=Math.LN2;function he(h){return h>>>=0,h===0?32:31-(Qe(h)/tt|0)|0}var Fe=256,we=262144,Ve=4194304;function je(h){var y=h&42;if(y!==0)return y;switch(h&-h){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return h&261888;case 262144:case 524288:case 1048576:case 2097152:return h&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return h&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return h}}function ce(h,y,S){var M=h.pendingLanes;if(M===0)return 0;var $=0,Z=h.suspendedLanes,Ne=h.pingedLanes;h=h.warmLanes;var He=M&134217727;return He!==0?(M=He&~Z,M!==0?$=je(M):(Ne&=He,Ne!==0?$=je(Ne):S||(S=He&~h,S!==0&&($=je(S))))):(He=M&~Z,He!==0?$=je(He):Ne!==0?$=je(Ne):S||(S=M&~h,S!==0&&($=je(S)))),$===0?0:y!==0&&y!==$&&(y&Z)===0&&(Z=$&-$,S=y&-y,Z>=S||Z===32&&(S&4194048)!==0)?y:$}function xe(h,y){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&y)===0}function Be(h,y){switch(h){case 1:case 2:case 4:case 8:case 64:return y+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return y+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var h=Ve;return Ve<<=1,(Ve&62914560)===0&&(Ve=4194304),h}function pt(h){for(var y=[],S=0;31>S;S++)y.push(h);return y}function xt(h,y){h.pendingLanes|=y,y!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function yt(h,y,S,M,$,Z){var Ne=h.pendingLanes;h.pendingLanes=S,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=S,h.entangledLanes&=S,h.errorRecoveryDisabledLanes&=S,h.shellSuspendCounter=0;var He=h.entanglements,nt=h.expirationTimes,Nt=h.hiddenUpdates;for(S=Ne&~S;0"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var Dr=/[\n"\\]/g;function En(h){return h.replace(Dr,function(y){return"\\"+y.charCodeAt(0).toString(16)+" "})}function Ea(h,y,S,M,$,Z,Ne,He){h.name="",Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"?h.type=Ne:h.removeAttribute("type"),y!=null?Ne==="number"?(y===0&&h.value===""||h.value!=y)&&(h.value=""+zn(y)):h.value!==""+zn(y)&&(h.value=""+zn(y)):Ne!=="submit"&&Ne!=="reset"||h.removeAttribute("value"),y!=null?na(h,Ne,zn(y)):S!=null?na(h,Ne,zn(S)):M!=null&&h.removeAttribute("value"),$==null&&Z!=null&&(h.defaultChecked=!!Z),$!=null&&(h.checked=$&&typeof $!="function"&&typeof $!="symbol"),He!=null&&typeof He!="function"&&typeof He!="symbol"&&typeof He!="boolean"?h.name=""+zn(He):h.removeAttribute("name")}function Pn(h,y,S,M,$,Z,Ne,He){if(Z!=null&&typeof Z!="function"&&typeof Z!="symbol"&&typeof Z!="boolean"&&(h.type=Z),y!=null||S!=null){if(!(Z!=="submit"&&Z!=="reset"||y!=null)){gn(h);return}S=S!=null?""+zn(S):"",y=y!=null?""+zn(y):S,He||y===h.value||(h.value=y),h.defaultValue=y}M=M??$,M=typeof M!="function"&&typeof M!="symbol"&&!!M,h.checked=He?h.checked:!!M,h.defaultChecked=!!M,Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"&&(h.name=Ne),gn(h)}function na(h,y,S){y==="number"&&gr(h.ownerDocument)===h||h.defaultValue===""+S||(h.defaultValue=""+S)}function qn(h,y,S,M){if(h=h.options,y){y={};for(var $=0;$"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),kl=!1;if(Ns)try{var ns={};Object.defineProperty(ns,"passive",{get:function(){kl=!0}}),window.addEventListener("test",ns,ns),window.removeEventListener("test",ns,ns)}catch{kl=!1}var $o=null,Nl=null,wc=null;function vo(){if(wc)return wc;var h,y=Nl,S=y.length,M,$="value"in $o?$o.value:$o.textContent,Z=$.length;for(h=0;h=ct),ir=" ",aa=!1;function ka(h,y){switch(h){case"keyup":return Ht.indexOf(y.keyCode)!==-1;case"keydown":return y.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function an(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var wn=!1;function Da(h,y){switch(h){case"compositionend":return an(y);case"keypress":return y.which!==32?null:(aa=!0,ir);case"textInput":return h=y.data,h===ir&&aa?null:h;default:return null}}function di(h,y){if(wn)return h==="compositionend"||!Zt&&ka(h,y)?(h=vo(),wc=Nl=$o=null,wn=!1,h):null;switch(h){case"paste":return null;case"keypress":if(!(y.ctrlKey||y.altKey||y.metaKey)||y.ctrlKey&&y.altKey){if(y.char&&1=y)return{node:S,offset:y-h};h=M}e:{for(;S;){if(S.nextSibling){S=S.nextSibling;break e}S=S.parentNode}S=void 0}S=BS(S)}}function b5(h,y){return h&&y?h===y?!0:h&&h.nodeType===3?!1:y&&y.nodeType===3?b5(h,y.parentNode):"contains"in h?h.contains(y):h.compareDocumentPosition?!!(h.compareDocumentPosition(y)&16):!1:!1}function x5(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var y=gr(h.document);y instanceof h.HTMLIFrameElement;){try{var S=typeof y.contentWindow.location.href=="string"}catch{S=!1}if(S)h=y.contentWindow;else break;y=gr(h.document)}return y}function wA(h){var y=h&&h.nodeName&&h.nodeName.toLowerCase();return y&&(y==="input"&&(h.type==="text"||h.type==="search"||h.type==="tel"||h.type==="url"||h.type==="password")||y==="textarea"||h.contentEditable==="true")}var hce=Ns&&"documentMode"in document&&11>=document.documentMode,Gg=null,SA=null,Vy=null,_A=!1;function y5(h,y,S){var M=S.window===S?S.document:S.nodeType===9?S:S.ownerDocument;_A||Gg==null||Gg!==gr(M)||(M=Gg,"selectionStart"in M&&wA(M)?M={start:M.selectionStart,end:M.selectionEnd}:(M=(M.ownerDocument&&M.ownerDocument.defaultView||window).getSelection(),M={anchorNode:M.anchorNode,anchorOffset:M.anchorOffset,focusNode:M.focusNode,focusOffset:M.focusOffset}),Vy&&Um(Vy,M)||(Vy=M,M=A_(SA,"onSelect"),0>=Ne,$-=Ne,md=1<<32-qe(y)+$|S<<$|M,hd=Z+h}else md=1<Zn?(yr=bn,bn=null):yr=bn.sibling;var Ar=Ct(bt,bn,kt[Zn],Ot);if(Ar===null){bn===null&&(bn=yr);break}h&&bn&&Ar.alternate===null&&y(bt,bn),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar,bn=yr}if(Zn===kt.length)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;ZnZn?(yr=bn,bn=null):yr=bn.sibling;var lh=Ct(bt,bn,Ar.value,Ot);if(lh===null){bn===null&&(bn=yr);break}h&&bn&&lh.alternate===null&&y(bt,bn),ut=Z(lh,ut,Zn),Tr===null?Cn=lh:Tr.sibling=lh,Tr=lh,bn=yr}if(Ar.done)return S(bt,bn),wr&&lu(bt,Zn),Cn;if(bn===null){for(;!Ar.done;Zn++,Ar=kt.next())Ar=zt(bt,Ar.value,Ot),Ar!==null&&(ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return wr&&lu(bt,Zn),Cn}for(bn=M(bn);!Ar.done;Zn++,Ar=kt.next())Ar=Et(bn,bt,Zn,Ar.value,Ot),Ar!==null&&(h&&Ar.alternate!==null&&bn.delete(Ar.key===null?Zn:Ar.key),ut=Z(Ar,ut,Zn),Tr===null?Cn=Ar:Tr.sibling=Ar,Tr=Ar);return h&&bn.forEach(function(Dde){return y(bt,Dde)}),wr&&lu(bt,Zn),Cn}function Wr(bt,ut,kt,Ot){if(typeof kt=="object"&&kt!==null&&kt.type===v&&kt.key===null&&(kt=kt.props.children),typeof kt=="object"&&kt!==null){switch(kt.$$typeof){case f:e:{for(var Cn=kt.key;ut!==null;){if(ut.key===Cn){if(Cn=kt.type,Cn===v){if(ut.tag===7){S(bt,ut.sibling),Ot=$(ut,kt.props.children),Ot.return=bt,bt=Ot;break e}}else if(ut.elementType===Cn||typeof Cn=="object"&&Cn!==null&&Cn.$$typeof===F&&Yp(Cn)===ut.type){S(bt,ut.sibling),Ot=$(ut,kt.props),Qy(Ot,kt),Ot.return=bt,bt=Ot;break e}S(bt,ut);break}else y(bt,ut);ut=ut.sibling}kt.type===v?(Ot=Vp(kt.props.children,bt.mode,Ot,kt.key),Ot.return=bt,bt=Ot):(Ot=GS(kt.type,kt.key,kt.props,null,bt.mode,Ot),Qy(Ot,kt),Ot.return=bt,bt=Ot)}return Ne(bt);case x:e:{for(Cn=kt.key;ut!==null;){if(ut.key===Cn)if(ut.tag===4&&ut.stateNode.containerInfo===kt.containerInfo&&ut.stateNode.implementation===kt.implementation){S(bt,ut.sibling),Ot=$(ut,kt.children||[]),Ot.return=bt,bt=Ot;break e}else{S(bt,ut);break}else y(bt,ut);ut=ut.sibling}Ot=jA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot}return Ne(bt);case F:return kt=Yp(kt),Wr(bt,ut,kt,Ot)}if(te(kt))return mn(bt,ut,kt,Ot);if(z(kt)){if(Cn=z(kt),typeof Cn!="function")throw Error(r(150));return kt=Cn.call(kt),Fn(bt,ut,kt,Ot)}if(typeof kt.then=="function")return Wr(bt,ut,JS(kt),Ot);if(kt.$$typeof===C)return Wr(bt,ut,XS(bt,kt),Ot);e_(bt,kt)}return typeof kt=="string"&&kt!==""||typeof kt=="number"||typeof kt=="bigint"?(kt=""+kt,ut!==null&&ut.tag===6?(S(bt,ut.sibling),Ot=$(ut,kt),Ot.return=bt,bt=Ot):(S(bt,ut),Ot=AA(kt,bt.mode,Ot),Ot.return=bt,bt=Ot),Ne(bt)):S(bt,ut)}return function(bt,ut,kt,Ot){try{Yy=0;var Cn=Wr(bt,ut,kt,Ot);return rb=null,Cn}catch(bn){if(bn===nb||bn===QS)throw bn;var Tr=Yo(29,bn,null,bt.mode);return Tr.lanes=Ot,Tr.return=bt,Tr}}}var Zp=H5(!0),q5=H5(!1),Vm=!1;function HA(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function qA(h,y){h=h.updateQueue,y.updateQueue===h&&(y.updateQueue={baseState:h.baseState,firstBaseUpdate:h.firstBaseUpdate,lastBaseUpdate:h.lastBaseUpdate,shared:h.shared,callbacks:null})}function Gm(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function Wm(h,y,S){var M=h.updateQueue;if(M===null)return null;if(M=M.shared,(Fr&2)!==0){var $=M.pending;return $===null?y.next=y:(y.next=$.next,$.next=y),M.pending=y,y=VS(h),C5(h,null,S),y}return $S(h,M,y,S),VS(h)}function Zy(h,y,S){if(y=y.updateQueue,y!==null&&(y=y.shared,(S&4194048)!==0)){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}function $A(h,y){var S=h.updateQueue,M=h.alternate;if(M!==null&&(M=M.updateQueue,S===M)){var $=null,Z=null;if(S=S.firstBaseUpdate,S!==null){do{var Ne={lane:S.lane,tag:S.tag,payload:S.payload,callback:null,next:null};Z===null?$=Z=Ne:Z=Z.next=Ne,S=S.next}while(S!==null);Z===null?$=Z=y:Z=Z.next=y}else $=Z=y;S={baseState:M.baseState,firstBaseUpdate:$,lastBaseUpdate:Z,shared:M.shared,callbacks:M.callbacks},h.updateQueue=S;return}h=S.lastBaseUpdate,h===null?S.firstBaseUpdate=y:h.next=y,S.lastBaseUpdate=y}var VA=!1;function Jy(){if(VA){var h=tb;if(h!==null)throw h}}function ev(h,y,S,M){VA=!1;var $=h.updateQueue;Vm=!1;var Z=$.firstBaseUpdate,Ne=$.lastBaseUpdate,He=$.shared.pending;if(He!==null){$.shared.pending=null;var nt=He,Nt=nt.next;nt.next=null,Ne===null?Z=Nt:Ne.next=Nt,Ne=nt;var Lt=h.alternate;Lt!==null&&(Lt=Lt.updateQueue,He=Lt.lastBaseUpdate,He!==Ne&&(He===null?Lt.firstBaseUpdate=Nt:He.next=Nt,Lt.lastBaseUpdate=nt))}if(Z!==null){var zt=$.baseState;Ne=0,Lt=Nt=nt=null,He=Z;do{var Ct=He.lane&-536870913,Et=Ct!==He.lane;if(Et?(xr&Ct)===Ct:(M&Ct)===Ct){Ct!==0&&Ct===eb&&(VA=!0),Lt!==null&&(Lt=Lt.next={lane:0,tag:He.tag,payload:He.payload,callback:null,next:null});e:{var mn=h,Fn=He;Ct=y;var Wr=S;switch(Fn.tag){case 1:if(mn=Fn.payload,typeof mn=="function"){zt=mn.call(Wr,zt,Ct);break e}zt=mn;break e;case 3:mn.flags=mn.flags&-65537|128;case 0:if(mn=Fn.payload,Ct=typeof mn=="function"?mn.call(Wr,zt,Ct):mn,Ct==null)break e;zt=m({},zt,Ct);break e;case 2:Vm=!0}}Ct=He.callback,Ct!==null&&(h.flags|=64,Et&&(h.flags|=8192),Et=$.callbacks,Et===null?$.callbacks=[Ct]:Et.push(Ct))}else Et={lane:Ct,tag:He.tag,payload:He.payload,callback:He.callback,next:null},Lt===null?(Nt=Lt=Et,nt=zt):Lt=Lt.next=Et,Ne|=Ct;if(He=He.next,He===null){if(He=$.shared.pending,He===null)break;Et=He,He=Et.next,Et.next=null,$.lastBaseUpdate=Et,$.shared.pending=null}}while(!0);Lt===null&&(nt=zt),$.baseState=nt,$.firstBaseUpdate=Nt,$.lastBaseUpdate=Lt,Z===null&&($.shared.lanes=0),Zm|=Ne,h.lanes=Ne,h.memoizedState=zt}}function $5(h,y){if(typeof h!="function")throw Error(r(191,h));h.call(y)}function V5(h,y){var S=h.callbacks;if(S!==null)for(h.callbacks=null,h=0;hZ?Z:8;var Ne=ie.T,He={};ie.T=He,dj(h,!1,y,S);try{var nt=$(),Nt=ie.S;if(Nt!==null&&Nt(He,nt),nt!==null&&typeof nt=="object"&&typeof nt.then=="function"){var Lt=Sce(nt,M);rv(h,y,Lt,tl(h))}else rv(h,y,M,tl(h))}catch(zt){rv(h,y,{then:function(){},status:"rejected",reason:zt},tl())}finally{J.p=Z,Ne!==null&&He.types!==null&&(Ne.types=He.types),ie.T=Ne}}function Tce(){}function lj(h,y,S,M){if(h.tag!==5)throw Error(r(476));var $=_U(h).queue;SU(h,$,y,oe,S===null?Tce:function(){return kU(h),S(M)})}function _U(h){var y=h.memoizedState;if(y!==null)return y;y={memoizedState:oe,baseState:oe,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:oe},next:null};var S={};return y.next={memoizedState:S,baseState:S,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:mu,lastRenderedState:S},next:null},h.memoizedState=y,h=h.alternate,h!==null&&(h.memoizedState=y),y}function kU(h){var y=_U(h);y.next===null&&(y=h.alternate.memoizedState),rv(h,y.next.queue,{},tl())}function cj(){return as(vv)}function NU(){return ai().memoizedState}function CU(){return ai().memoizedState}function Ace(h){for(var y=h.return;y!==null;){switch(y.tag){case 24:case 3:var S=tl();h=Gm(S);var M=Wm(y,h,S);M!==null&&(Co(M,y,S),Zy(M,y,S)),y={cache:IA()},h.payload=y;return}y=y.return}}function jce(h,y,S){var M=tl();S={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null},d_(h)?TU(y,S):(S=PA(h,y,S,M),S!==null&&(Co(S,h,M),AU(S,y,M)))}function PU(h,y,S){var M=tl();rv(h,y,S,M)}function rv(h,y,S,M){var $={lane:M,revertLane:0,gesture:null,action:S,hasEagerState:!1,eagerState:null,next:null};if(d_(h))TU(y,$);else{var Z=h.alternate;if(h.lanes===0&&(Z===null||Z.lanes===0)&&(Z=y.lastRenderedReducer,Z!==null))try{var Ne=y.lastRenderedState,He=Z(Ne,S);if($.hasEagerState=!0,$.eagerState=He,js(He,Ne))return $S(h,y,$,0),oa===null&&qS(),!1}catch{}if(S=PA(h,y,$,M),S!==null)return Co(S,h,M),AU(S,y,M),!0}return!1}function dj(h,y,S,M){if(M={lane:2,revertLane:Hj(),gesture:null,action:M,hasEagerState:!1,eagerState:null,next:null},d_(h)){if(y)throw Error(r(479))}else y=PA(h,S,M,2),y!==null&&Co(y,h,2)}function d_(h){var y=h.alternate;return h===Yn||y!==null&&y===Yn}function TU(h,y){ib=r_=!0;var S=h.pending;S===null?y.next=y:(y.next=S.next,S.next=y),h.pending=y}function AU(h,y,S){if((S&4194048)!==0){var M=y.lanes;M&=h.pendingLanes,S|=M,y.lanes=S,Kt(h,S)}}var av={readContext:as,use:s_,useCallback:Ba,useContext:Ba,useEffect:Ba,useImperativeHandle:Ba,useLayoutEffect:Ba,useInsertionEffect:Ba,useMemo:Ba,useReducer:Ba,useRef:Ba,useState:Ba,useDebugValue:Ba,useDeferredValue:Ba,useTransition:Ba,useSyncExternalStore:Ba,useId:Ba,useHostTransitionStatus:Ba,useFormState:Ba,useActionState:Ba,useOptimistic:Ba,useMemoCache:Ba,useCacheRefresh:Ba};av.useEffectEvent=Ba;var jU={readContext:as,use:s_,useCallback:function(h,y){return Qs().memoizedState=[h,y===void 0?null:y],h},useContext:as,useEffect:hU,useImperativeHandle:function(h,y,S){S=S!=null?S.concat([h]):null,l_(4194308,4,bU.bind(null,y,h),S)},useLayoutEffect:function(h,y){return l_(4194308,4,h,y)},useInsertionEffect:function(h,y){l_(4,2,h,y)},useMemo:function(h,y){var S=Qs();y=y===void 0?null:y;var M=h();if(Jp){Oe(!0);try{h()}finally{Oe(!1)}}return S.memoizedState=[M,y],M},useReducer:function(h,y,S){var M=Qs();if(S!==void 0){var $=S(y);if(Jp){Oe(!0);try{S(y)}finally{Oe(!1)}}}else $=y;return M.memoizedState=M.baseState=$,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:$},M.queue=h,h=h.dispatch=jce.bind(null,Yn,h),[M.memoizedState,h]},useRef:function(h){var y=Qs();return h={current:h},y.memoizedState=h},useState:function(h){h=rj(h);var y=h.queue,S=PU.bind(null,Yn,y);return y.dispatch=S,[h.memoizedState,S]},useDebugValue:sj,useDeferredValue:function(h,y){var S=Qs();return oj(S,h,y)},useTransition:function(){var h=rj(!1);return h=SU.bind(null,Yn,h.queue,!0,!1),Qs().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,y,S){var M=Yn,$=Qs();if(wr){if(S===void 0)throw Error(r(407));S=S()}else{if(S=y(),oa===null)throw Error(r(349));(xr&127)!==0||Q5(M,y,S)}$.memoizedState=S;var Z={value:S,getSnapshot:y};return $.queue=Z,hU(J5.bind(null,M,Z,h),[h]),M.flags|=2048,ob(9,{destroy:void 0},Z5.bind(null,M,Z,S,y),null),S},useId:function(){var h=Qs(),y=oa.identifierPrefix;if(wr){var S=hd,M=md;S=(M&~(1<<32-qe(M)-1)).toString(32)+S,y="_"+y+"R_"+S,S=a_++,0<\/script>",Z=Z.removeChild(Z.firstChild);break;case"select":Z=typeof M.is=="string"?Ne.createElement("select",{is:M.is}):Ne.createElement("select"),M.multiple?Z.multiple=!0:M.size&&(Z.size=M.size);break;default:Z=typeof M.is=="string"?Ne.createElement($,{is:M.is}):Ne.createElement($)}}Z[at]=y,Z[dt]=M;e:for(Ne=y.child;Ne!==null;){if(Ne.tag===5||Ne.tag===6)Z.appendChild(Ne.stateNode);else if(Ne.tag!==4&&Ne.tag!==27&&Ne.child!==null){Ne.child.return=Ne,Ne=Ne.child;continue}if(Ne===y)break e;for(;Ne.sibling===null;){if(Ne.return===null||Ne.return===y)break e;Ne=Ne.return}Ne.sibling.return=Ne.return,Ne=Ne.sibling}y.stateNode=Z;e:switch(ss(Z,$,M),$){case"button":case"input":case"select":case"textarea":M=!!M.autoFocus;break e;case"img":M=!0;break e;default:M=!1}M&&pu(y)}}return va(y),kj(y,y.type,h===null?null:h.memoizedProps,y.pendingProps,S),null;case 6:if(h&&y.stateNode!=null)h.memoizedProps!==M&&pu(y);else{if(typeof M!="string"&&y.stateNode===null)throw Error(r(166));if(h=q.current,Zg(y)){if(h=y.stateNode,S=y.memoizedProps,M=null,$=rs,$!==null)switch($.tag){case 27:case 5:M=$.memoizedProps}h[at]=y,h=!!(h.nodeValue===S||M!==null&&M.suppressHydrationWarning===!0||XB(h.nodeValue,S)),h||qm(y,!0)}else h=j_(h).createTextNode(M),h[at]=y,y.stateNode=h}return va(y),null;case 31:if(S=y.memoizedState,h===null||h.memoizedState!==null){if(M=Zg(y),S!==null){if(h===null){if(!M)throw Error(r(318));if(h=y.memoizedState,h=h!==null?h.dehydrated:null,!h)throw Error(r(557));h[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),h=!1}else S=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=S),h=!0;if(!h)return y.flags&256?(Zo(y),y):(Zo(y),null);if((y.flags&128)!==0)throw Error(r(558))}return va(y),null;case 13:if(M=y.memoizedState,h===null||h.memoizedState!==null&&h.memoizedState.dehydrated!==null){if($=Zg(y),M!==null&&M.dehydrated!==null){if(h===null){if(!$)throw Error(r(318));if($=y.memoizedState,$=$!==null?$.dehydrated:null,!$)throw Error(r(317));$[at]=y}else Gp(),(y.flags&128)===0&&(y.memoizedState=null),y.flags|=4;va(y),$=!1}else $=FA(),h!==null&&h.memoizedState!==null&&(h.memoizedState.hydrationErrors=$),$=!0;if(!$)return y.flags&256?(Zo(y),y):(Zo(y),null)}return Zo(y),(y.flags&128)!==0?(y.lanes=S,y):(S=M!==null,h=h!==null&&h.memoizedState!==null,S&&(M=y.child,$=null,M.alternate!==null&&M.alternate.memoizedState!==null&&M.alternate.memoizedState.cachePool!==null&&($=M.alternate.memoizedState.cachePool.pool),Z=null,M.memoizedState!==null&&M.memoizedState.cachePool!==null&&(Z=M.memoizedState.cachePool.pool),Z!==$&&(M.flags|=2048)),S!==h&&S&&(y.child.flags|=8192),f_(y,y.updateQueue),va(y),null);case 4:return j(),h===null&&Gj(y.stateNode.containerInfo),va(y),null;case 10:return du(y.type),va(y),null;case 19:if(ne(ri),M=y.memoizedState,M===null)return va(y),null;if($=(y.flags&128)!==0,Z=M.rendering,Z===null)if($)sv(M,!1);else{if(Ha!==0||h!==null&&(h.flags&128)!==0)for(h=y.child;h!==null;){if(Z=n_(h),Z!==null){for(y.flags|=128,sv(M,!1),h=Z.updateQueue,y.updateQueue=h,f_(y,h),y.subtreeFlags=0,h=S,S=y.child;S!==null;)P5(S,h),S=S.sibling;return me(ri,ri.current&1|2),wr&&lu(y,M.treeForkCount),y.child}h=h.sibling}M.tail!==null&&R()>v_&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304)}else{if(!$)if(h=n_(Z),h!==null){if(y.flags|=128,$=!0,h=h.updateQueue,y.updateQueue=h,f_(y,h),sv(M,!0),M.tail===null&&M.tailMode==="hidden"&&!Z.alternate&&!wr)return va(y),null}else 2*R()-M.renderingStartTime>v_&&S!==536870912&&(y.flags|=128,$=!0,sv(M,!1),y.lanes=4194304);M.isBackwards?(Z.sibling=y.child,y.child=Z):(h=M.last,h!==null?h.sibling=Z:y.child=Z,M.last=Z)}return M.tail!==null?(h=M.tail,M.rendering=h,M.tail=h.sibling,M.renderingStartTime=R(),h.sibling=null,S=ri.current,me(ri,$?S&1|2:S&1),wr&&lu(y,M.treeForkCount),h):(va(y),null);case 22:case 23:return Zo(y),WA(),M=y.memoizedState!==null,h!==null?h.memoizedState!==null!==M&&(y.flags|=8192):M&&(y.flags|=8192),M?(S&536870912)!==0&&(y.flags&128)===0&&(va(y),y.subtreeFlags&6&&(y.flags|=8192)):va(y),S=y.updateQueue,S!==null&&f_(y,S.retryQueue),S=null,h!==null&&h.memoizedState!==null&&h.memoizedState.cachePool!==null&&(S=h.memoizedState.cachePool.pool),M=null,y.memoizedState!==null&&y.memoizedState.cachePool!==null&&(M=y.memoizedState.cachePool.pool),M!==S&&(y.flags|=2048),h!==null&&ne(Xp),null;case 24:return S=null,h!==null&&(S=h.memoizedState.cache),y.memoizedState.cache!==S&&(y.flags|=2048),du(ui),va(y),null;case 25:return null;case 30:return null}throw Error(r(156,y.tag))}function Rce(h,y){switch(EA(y),y.tag){case 1:return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 3:return du(ui),j(),h=y.flags,(h&65536)!==0&&(h&128)===0?(y.flags=h&-65537|128,y):null;case 26:case 27:case 5:return K(y),null;case 31:if(y.memoizedState!==null){if(Zo(y),y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 13:if(Zo(y),h=y.memoizedState,h!==null&&h.dehydrated!==null){if(y.alternate===null)throw Error(r(340));Gp()}return h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 19:return ne(ri),null;case 4:return j(),null;case 10:return du(y.type),null;case 22:case 23:return Zo(y),WA(),h!==null&&ne(Xp),h=y.flags,h&65536?(y.flags=h&-65537|128,y):null;case 24:return du(ui),null;case 25:return null;default:return null}}function eB(h,y){switch(EA(y),y.tag){case 3:du(ui),j();break;case 26:case 27:case 5:K(y);break;case 4:j();break;case 31:y.memoizedState!==null&&Zo(y);break;case 13:Zo(y);break;case 19:ne(ri);break;case 10:du(y.type);break;case 22:case 23:Zo(y),WA(),h!==null&&ne(Xp);break;case 24:du(ui)}}function ov(h,y){try{var S=y.updateQueue,M=S!==null?S.lastEffect:null;if(M!==null){var $=M.next;S=$;do{if((S.tag&h)===h){M=void 0;var Z=S.create,Ne=S.inst;M=Z(),Ne.destroy=M}S=S.next}while(S!==$)}}catch(He){Br(y,y.return,He)}}function Ym(h,y,S){try{var M=y.updateQueue,$=M!==null?M.lastEffect:null;if($!==null){var Z=$.next;M=Z;do{if((M.tag&h)===h){var Ne=M.inst,He=Ne.destroy;if(He!==void 0){Ne.destroy=void 0,$=y;var nt=S,Nt=He;try{Nt()}catch(Lt){Br($,nt,Lt)}}}M=M.next}while(M!==Z)}}catch(Lt){Br(y,y.return,Lt)}}function tB(h){var y=h.updateQueue;if(y!==null){var S=h.stateNode;try{V5(y,S)}catch(M){Br(h,h.return,M)}}}function nB(h,y,S){S.props=ef(h.type,h.memoizedProps),S.state=h.memoizedState;try{S.componentWillUnmount()}catch(M){Br(h,y,M)}}function lv(h,y){try{var S=h.ref;if(S!==null){switch(h.tag){case 26:case 27:case 5:var M=h.stateNode;break;case 30:M=h.stateNode;break;default:M=h.stateNode}typeof S=="function"?h.refCleanup=S(M):S.current=M}}catch($){Br(h,y,$)}}function pd(h,y){var S=h.ref,M=h.refCleanup;if(S!==null)if(typeof M=="function")try{M()}catch($){Br(h,y,$)}finally{h.refCleanup=null,h=h.alternate,h!=null&&(h.refCleanup=null)}else if(typeof S=="function")try{S(null)}catch($){Br(h,y,$)}else S.current=null}function rB(h){var y=h.type,S=h.memoizedProps,M=h.stateNode;try{e:switch(y){case"button":case"input":case"select":case"textarea":S.autoFocus&&M.focus();break e;case"img":S.src?M.src=S.src:S.srcSet&&(M.srcset=S.srcSet)}}catch($){Br(h,h.return,$)}}function Nj(h,y,S){try{var M=h.stateNode;rde(M,h.type,S,y),M[dt]=y}catch($){Br(h,h.return,$)}}function aB(h){return h.tag===5||h.tag===3||h.tag===26||h.tag===27&&rh(h.type)||h.tag===4}function Cj(h){e:for(;;){for(;h.sibling===null;){if(h.return===null||aB(h.return))return null;h=h.return}for(h.sibling.return=h.return,h=h.sibling;h.tag!==5&&h.tag!==6&&h.tag!==18;){if(h.tag===27&&rh(h.type)||h.flags&2||h.child===null||h.tag===4)continue e;h.child.return=h,h=h.child}if(!(h.flags&2))return h.stateNode}}function Pj(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?(S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S).insertBefore(h,y):(y=S.nodeType===9?S.body:S.nodeName==="HTML"?S.ownerDocument.body:S,y.appendChild(h),S=S._reactRootContainer,S!=null||y.onclick!==null||(y.onclick=qt));else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode,y=null),h=h.child,h!==null))for(Pj(h,y,S),h=h.sibling;h!==null;)Pj(h,y,S),h=h.sibling}function g_(h,y,S){var M=h.tag;if(M===5||M===6)h=h.stateNode,y?S.insertBefore(h,y):S.appendChild(h);else if(M!==4&&(M===27&&rh(h.type)&&(S=h.stateNode),h=h.child,h!==null))for(g_(h,y,S),h=h.sibling;h!==null;)g_(h,y,S),h=h.sibling}function iB(h){var y=h.stateNode,S=h.memoizedProps;try{for(var M=h.type,$=y.attributes;$.length;)y.removeAttributeNode($[0]);ss(y,M,S),y[at]=h,y[dt]=S}catch(Z){Br(h,h.return,Z)}}var fu=!1,pi=!1,Tj=!1,sB=typeof WeakSet=="function"?WeakSet:Set,Hi=null;function Lce(h,y){if(h=h.containerInfo,Xj=O_,h=x5(h),wA(h)){if("selectionStart"in h)var S={start:h.selectionStart,end:h.selectionEnd};else e:{S=(S=h.ownerDocument)&&S.defaultView||window;var M=S.getSelection&&S.getSelection();if(M&&M.rangeCount!==0){S=M.anchorNode;var $=M.anchorOffset,Z=M.focusNode;M=M.focusOffset;try{S.nodeType,Z.nodeType}catch{S=null;break e}var Ne=0,He=-1,nt=-1,Nt=0,Lt=0,zt=h,Ct=null;t:for(;;){for(var Et;zt!==S||$!==0&&zt.nodeType!==3||(He=Ne+$),zt!==Z||M!==0&&zt.nodeType!==3||(nt=Ne+M),zt.nodeType===3&&(Ne+=zt.nodeValue.length),(Et=zt.firstChild)!==null;)Ct=zt,zt=Et;for(;;){if(zt===h)break t;if(Ct===S&&++Nt===$&&(He=Ne),Ct===Z&&++Lt===M&&(nt=Ne),(Et=zt.nextSibling)!==null)break;zt=Ct,Ct=zt.parentNode}zt=Et}S=He===-1||nt===-1?null:{start:He,end:nt}}else S=null}S=S||{start:0,end:0}}else S=null;for(Yj={focusedElem:h,selectionRange:S},O_=!1,Hi=y;Hi!==null;)if(y=Hi,h=y.child,(y.subtreeFlags&1028)!==0&&h!==null)h.return=y,Hi=h;else for(;Hi!==null;){switch(y=Hi,Z=y.alternate,h=y.flags,y.tag){case 0:if((h&4)!==0&&(h=y.updateQueue,h=h!==null?h.events:null,h!==null))for(S=0;S title"))),ss(Z,M,S),Z[at]=h,Ke(Z),M=Z;break e;case"link":var Ne=m8("link","href",$).get(M+(S.href||""));if(Ne){for(var He=0;HeWr&&(Ne=Wr,Wr=Fn,Fn=Ne);var bt=g5(He,Fn),ut=g5(He,Wr);if(bt&&ut&&(Et.rangeCount!==1||Et.anchorNode!==bt.node||Et.anchorOffset!==bt.offset||Et.focusNode!==ut.node||Et.focusOffset!==ut.offset)){var kt=zt.createRange();kt.setStart(bt.node,bt.offset),Et.removeAllRanges(),Fn>Wr?(Et.addRange(kt),Et.extend(ut.node,ut.offset)):(kt.setEnd(ut.node,ut.offset),Et.addRange(kt))}}}}for(zt=[],Et=He;Et=Et.parentNode;)Et.nodeType===1&&zt.push({element:Et,left:Et.scrollLeft,top:Et.scrollTop});for(typeof He.focus=="function"&&He.focus(),He=0;HeS?32:S,ie.T=null,S=Rj,Rj=null;var Z=eh,Ne=vu;if(Ti=0,mb=eh=null,vu=0,(Fr&6)!==0)throw Error(r(331));var He=Fr;if(Fr|=4,bB(Z.current),pB(Z,Z.current,Ne,S),Fr=He,pv(0,!1),Le&&typeof Le.onPostCommitFiberRoot=="function")try{Le.onPostCommitFiberRoot(Me,Z)}catch{}return!0}finally{J.p=$,ie.T=M,RB(h,y)}}function OB(h,y,S){y=Al(S,y),y=pj(h.stateNode,y,2),h=Wm(h,y,2),h!==null&&(xt(h,2),fd(h))}function Br(h,y,S){if(h.tag===3)OB(h,h,S);else for(;y!==null;){if(y.tag===3){OB(y,h,S);break}else if(y.tag===1){var M=y.stateNode;if(typeof y.type.getDerivedStateFromError=="function"||typeof M.componentDidCatch=="function"&&(Jm===null||!Jm.has(M))){h=Al(S,h),S=IU(2),M=Wm(y,S,2),M!==null&&(zU(S,M,y,h),xt(M,2),fd(M));break}}y=y.return}}function zj(h,y,S){var M=h.pingCache;if(M===null){M=h.pingCache=new zce;var $=new Set;M.set(y,$)}else $=M.get(y),$===void 0&&($=new Set,M.set(y,$));$.has(S)||(Mj=!0,$.add(S),h=$ce.bind(null,h,y,S),y.then(h,h))}function $ce(h,y,S){var M=h.pingCache;M!==null&&M.delete(y),h.pingedLanes|=h.suspendedLanes&S,h.warmLanes&=~S,oa===h&&(xr&S)===S&&(Ha===4||Ha===3&&(xr&62914560)===xr&&300>R()-y_?(Fr&2)===0&&hb(h,0):Ej|=S,ub===xr&&(ub=0)),fd(h)}function IB(h,y){y===0&&(y=Ze()),h=$p(h,y),h!==null&&(xt(h,y),fd(h))}function Vce(h){var y=h.memoizedState,S=0;y!==null&&(S=y.retryLane),IB(h,S)}function Gce(h,y){var S=0;switch(h.tag){case 31:case 13:var M=h.stateNode,$=h.memoizedState;$!==null&&(S=$.retryLane);break;case 19:M=h.stateNode;break;case 22:M=h.stateNode._retryCache;break;default:throw Error(r(314))}M!==null&&M.delete(y),IB(h,S)}function Wce(h,y){return ge(h,y)}var C_=null,fb=null,Uj=!1,P_=!1,Bj=!1,nh=0;function fd(h){h!==fb&&h.next===null&&(fb===null?C_=fb=h:fb=fb.next=h),P_=!0,Uj||(Uj=!0,Xce())}function pv(h,y){if(!Bj&&P_){Bj=!0;do for(var S=!1,M=C_;M!==null;){if(h!==0){var $=M.pendingLanes;if($===0)var Z=0;else{var Ne=M.suspendedLanes,He=M.pingedLanes;Z=(1<<31-qe(42|h)+1)-1,Z&=$&~(Ne&~He),Z=Z&201326741?Z&201326741|1:Z?Z|2:0}Z!==0&&(S=!0,HB(M,Z))}else Z=xr,Z=ce(M,M===oa?Z:0,M.cancelPendingCommit!==null||M.timeoutHandle!==-1),(Z&3)===0||xe(M,Z)||(S=!0,HB(M,Z));M=M.next}while(S);Bj=!1}}function Kce(){zB()}function zB(){P_=Uj=!1;var h=0;nh!==0&&ide()&&(h=nh);for(var y=R(),S=null,M=C_;M!==null;){var $=M.next,Z=UB(M,y);Z===0?(M.next=null,S===null?C_=$:S.next=$,$===null&&(fb=S)):(S=M,(h!==0||(Z&3)!==0)&&(P_=!0)),M=$}Ti!==0&&Ti!==5||pv(h),nh!==0&&(nh=0)}function UB(h,y){for(var S=h.suspendedLanes,M=h.pingedLanes,$=h.expirationTimes,Z=h.pendingLanes&-62914561;0He)break;var Lt=nt.transferSize,zt=nt.initiatorType;Lt&&YB(zt)&&(nt=nt.responseEnd,Ne+=Lt*(nt"u"?null:document;function l8(h,y,S){var M=gb;if(M&&typeof y=="string"&&y){var $=En(y);$='link[rel="'+h+'"][href="'+$+'"]',typeof S=="string"&&($+='[crossorigin="'+S+'"]'),o8.has($)||(o8.add($),h={rel:h,crossOrigin:S,href:y},M.querySelector($)===null&&(y=M.createElement("link"),ss(y,"link",h),Ke(y),M.head.appendChild(y)))}}function pde(h){wu.D(h),l8("dns-prefetch",h,null)}function fde(h,y){wu.C(h,y),l8("preconnect",h,y)}function gde(h,y,S){wu.L(h,y,S);var M=gb;if(M&&h&&y){var $='link[rel="preload"][as="'+En(y)+'"]';y==="image"&&S&&S.imageSrcSet?($+='[imagesrcset="'+En(S.imageSrcSet)+'"]',typeof S.imageSizes=="string"&&($+='[imagesizes="'+En(S.imageSizes)+'"]')):$+='[href="'+En(h)+'"]';var Z=$;switch(y){case"style":Z=bb(h);break;case"script":Z=xb(h)}Rl.has(Z)||(h=m({rel:"preload",href:y==="image"&&S&&S.imageSrcSet?void 0:h,as:y},S),Rl.set(Z,h),M.querySelector($)!==null||y==="style"&&M.querySelector(xv(Z))||y==="script"&&M.querySelector(yv(Z))||(y=M.createElement("link"),ss(y,"link",h),Ke(y),M.head.appendChild(y)))}}function bde(h,y){wu.m(h,y);var S=gb;if(S&&h){var M=y&&typeof y.as=="string"?y.as:"script",$='link[rel="modulepreload"][as="'+En(M)+'"][href="'+En(h)+'"]',Z=$;switch(M){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":Z=xb(h)}if(!Rl.has(Z)&&(h=m({rel:"modulepreload",href:h},y),Rl.set(Z,h),S.querySelector($)===null)){switch(M){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(S.querySelector(yv(Z)))return}M=S.createElement("link"),ss(M,"link",h),Ke(M),S.head.appendChild(M)}}}function xde(h,y,S){wu.S(h,y,S);var M=gb;if(M&&h){var $=et(M).hoistableStyles,Z=bb(h);y=y||"default";var Ne=$.get(Z);if(!Ne){var He={loading:0,preload:null};if(Ne=M.querySelector(xv(Z)))He.loading=5;else{h=m({rel:"stylesheet",href:h,"data-precedence":y},S),(S=Rl.get(Z))&&rM(h,S);var nt=Ne=M.createElement("link");Ke(nt),ss(nt,"link",h),nt._p=new Promise(function(Nt,Lt){nt.onload=Nt,nt.onerror=Lt}),nt.addEventListener("load",function(){He.loading|=1}),nt.addEventListener("error",function(){He.loading|=2}),He.loading|=4,E_(Ne,y,M)}Ne={type:"stylesheet",instance:Ne,count:1,state:He},$.set(Z,Ne)}}}function yde(h,y){wu.X(h,y);var S=gb;if(S&&h){var M=et(S).hoistableScripts,$=xb(h),Z=M.get($);Z||(Z=S.querySelector(yv($)),Z||(h=m({src:h,async:!0},y),(y=Rl.get($))&&aM(h,y),Z=S.createElement("script"),Ke(Z),ss(Z,"link",h),S.head.appendChild(Z)),Z={type:"script",instance:Z,count:1,state:null},M.set($,Z))}}function vde(h,y){wu.M(h,y);var S=gb;if(S&&h){var M=et(S).hoistableScripts,$=xb(h),Z=M.get($);Z||(Z=S.querySelector(yv($)),Z||(h=m({src:h,async:!0,type:"module"},y),(y=Rl.get($))&&aM(h,y),Z=S.createElement("script"),Ke(Z),ss(Z,"link",h),S.head.appendChild(Z)),Z={type:"script",instance:Z,count:1,state:null},M.set($,Z))}}function c8(h,y,S,M){var $=($=q.current)?M_($):null;if(!$)throw Error(r(446));switch(h){case"meta":case"title":return null;case"style":return typeof S.precedence=="string"&&typeof S.href=="string"?(y=bb(S.href),S=et($).hoistableStyles,M=S.get(y),M||(M={type:"style",instance:null,count:0,state:null},S.set(y,M)),M):{type:"void",instance:null,count:0,state:null};case"link":if(S.rel==="stylesheet"&&typeof S.href=="string"&&typeof S.precedence=="string"){h=bb(S.href);var Z=et($).hoistableStyles,Ne=Z.get(h);if(Ne||($=$.ownerDocument||$,Ne={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},Z.set(h,Ne),(Z=$.querySelector(xv(h)))&&!Z._p&&(Ne.instance=Z,Ne.state.loading=5),Rl.has(h)||(S={rel:"preload",as:"style",href:S.href,crossOrigin:S.crossOrigin,integrity:S.integrity,media:S.media,hrefLang:S.hrefLang,referrerPolicy:S.referrerPolicy},Rl.set(h,S),Z||wde($,h,S,Ne.state))),y&&M===null)throw Error(r(528,""));return Ne}if(y&&M!==null)throw Error(r(529,""));return null;case"script":return y=S.async,S=S.src,typeof S=="string"&&y&&typeof y!="function"&&typeof y!="symbol"?(y=xb(S),S=et($).hoistableScripts,M=S.get(y),M||(M={type:"script",instance:null,count:0,state:null},S.set(y,M)),M):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,h))}}function bb(h){return'href="'+En(h)+'"'}function xv(h){return'link[rel="stylesheet"]['+h+"]"}function d8(h){return m({},h,{"data-precedence":h.precedence,precedence:null})}function wde(h,y,S,M){h.querySelector('link[rel="preload"][as="style"]['+y+"]")?M.loading=1:(y=h.createElement("link"),M.preload=y,y.addEventListener("load",function(){return M.loading|=1}),y.addEventListener("error",function(){return M.loading|=2}),ss(y,"link",S),Ke(y),h.head.appendChild(y))}function xb(h){return'[src="'+En(h)+'"]'}function yv(h){return"script[async]"+h}function u8(h,y,S){if(y.count++,y.instance===null)switch(y.type){case"style":var M=h.querySelector('style[data-href~="'+En(S.href)+'"]');if(M)return y.instance=M,Ke(M),M;var $=m({},S,{"data-href":S.href,"data-precedence":S.precedence,href:null,precedence:null});return M=(h.ownerDocument||h).createElement("style"),Ke(M),ss(M,"style",$),E_(M,S.precedence,h),y.instance=M;case"stylesheet":$=bb(S.href);var Z=h.querySelector(xv($));if(Z)return y.state.loading|=4,y.instance=Z,Ke(Z),Z;M=d8(S),($=Rl.get($))&&rM(M,$),Z=(h.ownerDocument||h).createElement("link"),Ke(Z);var Ne=Z;return Ne._p=new Promise(function(He,nt){Ne.onload=He,Ne.onerror=nt}),ss(Z,"link",M),y.state.loading|=4,E_(Z,S.precedence,h),y.instance=Z;case"script":return Z=xb(S.src),($=h.querySelector(yv(Z)))?(y.instance=$,Ke($),$):(M=S,($=Rl.get(Z))&&(M=m({},S),aM(M,$)),h=h.ownerDocument||h,$=h.createElement("script"),Ke($),ss($,"link",M),h.head.appendChild($),y.instance=$);case"void":return null;default:throw Error(r(443,y.type))}else y.type==="stylesheet"&&(y.state.loading&4)===0&&(M=y.instance,y.state.loading|=4,E_(M,S.precedence,h));return y.instance}function E_(h,y,S){for(var M=S.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),$=M.length?M[M.length-1]:null,Z=$,Ne=0;Ne title"):null)}function Sde(h,y,S){if(S===1||y.itemProp!=null)return!1;switch(h){case"meta":case"title":return!0;case"style":if(typeof y.precedence!="string"||typeof y.href!="string"||y.href==="")break;return!0;case"link":if(typeof y.rel!="string"||typeof y.href!="string"||y.href===""||y.onLoad||y.onError)break;return y.rel==="stylesheet"?(h=y.disabled,typeof y.precedence=="string"&&h==null):!0;case"script":if(y.async&&typeof y.async!="function"&&typeof y.async!="symbol"&&!y.onLoad&&!y.onError&&y.src&&typeof y.src=="string")return!0}return!1}function p8(h){return!(h.type==="stylesheet"&&(h.state.loading&3)===0)}function _de(h,y,S,M){if(S.type==="stylesheet"&&(typeof M.media!="string"||matchMedia(M.media).matches!==!1)&&(S.state.loading&4)===0){if(S.instance===null){var $=bb(M.href),Z=y.querySelector(xv($));if(Z){y=Z._p,y!==null&&typeof y=="object"&&typeof y.then=="function"&&(h.count++,h=F_.bind(h),y.then(h,h)),S.state.loading|=4,S.instance=Z,Ke(Z);return}Z=y.ownerDocument||y,M=d8(M),($=Rl.get($))&&rM(M,$),Z=Z.createElement("link"),Ke(Z);var Ne=Z;Ne._p=new Promise(function(He,nt){Ne.onload=He,Ne.onerror=nt}),ss(Z,"link",M),S.instance=Z}h.stylesheets===null&&(h.stylesheets=new Map),h.stylesheets.set(S,y),(y=S.state.preload)&&(S.state.loading&3)===0&&(h.count++,S=F_.bind(h),y.addEventListener("load",S),y.addEventListener("error",S))}}var iM=0;function kde(h,y){return h.stylesheets&&h.count===0&&L_(h,h.stylesheets),0iM?50:800)+y);return h.unsuspend=S,function(){h.unsuspend=null,clearTimeout(M),clearTimeout($)}}:null}function F_(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)L_(this,this.stylesheets);else if(this.unsuspend){var h=this.unsuspend;this.unsuspend=null,h()}}}var R_=null;function L_(h,y){h.stylesheets=null,h.unsuspend!==null&&(h.count++,R_=new Map,y.forEach(Nde,h),R_=null,F_.call(h))}function Nde(h,y){if(!(y.state.loading&4)){var S=R_.get(h);if(S)var M=S.get(null);else{S=new Map,R_.set(h,S);for(var $=h.querySelectorAll("link[data-precedence],style[data-precedence]"),Z=0;Z<$.length;Z++){var Ne=$[Z];(Ne.nodeName==="LINK"||Ne.getAttribute("media")!=="not all")&&(S.set(Ne.dataset.precedence,Ne),M=Ne)}M&&S.set(null,M)}$=y.instance,Ne=$.getAttribute("data-precedence"),Z=S.get(Ne)||M,Z===M&&S.set(null,$),S.set(Ne,$),this.count++,M=F_.bind(this),$.addEventListener("load",M),$.addEventListener("error",M),Z?Z.parentNode.insertBefore($,Z.nextSibling):(h=h.nodeType===9?h.head:h,h.insertBefore($,h.firstChild)),y.state.loading|=4}}var vv={$$typeof:C,Provider:null,Consumer:null,_currentValue:oe,_currentValue2:oe,_threadCount:0};function Cde(h,y,S,M,$,Z,Ne,He,nt){this.tag=1,this.containerInfo=h,this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.next=this.pendingContext=this.context=this.cancelPendingCommit=null,this.callbackPriority=0,this.expirationTimes=pt(-1),this.entangledLanes=this.shellSuspendCounter=this.errorRecoveryDisabledLanes=this.expiredLanes=this.warmLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=pt(0),this.hiddenUpdates=pt(null),this.identifierPrefix=M,this.onUncaughtError=$,this.onCaughtError=Z,this.onRecoverableError=Ne,this.pooledCache=null,this.pooledCacheLanes=0,this.formState=nt,this.incompleteTransitions=new Map}function f8(h,y,S,M,$,Z,Ne,He,nt,Nt,Lt,zt){return h=new Cde(h,y,S,Ne,nt,Nt,Lt,zt,He),y=1,Z===!0&&(y|=24),Z=Yo(3,null,null,y),h.current=Z,Z.stateNode=h,y=IA(),y.refCount++,h.pooledCache=y,y.refCount++,Z.memoizedState={element:M,isDehydrated:S,cache:y},HA(Z),h}function g8(h){return h?(h=Xg,h):Xg}function b8(h,y,S,M,$,Z){$=g8($),M.context===null?M.context=$:M.pendingContext=$,M=Gm(y),M.payload={element:S},Z=Z===void 0?null:Z,Z!==null&&(M.callback=Z),S=Wm(h,M,y),S!==null&&(Co(S,h,y),Zy(S,h,y))}function x8(h,y){if(h=h.memoizedState,h!==null&&h.dehydrated!==null){var S=h.retryLane;h.retryLane=S!==0&&S"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),pM.exports=Hde(),pM.exports}var $de=qde();const $n=t=>typeof t=="string",Cv=()=>{let t,e;const n=new Promise((r,i)=>{t=r,e=i});return n.resolve=t,n.reject=e,n},I8=t=>t==null?"":""+t,Vde=(t,e,n)=>{t.forEach(r=>{e[r]&&(n[r]=e[r])})},Gde=/###/g,z8=t=>t&&t.indexOf("###")>-1?t.replace(Gde,"."):t,U8=t=>!t||$n(t),_0=(t,e,n)=>{const r=$n(e)?e.split("."):e;let i=0;for(;i{const{obj:r,k:i}=_0(t,e,Object);if(r!==void 0||e.length===1){r[i]=n;return}let s=e[e.length-1],o=e.slice(0,e.length-1),l=_0(t,o,Object);for(;l.obj===void 0&&o.length;)s=`${o[o.length-1]}.${s}`,o=o.slice(0,o.length-1),l=_0(t,o,Object),l?.obj&&typeof l.obj[`${l.k}.${s}`]<"u"&&(l.obj=void 0);l.obj[`${l.k}.${s}`]=n},Wde=(t,e,n,r)=>{const{obj:i,k:s}=_0(t,e,Object);i[s]=i[s]||[],i[s].push(n)},dN=(t,e)=>{const{obj:n,k:r}=_0(t,e);if(n&&Object.prototype.hasOwnProperty.call(n,r))return n[r]},Kde=(t,e,n)=>{const r=dN(t,n);return r!==void 0?r:dN(e,n)},BY=(t,e,n)=>{for(const r in e)r!=="__proto__"&&r!=="constructor"&&(r in t?$n(t[r])||t[r]instanceof String||$n(e[r])||e[r]instanceof String?n&&(t[r]=e[r]):BY(t[r],e[r],n):t[r]=e[r]);return t},vb=t=>t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");var Xde={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};const Yde=t=>$n(t)?t.replace(/[&<>"'\/]/g,e=>Xde[e]):t;class Qde{constructor(e){this.capacity=e,this.regExpMap=new Map,this.regExpQueue=[]}getRegExp(e){const n=this.regExpMap.get(e);if(n!==void 0)return n;const r=new RegExp(e);return this.regExpQueue.length===this.capacity&&this.regExpMap.delete(this.regExpQueue.shift()),this.regExpMap.set(e,r),this.regExpQueue.push(e),r}}const Zde=[" ",",","?","!",";"],Jde=new Qde(20),eue=(t,e,n)=>{e=e||"",n=n||"";const r=Zde.filter(o=>e.indexOf(o)<0&&n.indexOf(o)<0);if(r.length===0)return!0;const i=Jde.getRegExp(`(${r.map(o=>o==="?"?"\\?":o).join("|")})`);let s=!i.test(t);if(!s){const o=t.indexOf(n);o>0&&!i.test(t.substring(0,o))&&(s=!0)}return s},I3=(t,e,n=".")=>{if(!t)return;if(t[e])return Object.prototype.hasOwnProperty.call(t,e)?t[e]:void 0;const r=e.split(n);let i=t;for(let s=0;s-1&&ct?.replace("_","-"),tue={type:"logger",log(t){this.output("log",t)},warn(t){this.output("warn",t)},error(t){this.output("error",t)},output(t,e){console?.[t]?.apply?.(console,e)}};class uN{constructor(e,n={}){this.init(e,n)}init(e,n={}){this.prefix=n.prefix||"i18next:",this.logger=e||tue,this.options=n,this.debug=n.debug}log(...e){return this.forward(e,"log","",!0)}warn(...e){return this.forward(e,"warn","",!0)}error(...e){return this.forward(e,"error","")}deprecate(...e){return this.forward(e,"warn","WARNING DEPRECATED: ",!0)}forward(e,n,r,i){return i&&!this.debug?null:($n(e[0])&&(e[0]=`${r}${this.prefix} ${e[0]}`),this.logger[n](e))}create(e){return new uN(this.logger,{prefix:`${this.prefix}:${e}:`,...this.options})}clone(e){return e=e||this.options,e.prefix=e.prefix||this.prefix,new uN(this.logger,e)}}var Ed=new uN;let LP=class{constructor(){this.observers={}}on(e,n){return e.split(" ").forEach(r=>{this.observers[r]||(this.observers[r]=new Map);const i=this.observers[r].get(n)||0;this.observers[r].set(n,i+1)}),this}off(e,n){if(this.observers[e]){if(!n){delete this.observers[e];return}this.observers[e].delete(n)}}emit(e,...n){this.observers[e]&&Array.from(this.observers[e].entries()).forEach(([i,s])=>{for(let o=0;o{for(let o=0;o-1&&this.options.ns.splice(n,1)}getResource(e,n,r,i={}){const s=i.keySeparator!==void 0?i.keySeparator:this.options.keySeparator,o=i.ignoreJSONStructure!==void 0?i.ignoreJSONStructure:this.options.ignoreJSONStructure;let l;e.indexOf(".")>-1?l=e.split("."):(l=[e,n],r&&(Array.isArray(r)?l.push(...r):$n(r)&&s?l.push(...r.split(s)):l.push(r)));const c=dN(this.data,l);return!c&&!n&&!r&&e.indexOf(".")>-1&&(e=l[0],n=l[1],r=l.slice(2).join(".")),c||!o||!$n(r)?c:I3(this.data?.[e]?.[n],r,s)}addResource(e,n,r,i,s={silent:!1}){const o=s.keySeparator!==void 0?s.keySeparator:this.options.keySeparator;let l=[e,n];r&&(l=l.concat(o?r.split(o):r)),e.indexOf(".")>-1&&(l=e.split("."),i=n,n=l[1]),this.addNamespaces(n),B8(this.data,l,i),s.silent||this.emit("added",e,n,r,i)}addResources(e,n,r,i={silent:!1}){for(const s in r)($n(r[s])||Array.isArray(r[s]))&&this.addResource(e,n,s,r[s],{silent:!0});i.silent||this.emit("added",e,n,r)}addResourceBundle(e,n,r,i,s,o={silent:!1,skipCopy:!1}){let l=[e,n];e.indexOf(".")>-1&&(l=e.split("."),i=r,r=n,n=l[1]),this.addNamespaces(n);let c=dN(this.data,l)||{};o.skipCopy||(r=JSON.parse(JSON.stringify(r))),i?BY(c,r,s):c={...c,...r},B8(this.data,l,c),o.silent||this.emit("added",e,n,r)}removeResourceBundle(e,n){this.hasResourceBundle(e,n)&&delete this.data[e][n],this.removeNamespaces(n),this.emit("removed",e,n)}hasResourceBundle(e,n){return this.getResource(e,n)!==void 0}getResourceBundle(e,n){return n||(n=this.options.defaultNS),this.getResource(e,n)}getDataByLanguage(e){return this.data[e]}hasLanguageSomeTranslations(e){const n=this.getDataByLanguage(e);return!!(n&&Object.keys(n)||[]).find(i=>n[i]&&Object.keys(n[i]).length>0)}toJSON(){return this.data}}var HY={processors:{},addPostProcessor(t){this.processors[t.name]=t},handle(t,e,n,r,i){return t.forEach(s=>{e=this.processors[s]?.process(e,n,r,i)??e}),e}};const qY=Symbol("i18next/PATH_KEY");function nue(){const t=[],e=Object.create(null);let n;return e.get=(r,i)=>(n?.revoke?.(),i===qY?t:(t.push(i),n=Proxy.revocable(r,e),n.proxy)),Proxy.revocable(Object.create(null),e).proxy}function z3(t,e){const{[qY]:n}=t(nue());return n.join(e?.keySeparator??".")}const q8={},xM=t=>!$n(t)&&typeof t!="boolean"&&typeof t!="number";class mN extends LP{constructor(e,n={}){super(),Vde(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector","i18nFormat","utils"],e,this),this.options=n,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.logger=Ed.create("translator")}changeLanguage(e){e&&(this.language=e)}exists(e,n={interpolation:{}}){const r={...n};if(e==null)return!1;const i=this.resolve(e,r);if(i?.res===void 0)return!1;const s=xM(i.res);return!(r.returnObjects===!1&&s)}extractFromKey(e,n){let r=n.nsSeparator!==void 0?n.nsSeparator:this.options.nsSeparator;r===void 0&&(r=":");const i=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator;let s=n.ns||this.options.defaultNS||[];const o=r&&e.indexOf(r)>-1,l=!this.options.userDefinedKeySeparator&&!n.keySeparator&&!this.options.userDefinedNsSeparator&&!n.nsSeparator&&!eue(e,r,i);if(o&&!l){const c=e.match(this.interpolator.nestingRegexp);if(c&&c.length>0)return{key:e,namespaces:$n(s)?[s]:s};const d=e.split(r);(r!==i||r===i&&this.options.ns.indexOf(d[0])>-1)&&(s=d.shift()),e=d.join(i)}return{key:e,namespaces:$n(s)?[s]:s}}translate(e,n,r){let i=typeof n=="object"?{...n}:n;if(typeof i!="object"&&this.options.overloadTranslationOptionHandler&&(i=this.options.overloadTranslationOptionHandler(arguments)),typeof i=="object"&&(i={...i}),i||(i={}),e==null)return"";typeof e=="function"&&(e=z3(e,{...this.options,...i})),Array.isArray(e)||(e=[String(e)]);const s=i.returnDetails!==void 0?i.returnDetails:this.options.returnDetails,o=i.keySeparator!==void 0?i.keySeparator:this.options.keySeparator,{key:l,namespaces:c}=this.extractFromKey(e[e.length-1],i),d=c[c.length-1];let u=i.nsSeparator!==void 0?i.nsSeparator:this.options.nsSeparator;u===void 0&&(u=":");const m=i.lng||this.language,p=i.appendNamespaceToCIMode||this.options.appendNamespaceToCIMode;if(m?.toLowerCase()==="cimode")return p?s?{res:`${d}${u}${l}`,usedKey:l,exactUsedKey:l,usedLng:m,usedNS:d,usedParams:this.getUsedParamsDetails(i)}:`${d}${u}${l}`:s?{res:l,usedKey:l,exactUsedKey:l,usedLng:m,usedNS:d,usedParams:this.getUsedParamsDetails(i)}:l;const f=this.resolve(e,i);let x=f?.res;const v=f?.usedKey||l,b=f?.exactUsedKey||l,g=["[object Number]","[object Function]","[object RegExp]"],_=i.joinArrays!==void 0?i.joinArrays:this.options.joinArrays,C=!this.i18nFormat||this.i18nFormat.handleAsObject,P=i.count!==void 0&&!$n(i.count),N=mN.hasDefaultValue(i),A=P?this.pluralResolver.getSuffix(m,i.count,i):"",T=i.ordinal&&P?this.pluralResolver.getSuffix(m,i.count,{ordinal:!1}):"",F=P&&!i.ordinal&&i.count===0,k=F&&i[`defaultValue${this.options.pluralSeparator}zero`]||i[`defaultValue${A}`]||i[`defaultValue${T}`]||i.defaultValue;let D=x;C&&!x&&N&&(D=k);const H=xM(D),z=Object.prototype.toString.apply(D);if(C&&D&&H&&g.indexOf(z)<0&&!($n(_)&&Array.isArray(D))){if(!i.returnObjects&&!this.options.returnObjects){this.options.returnedObjectHandler||this.logger.warn("accessing an object - but returnObjects options is not enabled!");const Y=this.options.returnedObjectHandler?this.options.returnedObjectHandler(v,D,{...i,ns:c}):`key '${l} (${this.language})' returned an object instead of string.`;return s?(f.res=Y,f.usedParams=this.getUsedParamsDetails(i),f):Y}if(o){const Y=Array.isArray(D),L=Y?[]:{},te=Y?b:v;for(const ie in D)if(Object.prototype.hasOwnProperty.call(D,ie)){const J=`${te}${o}${ie}`;N&&!x?L[ie]=this.translate(J,{...i,defaultValue:xM(k)?k[ie]:void 0,joinArrays:!1,ns:c}):L[ie]=this.translate(J,{...i,joinArrays:!1,ns:c}),L[ie]===J&&(L[ie]=D[ie])}x=L}}else if(C&&$n(_)&&Array.isArray(x))x=x.join(_),x&&(x=this.extendTranslation(x,e,i,r));else{let Y=!1,L=!1;!this.isValidLookup(x)&&N&&(Y=!0,x=k),this.isValidLookup(x)||(L=!0,x=l);const ie=(i.missingKeyNoValueFallbackToKey||this.options.missingKeyNoValueFallbackToKey)&&L?void 0:x,J=N&&k!==x&&this.options.updateMissing;if(L||Y||J){if(this.logger.log(J?"updateKey":"missingKey",m,d,l,J?k:x),o){const W=this.resolve(l,{...i,keySeparator:!1});W&&W.res&&this.logger.warn("Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.")}let oe=[];const fe=this.languageUtils.getFallbackCodes(this.options.fallbackLng,i.lng||this.language);if(this.options.saveMissingTo==="fallback"&&fe&&fe[0])for(let W=0;W{const be=N&&me!==x?me:ie;this.options.missingKeyHandler?this.options.missingKeyHandler(W,d,ne,be,J,i):this.backendConnector?.saveMissing&&this.backendConnector.saveMissing(W,d,ne,be,J,i),this.emit("missingKey",W,d,ne,x)};this.options.saveMissing&&(this.options.saveMissingPlurals&&P?oe.forEach(W=>{const ne=this.pluralResolver.getSuffixes(W,i);F&&i[`defaultValue${this.options.pluralSeparator}zero`]&&ne.indexOf(`${this.options.pluralSeparator}zero`)<0&&ne.push(`${this.options.pluralSeparator}zero`),ne.forEach(me=>{re([W],l+me,i[`defaultValue${me}`]||k)})}):re(oe,l,k))}x=this.extendTranslation(x,e,i,f,r),L&&x===l&&this.options.appendNamespaceToMissingKey&&(x=`${d}${u}${l}`),(L||Y)&&this.options.parseMissingKeyHandler&&(x=this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey?`${d}${u}${l}`:l,Y?x:void 0,i))}return s?(f.res=x,f.usedParams=this.getUsedParamsDetails(i),f):x}extendTranslation(e,n,r,i,s){if(this.i18nFormat?.parse)e=this.i18nFormat.parse(e,{...this.options.interpolation.defaultVariables,...r},r.lng||this.language||i.usedLng,i.usedNS,i.usedKey,{resolved:i});else if(!r.skipInterpolation){r.interpolation&&this.interpolator.init({...r,interpolation:{...this.options.interpolation,...r.interpolation}});const c=$n(e)&&(r?.interpolation?.skipOnVariables!==void 0?r.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables);let d;if(c){const m=e.match(this.interpolator.nestingRegexp);d=m&&m.length}let u=r.replace&&!$n(r.replace)?r.replace:r;if(this.options.interpolation.defaultVariables&&(u={...this.options.interpolation.defaultVariables,...u}),e=this.interpolator.interpolate(e,u,r.lng||this.language||i.usedLng,r),c){const m=e.match(this.interpolator.nestingRegexp),p=m&&m.length;ds?.[0]===m[0]&&!r.context?(this.logger.warn(`It seems you are nesting recursively key: ${m[0]} in key: ${n[0]}`),null):this.translate(...m,n),r)),r.interpolation&&this.interpolator.reset()}const o=r.postProcess||this.options.postProcess,l=$n(o)?[o]:o;return e!=null&&l?.length&&r.applyPostProcessor!==!1&&(e=HY.handle(l,e,n,this.options&&this.options.postProcessPassResolved?{i18nResolved:{...i,usedParams:this.getUsedParamsDetails(r)},...r}:r,this)),e}resolve(e,n={}){let r,i,s,o,l;return $n(e)&&(e=[e]),e.forEach(c=>{if(this.isValidLookup(r))return;const d=this.extractFromKey(c,n),u=d.key;i=u;let m=d.namespaces;this.options.fallbackNS&&(m=m.concat(this.options.fallbackNS));const p=n.count!==void 0&&!$n(n.count),f=p&&!n.ordinal&&n.count===0,x=n.context!==void 0&&($n(n.context)||typeof n.context=="number")&&n.context!=="",v=n.lngs?n.lngs:this.languageUtils.toResolveHierarchy(n.lng||this.language,n.fallbackLng);m.forEach(b=>{this.isValidLookup(r)||(l=b,!q8[`${v[0]}-${b}`]&&this.utils?.hasLoadedNamespace&&!this.utils?.hasLoadedNamespace(l)&&(q8[`${v[0]}-${b}`]=!0,this.logger.warn(`key "${i}" for languages "${v.join(", ")}" won't get resolved as namespace "${l}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!")),v.forEach(g=>{if(this.isValidLookup(r))return;o=g;const _=[u];if(this.i18nFormat?.addLookupKeys)this.i18nFormat.addLookupKeys(_,u,g,b,n);else{let P;p&&(P=this.pluralResolver.getSuffix(g,n.count,n));const N=`${this.options.pluralSeparator}zero`,A=`${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;if(p&&(n.ordinal&&P.indexOf(A)===0&&_.push(u+P.replace(A,this.options.pluralSeparator)),_.push(u+P),f&&_.push(u+N)),x){const T=`${u}${this.options.contextSeparator||"_"}${n.context}`;_.push(T),p&&(n.ordinal&&P.indexOf(A)===0&&_.push(T+P.replace(A,this.options.pluralSeparator)),_.push(T+P),f&&_.push(T+N))}}let C;for(;C=_.pop();)this.isValidLookup(r)||(s=C,r=this.getResource(g,b,C,n))}))})}),{res:r,usedKey:i,exactUsedKey:s,usedLng:o,usedNS:l}}isValidLookup(e){return e!==void 0&&!(!this.options.returnNull&&e===null)&&!(!this.options.returnEmptyString&&e==="")}getResource(e,n,r,i={}){return this.i18nFormat?.getResource?this.i18nFormat.getResource(e,n,r,i):this.resourceStore.getResource(e,n,r,i)}getUsedParamsDetails(e={}){const n=["defaultValue","ordinal","context","replace","lng","lngs","fallbackLng","ns","keySeparator","nsSeparator","returnObjects","returnDetails","joinArrays","postProcess","interpolation"],r=e.replace&&!$n(e.replace);let i=r?e.replace:e;if(r&&typeof e.count<"u"&&(i.count=e.count),this.options.interpolation.defaultVariables&&(i={...this.options.interpolation.defaultVariables,...i}),!r){i={...i};for(const s of n)delete i[s]}return i}static hasDefaultValue(e){const n="defaultValue";for(const r in e)if(Object.prototype.hasOwnProperty.call(e,r)&&n===r.substring(0,n.length)&&e[r]!==void 0)return!0;return!1}}class $8{constructor(e){this.options=e,this.supportedLngs=this.options.supportedLngs||!1,this.logger=Ed.create("languageUtils")}getScriptPartFromCode(e){if(e=Y0(e),!e||e.indexOf("-")<0)return null;const n=e.split("-");return n.length===2||(n.pop(),n[n.length-1].toLowerCase()==="x")?null:this.formatLanguageCode(n.join("-"))}getLanguagePartFromCode(e){if(e=Y0(e),!e||e.indexOf("-")<0)return e;const n=e.split("-");return this.formatLanguageCode(n[0])}formatLanguageCode(e){if($n(e)&&e.indexOf("-")>-1){let n;try{n=Intl.getCanonicalLocales(e)[0]}catch{}return n&&this.options.lowerCaseLng&&(n=n.toLowerCase()),n||(this.options.lowerCaseLng?e.toLowerCase():e)}return this.options.cleanCode||this.options.lowerCaseLng?e.toLowerCase():e}isSupportedCode(e){return(this.options.load==="languageOnly"||this.options.nonExplicitSupportedLngs)&&(e=this.getLanguagePartFromCode(e)),!this.supportedLngs||!this.supportedLngs.length||this.supportedLngs.indexOf(e)>-1}getBestMatchFromCodes(e){if(!e)return null;let n;return e.forEach(r=>{if(n)return;const i=this.formatLanguageCode(r);(!this.options.supportedLngs||this.isSupportedCode(i))&&(n=i)}),!n&&this.options.supportedLngs&&e.forEach(r=>{if(n)return;const i=this.getScriptPartFromCode(r);if(this.isSupportedCode(i))return n=i;const s=this.getLanguagePartFromCode(r);if(this.isSupportedCode(s))return n=s;n=this.options.supportedLngs.find(o=>{if(o===s)return o;if(!(o.indexOf("-")<0&&s.indexOf("-")<0)&&(o.indexOf("-")>0&&s.indexOf("-")<0&&o.substring(0,o.indexOf("-"))===s||o.indexOf(s)===0&&s.length>1))return o})}),n||(n=this.getFallbackCodes(this.options.fallbackLng)[0]),n}getFallbackCodes(e,n){if(!e)return[];if(typeof e=="function"&&(e=e(n)),$n(e)&&(e=[e]),Array.isArray(e))return e;if(!n)return e.default||[];let r=e[n];return r||(r=e[this.getScriptPartFromCode(n)]),r||(r=e[this.formatLanguageCode(n)]),r||(r=e[this.getLanguagePartFromCode(n)]),r||(r=e.default),r||[]}toResolveHierarchy(e,n){const r=this.getFallbackCodes((n===!1?[]:n)||this.options.fallbackLng||[],e),i=[],s=o=>{o&&(this.isSupportedCode(o)?i.push(o):this.logger.warn(`rejecting language code not found in supportedLngs: ${o}`))};return $n(e)&&(e.indexOf("-")>-1||e.indexOf("_")>-1)?(this.options.load!=="languageOnly"&&s(this.formatLanguageCode(e)),this.options.load!=="languageOnly"&&this.options.load!=="currentOnly"&&s(this.getScriptPartFromCode(e)),this.options.load!=="currentOnly"&&s(this.getLanguagePartFromCode(e))):$n(e)&&s(this.formatLanguageCode(e)),r.forEach(o=>{i.indexOf(o)<0&&s(this.formatLanguageCode(o))}),i}}const V8={zero:0,one:1,two:2,few:3,many:4,other:5},G8={select:t=>t===1?"one":"other",resolvedOptions:()=>({pluralCategories:["one","other"]})};class rue{constructor(e,n={}){this.languageUtils=e,this.options=n,this.logger=Ed.create("pluralResolver"),this.pluralRulesCache={}}addRule(e,n){this.rules[e]=n}clearCache(){this.pluralRulesCache={}}getRule(e,n={}){const r=Y0(e==="dev"?"en":e),i=n.ordinal?"ordinal":"cardinal",s=JSON.stringify({cleanedCode:r,type:i});if(s in this.pluralRulesCache)return this.pluralRulesCache[s];let o;try{o=new Intl.PluralRules(r,{type:i})}catch{if(!Intl)return this.logger.error("No Intl support, please use an Intl polyfill!"),G8;if(!e.match(/-|_/))return G8;const c=this.languageUtils.getLanguagePartFromCode(e);o=this.getRule(c,n)}return this.pluralRulesCache[s]=o,o}needsPlural(e,n={}){let r=this.getRule(e,n);return r||(r=this.getRule("dev",n)),r?.resolvedOptions().pluralCategories.length>1}getPluralFormsOfKey(e,n,r={}){return this.getSuffixes(e,r).map(i=>`${n}${i}`)}getSuffixes(e,n={}){let r=this.getRule(e,n);return r||(r=this.getRule("dev",n)),r?r.resolvedOptions().pluralCategories.sort((i,s)=>V8[i]-V8[s]).map(i=>`${this.options.prepend}${n.ordinal?`ordinal${this.options.prepend}`:""}${i}`):[]}getSuffix(e,n,r={}){const i=this.getRule(e,r);return i?`${this.options.prepend}${r.ordinal?`ordinal${this.options.prepend}`:""}${i.select(n)}`:(this.logger.warn(`no plural rule found for: ${e}`),this.getSuffix("dev",n,r))}}const W8=(t,e,n,r=".",i=!0)=>{let s=Kde(t,e,n);return!s&&i&&$n(n)&&(s=I3(t,n,r),s===void 0&&(s=I3(e,n,r))),s},yM=t=>t.replace(/\$/g,"$$$$");class aue{constructor(e={}){this.logger=Ed.create("interpolator"),this.options=e,this.format=e?.interpolation?.format||(n=>n),this.init(e)}init(e={}){e.interpolation||(e.interpolation={escapeValue:!0});const{escape:n,escapeValue:r,useRawValueToEscape:i,prefix:s,prefixEscaped:o,suffix:l,suffixEscaped:c,formatSeparator:d,unescapeSuffix:u,unescapePrefix:m,nestingPrefix:p,nestingPrefixEscaped:f,nestingSuffix:x,nestingSuffixEscaped:v,nestingOptionsSeparator:b,maxReplaces:g,alwaysFormat:_}=e.interpolation;this.escape=n!==void 0?n:Yde,this.escapeValue=r!==void 0?r:!0,this.useRawValueToEscape=i!==void 0?i:!1,this.prefix=s?vb(s):o||"{{",this.suffix=l?vb(l):c||"}}",this.formatSeparator=d||",",this.unescapePrefix=u?"":m||"-",this.unescapeSuffix=this.unescapePrefix?"":u||"",this.nestingPrefix=p?vb(p):f||vb("$t("),this.nestingSuffix=x?vb(x):v||vb(")"),this.nestingOptionsSeparator=b||",",this.maxReplaces=g||1e3,this.alwaysFormat=_!==void 0?_:!1,this.resetRegExp()}reset(){this.options&&this.init(this.options)}resetRegExp(){const e=(n,r)=>n?.source===r?(n.lastIndex=0,n):new RegExp(r,"g");this.regexp=e(this.regexp,`${this.prefix}(.+?)${this.suffix}`),this.regexpUnescape=e(this.regexpUnescape,`${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`),this.nestingRegexp=e(this.nestingRegexp,`${this.nestingPrefix}((?:[^()"']+|"[^"]*"|'[^']*'|\\((?:[^()]|"[^"]*"|'[^']*')*\\))*?)${this.nestingSuffix}`)}interpolate(e,n,r,i){let s,o,l;const c=this.options&&this.options.interpolation&&this.options.interpolation.defaultVariables||{},d=f=>{if(f.indexOf(this.formatSeparator)<0){const g=W8(n,c,f,this.options.keySeparator,this.options.ignoreJSONStructure);return this.alwaysFormat?this.format(g,void 0,r,{...i,...n,interpolationkey:f}):g}const x=f.split(this.formatSeparator),v=x.shift().trim(),b=x.join(this.formatSeparator).trim();return this.format(W8(n,c,v,this.options.keySeparator,this.options.ignoreJSONStructure),b,r,{...i,...n,interpolationkey:v})};this.resetRegExp();const u=i?.missingInterpolationHandler||this.options.missingInterpolationHandler,m=i?.interpolation?.skipOnVariables!==void 0?i.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables;return[{regex:this.regexpUnescape,safeValue:f=>yM(f)},{regex:this.regexp,safeValue:f=>this.escapeValue?yM(this.escape(f)):yM(f)}].forEach(f=>{for(l=0;s=f.regex.exec(e);){const x=s[1].trim();if(o=d(x),o===void 0)if(typeof u=="function"){const b=u(e,s,i);o=$n(b)?b:""}else if(i&&Object.prototype.hasOwnProperty.call(i,x))o="";else if(m){o=s[0];continue}else this.logger.warn(`missed to pass in variable ${x} for interpolating ${e}`),o="";else!$n(o)&&!this.useRawValueToEscape&&(o=I8(o));const v=f.safeValue(o);if(e=e.replace(s[0],v),m?(f.regex.lastIndex+=o.length,f.regex.lastIndex-=s[0].length):f.regex.lastIndex=0,l++,l>=this.maxReplaces)break}}),e}nest(e,n,r={}){let i,s,o;const l=(c,d)=>{const u=this.nestingOptionsSeparator;if(c.indexOf(u)<0)return c;const m=c.split(new RegExp(`${u}[ ]*{`));let p=`{${m[1]}`;c=m[0],p=this.interpolate(p,o);const f=p.match(/'/g),x=p.match(/"/g);((f?.length??0)%2===0&&!x||x.length%2!==0)&&(p=p.replace(/'/g,'"'));try{o=JSON.parse(p),d&&(o={...d,...o})}catch(v){return this.logger.warn(`failed parsing options string in nesting for key ${c}`,v),`${c}${u}${p}`}return o.defaultValue&&o.defaultValue.indexOf(this.prefix)>-1&&delete o.defaultValue,c};for(;i=this.nestingRegexp.exec(e);){let c=[];o={...r},o=o.replace&&!$n(o.replace)?o.replace:o,o.applyPostProcessor=!1,delete o.defaultValue;const d=/{.*}/.test(i[1])?i[1].lastIndexOf("}")+1:i[1].indexOf(this.formatSeparator);if(d!==-1&&(c=i[1].slice(d).split(this.formatSeparator).map(u=>u.trim()).filter(Boolean),i[1]=i[1].slice(0,d)),s=n(l.call(this,i[1].trim(),o),o),s&&i[0]===e&&!$n(s))return s;$n(s)||(s=I8(s)),s||(this.logger.warn(`missed to resolve ${i[1]} for nesting ${e}`),s=""),c.length&&(s=c.reduce((u,m)=>this.format(u,m,r.lng,{...r,interpolationkey:i[1].trim()}),s.trim())),e=e.replace(i[0],s),this.regexp.lastIndex=0}return e}}const iue=t=>{let e=t.toLowerCase().trim();const n={};if(t.indexOf("(")>-1){const r=t.split("(");e=r[0].toLowerCase().trim();const i=r[1].substring(0,r[1].length-1);e==="currency"&&i.indexOf(":")<0?n.currency||(n.currency=i.trim()):e==="relativetime"&&i.indexOf(":")<0?n.range||(n.range=i.trim()):i.split(";").forEach(o=>{if(o){const[l,...c]=o.split(":"),d=c.join(":").trim().replace(/^'+|'+$/g,""),u=l.trim();n[u]||(n[u]=d),d==="false"&&(n[u]=!1),d==="true"&&(n[u]=!0),isNaN(d)||(n[u]=parseInt(d,10))}})}return{formatName:e,formatOptions:n}},K8=t=>{const e={};return(n,r,i)=>{let s=i;i&&i.interpolationkey&&i.formatParams&&i.formatParams[i.interpolationkey]&&i[i.interpolationkey]&&(s={...s,[i.interpolationkey]:void 0});const o=r+JSON.stringify(s);let l=e[o];return l||(l=t(Y0(r),i),e[o]=l),l(n)}},sue=t=>(e,n,r)=>t(Y0(n),r)(e);class oue{constructor(e={}){this.logger=Ed.create("formatter"),this.options=e,this.init(e)}init(e,n={interpolation:{}}){this.formatSeparator=n.interpolation.formatSeparator||",";const r=n.cacheInBuiltFormats?K8:sue;this.formats={number:r((i,s)=>{const o=new Intl.NumberFormat(i,{...s});return l=>o.format(l)}),currency:r((i,s)=>{const o=new Intl.NumberFormat(i,{...s,style:"currency"});return l=>o.format(l)}),datetime:r((i,s)=>{const o=new Intl.DateTimeFormat(i,{...s});return l=>o.format(l)}),relativetime:r((i,s)=>{const o=new Intl.RelativeTimeFormat(i,{...s});return l=>o.format(l,s.range||"day")}),list:r((i,s)=>{const o=new Intl.ListFormat(i,{...s});return l=>o.format(l)})}}add(e,n){this.formats[e.toLowerCase().trim()]=n}addCached(e,n){this.formats[e.toLowerCase().trim()]=K8(n)}format(e,n,r,i={}){const s=n.split(this.formatSeparator);if(s.length>1&&s[0].indexOf("(")>1&&s[0].indexOf(")")<0&&s.find(l=>l.indexOf(")")>-1)){const l=s.findIndex(c=>c.indexOf(")")>-1);s[0]=[s[0],...s.splice(1,l)].join(this.formatSeparator)}return s.reduce((l,c)=>{const{formatName:d,formatOptions:u}=iue(c);if(this.formats[d]){let m=l;try{const p=i?.formatParams?.[i.interpolationkey]||{},f=p.locale||p.lng||i.locale||i.lng||r;m=this.formats[d](l,f,{...u,...i,...p})}catch(p){this.logger.warn(p)}return m}else this.logger.warn(`there was no format function for ${d}`);return l},e)}}const lue=(t,e)=>{t.pending[e]!==void 0&&(delete t.pending[e],t.pendingCount--)};class cue extends LP{constructor(e,n,r,i={}){super(),this.backend=e,this.store=n,this.services=r,this.languageUtils=r.languageUtils,this.options=i,this.logger=Ed.create("backendConnector"),this.waitingReads=[],this.maxParallelReads=i.maxParallelReads||10,this.readingCalls=0,this.maxRetries=i.maxRetries>=0?i.maxRetries:5,this.retryTimeout=i.retryTimeout>=1?i.retryTimeout:350,this.state={},this.queue=[],this.backend?.init?.(r,i.backend,i)}queueLoad(e,n,r,i){const s={},o={},l={},c={};return e.forEach(d=>{let u=!0;n.forEach(m=>{const p=`${d}|${m}`;!r.reload&&this.store.hasResourceBundle(d,m)?this.state[p]=2:this.state[p]<0||(this.state[p]===1?o[p]===void 0&&(o[p]=!0):(this.state[p]=1,u=!1,o[p]===void 0&&(o[p]=!0),s[p]===void 0&&(s[p]=!0),c[m]===void 0&&(c[m]=!0)))}),u||(l[d]=!0)}),(Object.keys(s).length||Object.keys(o).length)&&this.queue.push({pending:o,pendingCount:Object.keys(o).length,loaded:{},errors:[],callback:i}),{toLoad:Object.keys(s),pending:Object.keys(o),toLoadLanguages:Object.keys(l),toLoadNamespaces:Object.keys(c)}}loaded(e,n,r){const i=e.split("|"),s=i[0],o=i[1];n&&this.emit("failedLoading",s,o,n),!n&&r&&this.store.addResourceBundle(s,o,r,void 0,void 0,{skipCopy:!0}),this.state[e]=n?-1:2,n&&r&&(this.state[e]=0);const l={};this.queue.forEach(c=>{Wde(c.loaded,[s],o),lue(c,e),n&&c.errors.push(n),c.pendingCount===0&&!c.done&&(Object.keys(c.loaded).forEach(d=>{l[d]||(l[d]={});const u=c.loaded[d];u.length&&u.forEach(m=>{l[d][m]===void 0&&(l[d][m]=!0)})}),c.done=!0,c.errors.length?c.callback(c.errors):c.callback())}),this.emit("loaded",l),this.queue=this.queue.filter(c=>!c.done)}read(e,n,r,i=0,s=this.retryTimeout,o){if(!e.length)return o(null,{});if(this.readingCalls>=this.maxParallelReads){this.waitingReads.push({lng:e,ns:n,fcName:r,tried:i,wait:s,callback:o});return}this.readingCalls++;const l=(d,u)=>{if(this.readingCalls--,this.waitingReads.length>0){const m=this.waitingReads.shift();this.read(m.lng,m.ns,m.fcName,m.tried,m.wait,m.callback)}if(d&&u&&i{this.read.call(this,e,n,r,i+1,s*2,o)},s);return}o(d,u)},c=this.backend[r].bind(this.backend);if(c.length===2){try{const d=c(e,n);d&&typeof d.then=="function"?d.then(u=>l(null,u)).catch(l):l(null,d)}catch(d){l(d)}return}return c(e,n,l)}prepareLoading(e,n,r={},i){if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),i&&i();$n(e)&&(e=this.languageUtils.toResolveHierarchy(e)),$n(n)&&(n=[n]);const s=this.queueLoad(e,n,r,i);if(!s.toLoad.length)return s.pending.length||i(),null;s.toLoad.forEach(o=>{this.loadOne(o)})}load(e,n,r){this.prepareLoading(e,n,{},r)}reload(e,n,r){this.prepareLoading(e,n,{reload:!0},r)}loadOne(e,n=""){const r=e.split("|"),i=r[0],s=r[1];this.read(i,s,"read",void 0,void 0,(o,l)=>{o&&this.logger.warn(`${n}loading namespace ${s} for language ${i} failed`,o),!o&&l&&this.logger.log(`${n}loaded namespace ${s} for language ${i}`,l),this.loaded(e,o,l)})}saveMissing(e,n,r,i,s,o={},l=()=>{}){if(this.services?.utils?.hasLoadedNamespace&&!this.services?.utils?.hasLoadedNamespace(n)){this.logger.warn(`did not save key "${r}" as the namespace "${n}" was not yet loaded`,"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!");return}if(!(r==null||r==="")){if(this.backend?.create){const c={...o,isUpdate:s},d=this.backend.create.bind(this.backend);if(d.length<6)try{let u;d.length===5?u=d(e,n,r,i,c):u=d(e,n,r,i),u&&typeof u.then=="function"?u.then(m=>l(null,m)).catch(l):l(null,u)}catch(u){l(u)}else d(e,n,r,i,l,c)}!e||!e[0]||this.store.addResource(e[0],n,r,i)}}}const X8=()=>({debug:!1,initAsync:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,supportedLngs:!1,nonExplicitSupportedLngs:!1,load:"all",preload:!1,simplifyPluralSuffix:!0,keySeparator:".",nsSeparator:":",pluralSeparator:"_",contextSeparator:"_",partialBundledLanguages:!1,saveMissing:!1,updateMissing:!1,saveMissingTo:"fallback",saveMissingPlurals:!0,missingKeyHandler:!1,missingInterpolationHandler:!1,postProcess:!1,postProcessPassResolved:!1,returnNull:!1,returnEmptyString:!0,returnObjects:!1,joinArrays:!1,returnedObjectHandler:!1,parseMissingKeyHandler:!1,appendNamespaceToMissingKey:!1,appendNamespaceToCIMode:!1,overloadTranslationOptionHandler:t=>{let e={};if(typeof t[1]=="object"&&(e=t[1]),$n(t[1])&&(e.defaultValue=t[1]),$n(t[2])&&(e.tDescription=t[2]),typeof t[2]=="object"||typeof t[3]=="object"){const n=t[3]||t[2];Object.keys(n).forEach(r=>{e[r]=n[r]})}return e},interpolation:{escapeValue:!0,format:t=>t,prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",nestingOptionsSeparator:",",maxReplaces:1e3,skipOnVariables:!0},cacheInBuiltFormats:!0}),Y8=t=>($n(t.ns)&&(t.ns=[t.ns]),$n(t.fallbackLng)&&(t.fallbackLng=[t.fallbackLng]),$n(t.fallbackNS)&&(t.fallbackNS=[t.fallbackNS]),t.supportedLngs?.indexOf?.("cimode")<0&&(t.supportedLngs=t.supportedLngs.concat(["cimode"])),typeof t.initImmediate=="boolean"&&(t.initAsync=t.initImmediate),t),V_=()=>{},due=t=>{Object.getOwnPropertyNames(Object.getPrototypeOf(t)).forEach(n=>{typeof t[n]=="function"&&(t[n]=t[n].bind(t))})};class k0 extends LP{constructor(e={},n){if(super(),this.options=Y8(e),this.services={},this.logger=Ed,this.modules={external:[]},due(this),n&&!this.isInitialized&&!e.isClone){if(!this.options.initAsync)return this.init(e,n),this;setTimeout(()=>{this.init(e,n)},0)}}init(e={},n){this.isInitializing=!0,typeof e=="function"&&(n=e,e={}),e.defaultNS==null&&e.ns&&($n(e.ns)?e.defaultNS=e.ns:e.ns.indexOf("translation")<0&&(e.defaultNS=e.ns[0]));const r=X8();this.options={...r,...this.options,...Y8(e)},this.options.interpolation={...r.interpolation,...this.options.interpolation},e.keySeparator!==void 0&&(this.options.userDefinedKeySeparator=e.keySeparator),e.nsSeparator!==void 0&&(this.options.userDefinedNsSeparator=e.nsSeparator);const i=d=>d?typeof d=="function"?new d:d:null;if(!this.options.isClone){this.modules.logger?Ed.init(i(this.modules.logger),this.options):Ed.init(null,this.options);let d;this.modules.formatter?d=this.modules.formatter:d=oue;const u=new $8(this.options);this.store=new H8(this.options.resources,this.options);const m=this.services;m.logger=Ed,m.resourceStore=this.store,m.languageUtils=u,m.pluralResolver=new rue(u,{prepend:this.options.pluralSeparator,simplifyPluralSuffix:this.options.simplifyPluralSuffix}),this.options.interpolation.format&&this.options.interpolation.format!==r.interpolation.format&&this.logger.deprecate("init: you are still using the legacy format function, please use the new approach: https://www.i18next.com/translation-function/formatting"),d&&(!this.options.interpolation.format||this.options.interpolation.format===r.interpolation.format)&&(m.formatter=i(d),m.formatter.init&&m.formatter.init(m,this.options),this.options.interpolation.format=m.formatter.format.bind(m.formatter)),m.interpolator=new aue(this.options),m.utils={hasLoadedNamespace:this.hasLoadedNamespace.bind(this)},m.backendConnector=new cue(i(this.modules.backend),m.resourceStore,m,this.options),m.backendConnector.on("*",(f,...x)=>{this.emit(f,...x)}),this.modules.languageDetector&&(m.languageDetector=i(this.modules.languageDetector),m.languageDetector.init&&m.languageDetector.init(m,this.options.detection,this.options)),this.modules.i18nFormat&&(m.i18nFormat=i(this.modules.i18nFormat),m.i18nFormat.init&&m.i18nFormat.init(this)),this.translator=new mN(this.services,this.options),this.translator.on("*",(f,...x)=>{this.emit(f,...x)}),this.modules.external.forEach(f=>{f.init&&f.init(this)})}if(this.format=this.options.interpolation.format,n||(n=V_),this.options.fallbackLng&&!this.services.languageDetector&&!this.options.lng){const d=this.services.languageUtils.getFallbackCodes(this.options.fallbackLng);d.length>0&&d[0]!=="dev"&&(this.options.lng=d[0])}!this.services.languageDetector&&!this.options.lng&&this.logger.warn("init: no languageDetector is used and no lng is defined"),["getResource","hasResourceBundle","getResourceBundle","getDataByLanguage"].forEach(d=>{this[d]=(...u)=>this.store[d](...u)}),["addResource","addResources","addResourceBundle","removeResourceBundle"].forEach(d=>{this[d]=(...u)=>(this.store[d](...u),this)});const l=Cv(),c=()=>{const d=(u,m)=>{this.isInitializing=!1,this.isInitialized&&!this.initializedStoreOnce&&this.logger.warn("init: i18next is already initialized. You should call init just once!"),this.isInitialized=!0,this.options.isClone||this.logger.log("initialized",this.options),this.emit("initialized",this.options),l.resolve(m),n(u,m)};if(this.languages&&!this.isInitialized)return d(null,this.t.bind(this));this.changeLanguage(this.options.lng,d)};return this.options.resources||!this.options.initAsync?c():setTimeout(c,0),l}loadResources(e,n=V_){let r=n;const i=$n(e)?e:this.language;if(typeof e=="function"&&(r=e),!this.options.resources||this.options.partialBundledLanguages){if(i?.toLowerCase()==="cimode"&&(!this.options.preload||this.options.preload.length===0))return r();const s=[],o=l=>{if(!l||l==="cimode")return;this.services.languageUtils.toResolveHierarchy(l).forEach(d=>{d!=="cimode"&&s.indexOf(d)<0&&s.push(d)})};i?o(i):this.services.languageUtils.getFallbackCodes(this.options.fallbackLng).forEach(c=>o(c)),this.options.preload?.forEach?.(l=>o(l)),this.services.backendConnector.load(s,this.options.ns,l=>{!l&&!this.resolvedLanguage&&this.language&&this.setResolvedLanguage(this.language),r(l)})}else r(null)}reloadResources(e,n,r){const i=Cv();return typeof e=="function"&&(r=e,e=void 0),typeof n=="function"&&(r=n,n=void 0),e||(e=this.languages),n||(n=this.options.ns),r||(r=V_),this.services.backendConnector.reload(e,n,s=>{i.resolve(),r(s)}),i}use(e){if(!e)throw new Error("You are passing an undefined module! Please check the object you are passing to i18next.use()");if(!e.type)throw new Error("You are passing a wrong module! Please check the object you are passing to i18next.use()");return e.type==="backend"&&(this.modules.backend=e),(e.type==="logger"||e.log&&e.warn&&e.error)&&(this.modules.logger=e),e.type==="languageDetector"&&(this.modules.languageDetector=e),e.type==="i18nFormat"&&(this.modules.i18nFormat=e),e.type==="postProcessor"&&HY.addPostProcessor(e),e.type==="formatter"&&(this.modules.formatter=e),e.type==="3rdParty"&&this.modules.external.push(e),this}setResolvedLanguage(e){if(!(!e||!this.languages)&&!(["cimode","dev"].indexOf(e)>-1)){for(let n=0;n-1)&&this.store.hasLanguageSomeTranslations(r)){this.resolvedLanguage=r;break}}!this.resolvedLanguage&&this.languages.indexOf(e)<0&&this.store.hasLanguageSomeTranslations(e)&&(this.resolvedLanguage=e,this.languages.unshift(e))}}changeLanguage(e,n){this.isLanguageChangingTo=e;const r=Cv();this.emit("languageChanging",e);const i=l=>{this.language=l,this.languages=this.services.languageUtils.toResolveHierarchy(l),this.resolvedLanguage=void 0,this.setResolvedLanguage(l)},s=(l,c)=>{c?this.isLanguageChangingTo===e&&(i(c),this.translator.changeLanguage(c),this.isLanguageChangingTo=void 0,this.emit("languageChanged",c),this.logger.log("languageChanged",c)):this.isLanguageChangingTo=void 0,r.resolve((...d)=>this.t(...d)),n&&n(l,(...d)=>this.t(...d))},o=l=>{!e&&!l&&this.services.languageDetector&&(l=[]);const c=$n(l)?l:l&&l[0],d=this.store.hasLanguageSomeTranslations(c)?c:this.services.languageUtils.getBestMatchFromCodes($n(l)?[l]:l);d&&(this.language||i(d),this.translator.language||this.translator.changeLanguage(d),this.services.languageDetector?.cacheUserLanguage?.(d)),this.loadResources(d,u=>{s(u,d)})};return!e&&this.services.languageDetector&&!this.services.languageDetector.async?o(this.services.languageDetector.detect()):!e&&this.services.languageDetector&&this.services.languageDetector.async?this.services.languageDetector.detect.length===0?this.services.languageDetector.detect().then(o):this.services.languageDetector.detect(o):o(e),r}getFixedT(e,n,r){const i=(s,o,...l)=>{let c;typeof o!="object"?c=this.options.overloadTranslationOptionHandler([s,o].concat(l)):c={...o},c.lng=c.lng||i.lng,c.lngs=c.lngs||i.lngs,c.ns=c.ns||i.ns,c.keyPrefix!==""&&(c.keyPrefix=c.keyPrefix||r||i.keyPrefix);const d=this.options.keySeparator||".";let u;return c.keyPrefix&&Array.isArray(s)?u=s.map(m=>(typeof m=="function"&&(m=z3(m,{...this.options,...o})),`${c.keyPrefix}${d}${m}`)):(typeof s=="function"&&(s=z3(s,{...this.options,...o})),u=c.keyPrefix?`${c.keyPrefix}${d}${s}`:s),this.t(u,c)};return $n(e)?i.lng=e:i.lngs=e,i.ns=n,i.keyPrefix=r,i}t(...e){return this.translator?.translate(...e)}exists(...e){return this.translator?.exists(...e)}setDefaultNamespace(e){this.options.defaultNS=e}hasLoadedNamespace(e,n={}){if(!this.isInitialized)return this.logger.warn("hasLoadedNamespace: i18next was not initialized",this.languages),!1;if(!this.languages||!this.languages.length)return this.logger.warn("hasLoadedNamespace: i18n.languages were undefined or empty",this.languages),!1;const r=n.lng||this.resolvedLanguage||this.languages[0],i=this.options?this.options.fallbackLng:!1,s=this.languages[this.languages.length-1];if(r.toLowerCase()==="cimode")return!0;const o=(l,c)=>{const d=this.services.backendConnector.state[`${l}|${c}`];return d===-1||d===0||d===2};if(n.precheck){const l=n.precheck(this,o);if(l!==void 0)return l}return!!(this.hasResourceBundle(r,e)||!this.services.backendConnector.backend||this.options.resources&&!this.options.partialBundledLanguages||o(r,e)&&(!i||o(s,e)))}loadNamespaces(e,n){const r=Cv();return this.options.ns?($n(e)&&(e=[e]),e.forEach(i=>{this.options.ns.indexOf(i)<0&&this.options.ns.push(i)}),this.loadResources(i=>{r.resolve(),n&&n(i)}),r):(n&&n(),Promise.resolve())}loadLanguages(e,n){const r=Cv();$n(e)&&(e=[e]);const i=this.options.preload||[],s=e.filter(o=>i.indexOf(o)<0&&this.services.languageUtils.isSupportedCode(o));return s.length?(this.options.preload=i.concat(s),this.loadResources(o=>{r.resolve(),n&&n(o)}),r):(n&&n(),Promise.resolve())}dir(e){if(e||(e=this.resolvedLanguage||(this.languages?.length>0?this.languages[0]:this.language)),!e)return"rtl";try{const i=new Intl.Locale(e);if(i&&i.getTextInfo){const s=i.getTextInfo();if(s&&s.direction)return s.direction}}catch{}const n=["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ug","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam","ckb"],r=this.services?.languageUtils||new $8(X8());return e.toLowerCase().indexOf("-latn")>1?"ltr":n.indexOf(r.getLanguagePartFromCode(e))>-1||e.toLowerCase().indexOf("-arab")>1?"rtl":"ltr"}static createInstance(e={},n){const r=new k0(e,n);return r.createInstance=k0.createInstance,r}cloneInstance(e={},n=V_){const r=e.forkResourceStore;r&&delete e.forkResourceStore;const i={...this.options,...e,isClone:!0},s=new k0(i);if((e.debug!==void 0||e.prefix!==void 0)&&(s.logger=s.logger.clone(e)),["store","services","language"].forEach(l=>{s[l]=this[l]}),s.services={...this.services},s.services.utils={hasLoadedNamespace:s.hasLoadedNamespace.bind(s)},r){const l=Object.keys(this.store.data).reduce((c,d)=>(c[d]={...this.store.data[d]},c[d]=Object.keys(c[d]).reduce((u,m)=>(u[m]={...c[d][m]},u),c[d]),c),{});s.store=new H8(l,i),s.services.resourceStore=s.store}return s.translator=new mN(s.services,i),s.translator.on("*",(l,...c)=>{s.emit(l,...c)}),s.init(i,n),s.translator.options=i,s.translator.backendConnector.services.utils={hasLoadedNamespace:s.hasLoadedNamespace.bind(s)},s}toJSON(){return{options:this.options,store:this.store,language:this.language,languages:this.languages,resolvedLanguage:this.resolvedLanguage}}}const xo=k0.createInstance();xo.createInstance;xo.dir;xo.init;xo.loadResources;xo.reloadResources;xo.use;xo.changeLanguage;xo.getFixedT;xo.t;xo.exists;xo.setDefaultNamespace;xo.hasLoadedNamespace;xo.loadNamespaces;xo.loadLanguages;const uue=(t,e,n,r)=>{const i=[n,{code:e,...r||{}}];if(t?.services?.logger?.forward)return t.services.logger.forward(i,"warn","react-i18next::",!0);ng(i[0])&&(i[0]=`react-i18next:: ${i[0]}`),t?.services?.logger?.warn?t.services.logger.warn(...i):console?.warn&&console.warn(...i)},Q8={},$Y=(t,e,n,r)=>{ng(n)&&Q8[n]||(ng(n)&&(Q8[n]=new Date),uue(t,e,n,r))},VY=(t,e)=>()=>{if(t.isInitialized)e();else{const n=()=>{setTimeout(()=>{t.off("initialized",n)},0),e()};t.on("initialized",n)}},U3=(t,e,n)=>{t.loadNamespaces(e,VY(t,n))},Z8=(t,e,n,r)=>{if(ng(n)&&(n=[n]),t.options.preload&&t.options.preload.indexOf(e)>-1)return U3(t,n,r);n.forEach(i=>{t.options.ns.indexOf(i)<0&&t.options.ns.push(i)}),t.loadLanguages(e,VY(t,r))},mue=(t,e,n={})=>!e.languages||!e.languages.length?($Y(e,"NO_LANGUAGES","i18n.languages were undefined or empty",{languages:e.languages}),!0):e.hasLoadedNamespace(t,{lng:n.lng,precheck:(r,i)=>{if(n.bindI18n&&n.bindI18n.indexOf("languageChanging")>-1&&r.services.backendConnector.backend&&r.isLanguageChangingTo&&!i(r.isLanguageChangingTo,t))return!1}}),ng=t=>typeof t=="string",hue=t=>typeof t=="object"&&t!==null,pue=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,fue={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},gue=t=>fue[t],bue=t=>t.replace(pue,gue);let B3={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:bue,transDefaultProps:void 0};const xue=(t={})=>{B3={...B3,...t}},yue=()=>B3;let GY;const vue=t=>{GY=t},wue=()=>GY,Sue={type:"3rdParty",init(t){xue(t.options.react),vue(t)}},_ue=w.createContext();class kue{constructor(){this.usedNamespaces={}}addUsedNamespaces(e){e.forEach(n=>{this.usedNamespaces[n]||(this.usedNamespaces[n]=!0)})}getUsedNamespaces(){return Object.keys(this.usedNamespaces)}}var vM={exports:{}},wM={};var J8;function Nue(){if(J8)return wM;J8=1;var t=jg();function e(m,p){return m===p&&(m!==0||1/m===1/p)||m!==m&&p!==p}var n=typeof Object.is=="function"?Object.is:e,r=t.useState,i=t.useEffect,s=t.useLayoutEffect,o=t.useDebugValue;function l(m,p){var f=p(),x=r({inst:{value:f,getSnapshot:p}}),v=x[0].inst,b=x[1];return s(function(){v.value=f,v.getSnapshot=p,c(v)&&b({inst:v})},[m,f,p]),i(function(){return c(v)&&b({inst:v}),m(function(){c(v)&&b({inst:v})})},[m]),o(f),f}function c(m){var p=m.getSnapshot;m=m.value;try{var f=p();return!n(m,f)}catch{return!0}}function d(m,p){return p()}var u=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?d:l;return wM.useSyncExternalStore=t.useSyncExternalStore!==void 0?t.useSyncExternalStore:u,wM}var eH;function WY(){return eH||(eH=1,vM.exports=Nue()),vM.exports}var cO=WY();const Cue=(t,e)=>ng(e)?e:hue(e)&&ng(e.defaultValue)?e.defaultValue:Array.isArray(t)?t[t.length-1]:t,Pue={t:Cue,ready:!1},Tue=()=>()=>{},Dt=(t,e={})=>{const{i18n:n}=e,{i18n:r,defaultNS:i}=w.useContext(_ue)||{},s=n||r||wue();s&&!s.reportNamespaces&&(s.reportNamespaces=new kue),s||$Y(s,"NO_I18NEXT_INSTANCE","useTranslation: You will need to pass in an i18next instance by using initReactI18next");const o=w.useMemo(()=>({...yue(),...s?.options?.react,...e}),[s,e]),{useSuspense:l,keyPrefix:c}=o,d=i||s?.options?.defaultNS,u=ng(d)?[d]:d||["translation"],m=w.useMemo(()=>u,u);s?.reportNamespaces?.addUsedNamespaces?.(m);const p=w.useRef(0),f=w.useCallback(k=>{if(!s)return Tue;const{bindI18n:D,bindI18nStore:H}=o,z=()=>{p.current+=1,k()};return D&&s.on(D,z),H&&s.store.on(H,z),()=>{D&&D.split(" ").forEach(Y=>s.off(Y,z)),H&&H.split(" ").forEach(Y=>s.store.off(Y,z))}},[s,o]),x=w.useRef(),v=w.useCallback(()=>{if(!s)return Pue;const k=!!(s.isInitialized||s.initializedStoreOnce)&&m.every(te=>mue(te,s,o)),D=e.lng||s.language,H=p.current,z=x.current;if(z&&z.ready===k&&z.lng===D&&z.keyPrefix===c&&z.revision===H)return z;const L={t:s.getFixedT(D,o.nsMode==="fallback"?m:m[0],c),ready:k,lng:D,keyPrefix:c,revision:H};return x.current=L,L},[s,m,c,o,e.lng]),[b,g]=w.useState(0),{t:_,ready:C}=cO.useSyncExternalStore(f,v,v);w.useEffect(()=>{if(s&&!C&&!l){const k=()=>g(D=>D+1);e.lng?Z8(s,e.lng,m,k):U3(s,m,k)}},[s,e.lng,m,C,l,b]);const P=s||{},N=w.useRef(null),A=w.useRef(),T=k=>{const D=Object.getOwnPropertyDescriptors(k);D.__original&&delete D.__original;const H=Object.create(Object.getPrototypeOf(k),D);if(!Object.prototype.hasOwnProperty.call(H,"__original"))try{Object.defineProperty(H,"__original",{value:k,writable:!1,enumerable:!1,configurable:!1})}catch{}return H},F=w.useMemo(()=>{const k=P,D=k?.language;let H=k;k&&(N.current&&N.current.__original===k?A.current!==D?(H=T(k),N.current=H,A.current=D):H=N.current:(H=T(k),N.current=H,A.current=D));const z=[_,H,C];return z.t=_,z.i18n=H,z.ready=C,z},[_,P,C,P.resolvedLanguage,P.language,P.languages]);if(s&&l&&!C)throw new Promise(k=>{const D=()=>k();e.lng?Z8(s,e.lng,m,D):U3(s,m,D)});return F},{slice:Aue,forEach:jue}=[];function Mue(t){return jue.call(Aue.call(arguments,1),e=>{if(e)for(const n in e)t[n]===void 0&&(t[n]=e[n])}),t}function Eue(t){return typeof t!="string"?!1:[/<\s*script.*?>/i,/<\s*\/\s*script\s*>/i,/<\s*img.*?on\w+\s*=/i,/<\s*\w+\s*on\w+\s*=.*?>/i,/javascript\s*:/i,/vbscript\s*:/i,/expression\s*\(/i,/eval\s*\(/i,/alert\s*\(/i,/document\.cookie/i,/document\.write\s*\(/i,/window\.location/i,/innerHTML/i].some(n=>n.test(t))}const tH=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/,Due=function(t,e){const r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{path:"/"},i=encodeURIComponent(e);let s=`${t}=${i}`;if(r.maxAge>0){const o=r.maxAge-0;if(Number.isNaN(o))throw new Error("maxAge should be a Number");s+=`; Max-Age=${Math.floor(o)}`}if(r.domain){if(!tH.test(r.domain))throw new TypeError("option domain is invalid");s+=`; Domain=${r.domain}`}if(r.path){if(!tH.test(r.path))throw new TypeError("option path is invalid");s+=`; Path=${r.path}`}if(r.expires){if(typeof r.expires.toUTCString!="function")throw new TypeError("option expires is invalid");s+=`; Expires=${r.expires.toUTCString()}`}if(r.httpOnly&&(s+="; HttpOnly"),r.secure&&(s+="; Secure"),r.sameSite)switch(typeof r.sameSite=="string"?r.sameSite.toLowerCase():r.sameSite){case!0:s+="; SameSite=Strict";break;case"lax":s+="; SameSite=Lax";break;case"strict":s+="; SameSite=Strict";break;case"none":s+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}return r.partitioned&&(s+="; Partitioned"),s},nH={create(t,e,n,r){let i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:{path:"/",sameSite:"strict"};n&&(i.expires=new Date,i.expires.setTime(i.expires.getTime()+n*60*1e3)),r&&(i.domain=r),document.cookie=Due(t,e,i)},read(t){const e=`${t}=`,n=document.cookie.split(";");for(let r=0;r-1&&(r=window.location.hash.substring(window.location.hash.indexOf("?")));const s=r.substring(1).split("&");for(let o=0;o0&&s[o].substring(0,l)===e&&(n=s[o].substring(l+1))}}return n}},Lue={name:"hash",lookup(t){let{lookupHash:e,lookupFromHashIndex:n}=t,r;if(typeof window<"u"){const{hash:i}=window.location;if(i&&i.length>2){const s=i.substring(1);if(e){const o=s.split("&");for(let l=0;l0&&o[l].substring(0,c)===e&&(r=o[l].substring(c+1))}}if(r)return r;if(!r&&n>-1){const o=i.match(/\/([a-zA-Z-]*)/g);return Array.isArray(o)?o[typeof n=="number"?n:0]?.replace("/",""):void 0}}}return r}};let wb=null;const rH=()=>{if(wb!==null)return wb;try{if(wb=typeof window<"u"&&window.localStorage!==null,!wb)return!1;const t="i18next.translate.boo";window.localStorage.setItem(t,"foo"),window.localStorage.removeItem(t)}catch{wb=!1}return wb};var Oue={name:"localStorage",lookup(t){let{lookupLocalStorage:e}=t;if(e&&rH())return window.localStorage.getItem(e)||void 0},cacheUserLanguage(t,e){let{lookupLocalStorage:n}=e;n&&rH()&&window.localStorage.setItem(n,t)}};let Sb=null;const aH=()=>{if(Sb!==null)return Sb;try{if(Sb=typeof window<"u"&&window.sessionStorage!==null,!Sb)return!1;const t="i18next.translate.boo";window.sessionStorage.setItem(t,"foo"),window.sessionStorage.removeItem(t)}catch{Sb=!1}return Sb};var Iue={name:"sessionStorage",lookup(t){let{lookupSessionStorage:e}=t;if(e&&aH())return window.sessionStorage.getItem(e)||void 0},cacheUserLanguage(t,e){let{lookupSessionStorage:n}=e;n&&aH()&&window.sessionStorage.setItem(n,t)}},zue={name:"navigator",lookup(t){const e=[];if(typeof navigator<"u"){const{languages:n,userLanguage:r,language:i}=navigator;if(n)for(let s=0;s0?e:void 0}},Uue={name:"htmlTag",lookup(t){let{htmlTag:e}=t,n;const r=e||(typeof document<"u"?document.documentElement:null);return r&&typeof r.getAttribute=="function"&&(n=r.getAttribute("lang")),n}},Bue={name:"path",lookup(t){let{lookupFromPathIndex:e}=t;if(typeof window>"u")return;const n=window.location.pathname.match(/\/([a-zA-Z-]*)/g);return Array.isArray(n)?n[typeof e=="number"?e:0]?.replace("/",""):void 0}},Hue={name:"subdomain",lookup(t){let{lookupFromSubdomainIndex:e}=t;const n=typeof e=="number"?e+1:1,r=typeof window<"u"&&window.location?.hostname?.match(/^(\w{2,5})\.(([a-z0-9-]{1,63}\.[a-z]{2,6})|localhost)/i);if(r)return r[n]}};let KY=!1;try{document.cookie,KY=!0}catch{}const XY=["querystring","cookie","localStorage","sessionStorage","navigator","htmlTag"];KY||XY.splice(1,1);const que=()=>({order:XY,lookupQuerystring:"lng",lookupCookie:"i18next",lookupLocalStorage:"i18nextLng",lookupSessionStorage:"i18nextLng",caches:["localStorage"],excludeCacheFor:["cimode"],convertDetectedLanguage:t=>t});class YY{constructor(e){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};this.type="languageDetector",this.detectors={},this.init(e,n)}init(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{languageUtils:{}},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};this.services=e,this.options=Mue(n,this.options||{},que()),typeof this.options.convertDetectedLanguage=="string"&&this.options.convertDetectedLanguage.indexOf("15897")>-1&&(this.options.convertDetectedLanguage=i=>i.replace("-","_")),this.options.lookupFromUrlIndex&&(this.options.lookupFromPathIndex=this.options.lookupFromUrlIndex),this.i18nOptions=r,this.addDetector(Fue),this.addDetector(Rue),this.addDetector(Oue),this.addDetector(Iue),this.addDetector(zue),this.addDetector(Uue),this.addDetector(Bue),this.addDetector(Hue),this.addDetector(Lue)}addDetector(e){return this.detectors[e.name]=e,this}detect(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:this.options.order,n=[];return e.forEach(r=>{if(this.detectors[r]){let i=this.detectors[r].lookup(this.options);i&&typeof i=="string"&&(i=[i]),i&&(n=n.concat(i))}}),n=n.filter(r=>r!=null&&!Eue(r)).map(r=>this.options.convertDetectedLanguage(r)),this.services&&this.services.languageUtils&&this.services.languageUtils.getBestMatchFromCodes?n:n.length>0?n[0]:null}cacheUserLanguage(e){let n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:this.options.caches;n&&(this.options.excludeCacheFor&&this.options.excludeCacheFor.indexOf(e)>-1||n.forEach(r=>{this.detectors[r]&&this.detectors[r].cacheUserLanguage(e,this.options)}))}}YY.type="languageDetector";const $ue={nav:{printers:"Printers",archives:"Archives",queue:"Queue",stats:"Statistics",profiles:"Profiles",maintenance:"Maintenance",projects:"Projects",inventory:"Filament",files:"File Manager",notifications:"Notifications",settings:"Settings",system:"System",collapseSidebar:"Collapse sidebar",expandSidebar:"Expand sidebar",update:"Update",updateAvailable:"Update available: v{{version}}",updateAvailableBanner:"Version {{version}} is available!",viewUpdate:"View update",viewOnGithub:"View on GitHub",keyboardShortcuts:"Keyboard shortcuts (?)",switchToLight:"Switch to light mode",switchToDark:"Switch to dark mode",smartSwitches:"Smart Switches",logout:"Logout"},common:{save:"Save",saving:"Saving...",cancel:"Cancel",delete:"Delete",edit:"Edit",add:"Add",close:"Close",confirm:"Confirm",loading:"Loading...",error:"Error",success:"Success",warning:"Warning",enabled:"Enabled",disabled:"Disabled",yes:"Yes",no:"No",on:"On",off:"Off",all:"All",none:"None",search:"Search",filter:"Filter",sort:"Sort",refresh:"Refresh",download:"Download",upload:"Upload",uploading:"Uploading...",uploadFailed:"Upload failed",actions:"Actions",status:"Status",name:"Name",description:"Description",date:"Date",time:"Time",hours:"hours",minutes:"minutes",seconds:"seconds",days:"days",enable:"Enable",disable:"Disable",permissions:"Permissions",noPrinters:"No printers configured",noData:"No data available",linkNotFound:"Link not found",required:"Required",optional:"Optional",dismiss:"Dismiss",apply:"Apply",reset:"Reset",export:"Export",import:"Import",clear:"Clear",selectAll:"Select All",deselectAll:"Deselect All",noChange:"— No change —",unchanged:"Unchanged",unassigned:"Unassigned",unknown:"Unknown",unknownError:"Unknown error",today:"Today",tomorrow:"Tomorrow",asap:"ASAP",overdue:"Overdue",now:"Now",collapse:"Collapse",expand:"Expand",viewArchive:"View archive",viewInFileManager:"View in File Manager",addedBy:"Added by {{username}}",prints:"prints",more:"+{{count}} more",ascending:"Ascending",descending:"Descending",back:"Back",copy:"Copy",copied:"Copied!",printer:"Printer",remove:"Remove",type:"Type",print:"Print",rename:"Rename",move:"Move",create:"Create",duplicate:"Duplicate",left:"Left",right:"Right"},printers:{title:"Printers",addPrinter:"Add Printer",editPrinter:"Edit Printer",deletePrinter:"Delete Printer",printerName:"Printer Name",serialNumber:"Serial Number",ipAddress:"IP Address / Hostname",accessCode:"Access Code",model:"Model",nozzleCount:"Nozzle Count",autoArchive:"Auto Archive",status:{available:"Available",idle:"Idle",printing:"Printing",paused:"Paused",offline:"Offline",problem:"Problem",error:"Error",finished:"Finished",unknown:"Unknown"},temperatures:{nozzle:"Nozzle",bed:"Bed",chamber:"Chamber"},progress:"{{percent}}% complete",timeRemaining:"{{time}} remaining",deleteConfirm:'Are you sure you want to delete "{{name}}"?',maintenanceOk:"Maintenance OK",maintenanceWarning:"{{count}} warning",maintenanceWarning_plural:"{{count}} warnings",maintenanceDue:"{{count}} due",maintenanceDue_plural:"{{count}} due",sort:{name:"Name",status:"Status",model:"Model",location:"Location",ascending:"Sort ascending",descending:"Sort descending"},cardSize:{small:"Small cards",medium:"Medium cards",large:"Large cards",extraLarge:"Extra large cards"},hideOffline:"Hide offline",nextAvailable:"Next available",powerOn:"Power On",offlinePrintersWithPlugs:"Offline printers with smart plugs",noPrintersConfigured:"No printers configured yet",search:"Search printers...",noSearchResults:"No printers match your search or filters",filter:{allStatuses:"All statuses",allLocations:"All locations"},readyToPrint:"Ready to print",external:"External",extL:"Ext-L",extR:"Ext-R",deleteArchives:"Delete print archives",noLabel:"No label",printPreview:"Print preview",width:"Width",height:"Height",noObjectsFound:"No objects found",objectsLoadedOnPrintStart:"Objects are loaded when a print starts",willBeSkipped:"Will be skipped",name:"Name",serialCannotBeChanged:"Serial number cannot be changed",locationHelp:"Used to group printers and filter queue jobs",wifiSignal:{veryWeak:"Very weak",weak:"Weak",fair:"Fair",good:"Good",excellent:"Excellent"},maintenanceUpToDate:"All maintenance up to date - Click to view",chamberLightOn:"Turn on chamber light",chamberLightOff:"Turn off chamber light",files:"Files",browseFiles:"Browse printer files",autoOffAfterPrint:"Auto power-off after print",autoOffExecuted:"Auto-off was executed - turn printer on to reset",hmsErrors:"HMS Errors",viewHmsErrors:"View {{count}} HMS error(s)",resume:"Resume",pause:"Pause",stop:"Stop",camera:"Camera",skipObject:"Skip Object",reconnect:"Reconnect",forceRefresh:"Force Refresh",forceRefreshSuccess:"Refresh requested",mqttDebug:"MQTT Debug",printerInformation:"Printer Information",copyToClipboard:"Copy",copied:"Copied!",state:"State",wifiSignalLabel:"WiFi Signal",developerMode:"Developer Mode",enabled:"Enabled",disabled:"Disabled",addedOn:"Added",sdCard:"SD Card",inserted:"Inserted",notInserted:"Not inserted",totalPrintHours:"Print Hours",activeNozzle:"Active: {{nozzle}} nozzle",nozzleRack:"Nozzle Rack",nozzleDocked:"Docked",nozzleMounted:"Mounted",nozzleActive:"Active",nozzleIdle:"Idle",nozzleDiameter:"Diameter",nozzleType:"Type",nozzleStatus:"Status",nozzleFilament:"Filament",nozzleWear:"Wear",nozzleMaxTemp:"Max Temp",nozzleSerial:"Serial",nozzleHardenedSteel:"Hardened Steel",nozzleStainlessSteel:"Stainless Steel",nozzleTungstenCarbide:"Tungsten Carbide",nozzleFlow:"Flow",nozzleHighFlow:"High Flow",nozzleStandardFlow:"Standard",firmwareUpdate:"Firmware Update",firmwareInstructions:"On the printer's touchscreen, go to",firmwareNav:"Navigate to",settings:"Settings",firmware:"Firmware",discoverPrinters:"Discover Printers",searching:"Searching...",manualEntry:"Manual Entry",addFromCloud:"Add from Cloud",toast:{printerDeleted:"Printer deleted",missingSpoolAssignment:"Print started on {{printer}}. Missing spool assignment for: {{slots}}",printerAdded:"Printer added",printerUpdated:"Printer updated",failedToDelete:"Failed to delete printer",failedToAdd:"Failed to add printer",failedToUpdate:"Failed to update printer",commandSent:"Command sent",failedToSendCommand:"Failed to send command",turnedOn:"{{name}} turned on",failedToPowerOn:"Failed to power on {{name}}",scriptTriggered:"Script triggered",printStopped:"Print stopped",printPaused:"Print paused",printResumed:"Print resumed",referenceDeleted:"Reference deleted",detectionAreaSaved:"Detection area saved",failedToRunScript:"Failed to run script",failedToStopPrint:"Failed to stop print",failedToPausePrint:"Failed to pause print",failedToResumePrint:"Failed to resume print",failedToControlChamberLight:"Failed to control chamber light",failedToSetSpeed:"Failed to set print speed",failedToUpdateSetting:"Failed to update setting",failedToSkipObjects:"Failed to skip objects",failedToRereadRfid:"Failed to re-read RFID",failedToCheckPlate:"Failed to check plate",failedToUpdateLabel:"Failed to update label",failedToDeleteReference:"Failed to delete reference",failedToSaveDetectionArea:"Failed to save detection area",plateCheckEnabled:"Plate check enabled",plateCheckDisabled:"Plate check disabled",calibrationSaved:"Calibration saved!",calibrationFailed:"Calibration failed",rfidRereadInitiated:"RFID re-read initiated"},connection:{connected:"Connected",offline:"Offline"},plateStatus:{markCleared:"Mark plate as cleared",cleared:"Plate Clear",notCleared:"Plate not Clear",inUse:"Plate in Use"},queue:{inQueue:"{{count}} print in queue",inQueue_plural:"{{count}} prints in queue"},controls:"Controls",rfid:{reread:"Re-read RFID"},bedJog:{title:"Move build plate",bed:"Bed",step:"Step (mm)",up:"Move plate up",down:"Move plate down",disabledWhilePrinting:"Disabled while printing",notHomedTitle:"Printer is not homed",notHomedMessage:"The Z axis has not been homed since the last print. Home Z first for safe positioning, or move anyway — soft endstops will be bypassed.",homeZ:"Home Z",moveAnyway:"Move anyway",homingStarted:"Homing Z axis…"},permission:{noAdd:"You do not have permission to add printers",noEdit:"You do not have permission to edit printers",noDelete:"You do not have permission to delete printers",noControl:"You do not have permission to control printers",noFiles:"You do not have permission to access printer files",noAmsRfid:"You do not have permission to re-read AMS RFID",noSmartPlugControl:"You do not have permission to control smart plugs",noCamera:"You do not have permission to view cameras"},modal:{addTitle:"Add Printer",editTitle:"Edit Printer",myPrinter:"My Printer",selectModel:"Select model...",locationGroup:"Location / Group (optional)",locationPlaceholder:"e.g., Workshop, Office, Basement",autoArchiveLabel:"Auto-archive completed prints",fromPrinterSettings:"From printer settings",modelOptional:"Model (optional)",saveChanges:"Save Changes"},skipObjects:{tooltip:"Skip objects",onlyWhilePrinting:"Skip objects (only while printing)",requiresMultiple:"Skip objects (requires 2+ objects)",title:"Skip Objects",matchIdsInfo:"Match IDs with your printer display",printerShowsIds:"The printer screen shows object IDs on the build plate",skipSelected:"Skip Selected",skipping:"Skipping...",noObjectsSelected:"No objects selected",selectObjectsToSkip:"Select objects you want to skip from the current print",skipped:"skipped",objectsSkipped:"Objects skipped",activeCount:"{{count}} active",waitForLayer:"Wait for layer 2+ to skip objects (currently layer {{layer}})",skip:"Skip",confirmTitle:"Skip Object?",confirmMessage:'Are you sure you want to skip "{{name}}"? This cannot be undone.'},confirm:{deleteTitle:"Delete Printer",deleteMessage:'Are you sure you want to delete "{{name}}"? This will remove all connection settings.',deleteArchivesNote:"All print history for this printer will be permanently deleted.",keepArchivesNote:"Print history will be kept but no longer associated with this printer.",stopTitle:"Stop Print",stopMessage:'Are you sure you want to stop the current print on "{{name}}"? This will cancel the print job.',stopButton:"Stop Print",pauseTitle:"Pause Print",pauseMessage:'Are you sure you want to pause the current print on "{{name}}"?',pauseButton:"Pause Print",resumeTitle:"Resume Print",resumeMessage:'Are you sure you want to resume the print on "{{name}}"?',resumeButton:"Resume Print",powerOnTitle:"Power On Printer",powerOnMessage:'Are you sure you want to turn ON the power for "{{name}}"?',powerOnButton:"Power On",powerOffTitle:"Power Off Printer",powerOffMessage:'Are you sure you want to turn OFF the power for "{{name}}"?',powerOffWarning:'WARNING: "{{name}}" is currently printing! Are you sure you want to turn OFF the power? This will interrupt the print and may damage the printer.',powerOffButton:"Power Off"},bulk:{select:"Select",selectAll:"Select All",selectByLocation:"Select by Location",selected:"{{count}} selected",actions:{stop:"Stop",pause:"Pause",resume:"Resume",clearPlate:"Clear Bed",clearHMS:"Clear Notifications"},confirm:{stopTitle:"Stop {{count}} Prints",stopMessage:"This will cancel active prints on {{count}} printer(s). This action cannot be undone.",stopButton:"Stop All",pauseTitle:"Pause {{count}} Prints",pauseMessage:"This will pause active prints on {{count}} printer(s).",pauseButton:"Pause All",clearPlateTitle:"Clear {{count}} Print Beds",clearPlateMessage:"This will clear the print bed on {{count}} printer(s) and may trigger queued jobs.",clearPlateButton:"Clear All"},success:"{{action}} completed on {{count}} printer(s)",partial:"{{succeeded}} succeeded, {{failed}} failed",noneApplicable:"No selected printers are in the right state for this action",selectByState:"Select by State"},discovery:{title:"Discover Printers",searching:"Searching...",scanning:"Scanning...",scanProgress:"Scanning... {{scanned}}/{{total}}",foundPrinters:"Found {{count}} printer(s)",noPrintersFound:"No printers found",noPrintersFoundSubnet:"No printers found in the specified subnet.",noPrintersFoundNetwork:"No printers found on the network.",allConfigured:"All discovered printers are already configured.",alreadyAdded:"Already added",select:"Select",manualEntry:"Manual Entry",addFromCloud:"Add from Cloud",subnetToScan:"Subnet to scan",dockerNote:"Docker detected. Enter your printer's subnet in CIDR notation. Requires network_mode: host in docker-compose.yml.",scanSubnet:"Scan Subnet for Printers",discoverNetwork:"Discover Printers on Network",scanningSubnet:"Scanning subnet for Bambu printers...",scanningNetwork:"Scanning network...",serialRequired:"Serial required",unknown:"Unknown",failedToStart:"Failed to start discovery"},drying:{start:"Start Drying",stop:"Stop Drying",temperature:"Temperature",duration:"Duration",hours:"hours",timeRemaining:"{{time}} left",active:"Drying",notSupported:"Drying not supported",powerRequired:"Connect AMS power adapter to enable drying",startingDrying:"Starting drying...",stoppingDrying:"Stopping drying...",rotateTray:"Rotate spool during drying"},filaments:"Filaments",openCameraOverlay:"Open camera overlay",openCameraWindow:"Open camera in new window",firmwareUpdateAvailable:"Firmware update available: {{current}} → {{latest}}",firmwareUpToDate:"Firmware {{version}} — Up to date",firmwareUpdateButton:"Update",plateDetection:{noPermission:"You do not have permission to update printers",enabledClick:"Plate check enabled - Click to disable",disabledClick:"Plate check disabled - Click to enable",manageCalibration:"Manage plate detection calibration",calibrationRequired:"Calibration Required",calibrationInstructions:"Please ensure the build plate is completely empty, then click Calibrate.",calibrationDescription:"Calibration captures a reference image of the empty plate. Future checks will compare against this reference to detect objects.",calibrationTip:"Tip: You can store up to 5 calibrations for different plates. The system automatically uses the best match when checking.",plateEmpty:"Plate appears empty",objectsDetected:"Objects detected on plate",confidence:"Confidence",difference:"Difference",analysisPreview:"Analysis preview:",analysisLegend:"Green box = detection area, Red overlay = differences from calibration",savedReferences:"Saved References ({{count}}/{{max}})",deleteReference:"Delete reference",labelPlaceholder:"Label...",clickToEdit:"{{label}} - Click to edit",clickToAddLabel:"Click to add label"},speed:{title:"Print Speed",silent:"Silent (50%)",standard:"Standard (100%)",sport:"Sport (124%)",ludicrous:"Ludicrous (166%)"},airduct:{title:"Airduct Mode",cooling:"Cooling",heating:"Heating"},noSdCard:"No SD",door:{open:"Open",closed:"Closed"},fans:{partCooling:"Part Cooling Fan",auxiliary:"Auxiliary Fan",chamber:"Chamber Fan"},clickToViewHmsErrors:"Click to view HMS errors",estimatedCompletion:"Estimated completion time",plateNumber:"Plate {{number}}",slotOptions:"Slot options",amsPopup:{friendlyName:"AMS Name",friendlyNamePlaceholder:"e.g. AMS Friendly Name",serialNumber:"Serial Number",firmwareVersion:"Firmware",save:"Save",clear:"Clear",noEditPermission:"You do not have permission to rename AMS units"},firmwareModal:{title:"Firmware Update",titleUpToDate:"Firmware Info",currentVersion:"Current:",latestVersion:"Latest:",releaseNotes:"Release Notes",checkingPrereqs:"Checking prerequisites...",sdCardReady:"SD card ready. Click below to upload firmware.",uploadedSuccess:"Firmware uploaded to SD card!",applyInstructions:"To apply the update on your printer:",step1:"On the printer's touchscreen, go to Settings",step2:"Navigate to Firmware",step3:"Select Update from SD card",step4:"The update will take 10-20 minutes",done:"Done",starting:"Starting...",uploadFirmware:"Upload Firmware",uploadFailed:"Failed to start upload: {{error}}",uploadedToast:"Firmware uploaded! Trigger update from printer screen.",availableVersions:"Available versions",usable:"Usable",unavailable:"Unavailable",installed:"Installed",newerBadge:"newer",olderBadge:"older",currentBadge:"current"},accessCodePlaceholder:"Leave empty to keep current",roi:{title:"Detection Area (ROI)",xStart:"X Start",yStart:"Y Start",width:"Width",height:"Height",instruction:"Adjust the detection area to focus on the build plate. The green box in the preview shows the current area."},developerModeWarning:"Developer LAN mode is not enabled on: {{names}}. Some features may not work.",howToEnable:"How to enable",incompatibleFile:"This file was sliced for {{slicedFor}}, but this printer is a {{printerModel}}",dropNotPrintable:"Only .gcode and .gcode.3mf files can be printed",dropToPrint:"Drop to print",cannotPrint:"Printer busy"},archives:{title:"Print Archives",searchPlaceholder:"Search archives...",filterByPrinter:"Filter by printer",filterByStatus:"Filter by status",sortBy:"Sort by",sortNewest:"Newest first",sortOldest:"Oldest first",sortName:"Name",sortDuration:"Duration",sortLargest:"Largest first",sortSmallest:"Smallest first",sortSize:"Size",noArchives:"No archives found",noArchivesSearch:"No archives match your search",originalPrintNotVisible:"Original print not visible - try clearing filters",noArchivesYet:"No archives yet",prints:"prints",pagination:{showing:"Showing",to:"to",of:"of",show:"Show",page:"Page",all:"All"},loadingArchives:"Loading archives...",releaseToUpload:"Release to upload",showAll:"Show all",showFavoritesOnly:"Show favorites only",gridView:"Grid view",listView:"List view",calendarView:"Calendar view",logView:"Print Log",manageTags:"Manage Tags",showFailedPrints:"Show failed prints",hideFailedPrints:"Hide failed prints",hideDuplicates:"Hide Duplicates",viewOriginalPrint:"Click to view original print (#{{id}})",printTime:"Print Time",filamentUsed:"Filament Used",cost:"Cost",reprint:"Reprint",preview:"Preview",deleteArchive:"Delete Archive",deleteConfirm:"Are you sure you want to delete this archive?",favorite:"Favorite",unfavorite:"Remove from favorites",viewDetails:"View Details",status:{completed:"Completed",failed:"Failed",stopped:"Stopped"},toast:{source3mfAttached:"Source 3MF attached: {{filename}}",failedUploadSource3mf:"Failed to upload source 3MF",source3mfRemoved:"Source 3MF removed",failedRemoveSource3mf:"Failed to remove source 3MF",f3dAttached:"F3D attached: {{filename}}",failedUploadF3d:"Failed to upload F3D",f3dRemoved:"F3D removed",failedRemoveF3d:"Failed to remove F3D",timelapseAttached:"Timelapse attached: {{filename}}",timelapseAlreadyAttached:"Timelapse already attached",noMatchingTimelapse:"No matching timelapse found",failedScanTimelapse:"Failed to scan for timelapse",failedAttachTimelapse:"Failed to attach timelapse",timelapseRemoved:"Timelapse removed",failedRemoveTimelapse:"Failed to remove timelapse",timelapseUploaded:"Timelapse uploaded: {{filename}}",failedUploadTimelapse:"Failed to upload timelapse",archiveDeleted:"Archive deleted",failedDeleteArchive:"Failed to delete archive",addedToFavorites:"Added to favorites",removedFromFavorites:"Removed from favorites",projectUpdated:"Project updated",failedUpdateProject:"Failed to update project",linkCopied:"Link copied to clipboard",failedCopyLink:"Failed to copy link",photoDeleted:"Photo deleted",failedDeletePhoto:"Failed to delete photo",failedDeleteArchives:"Failed to delete archives",failedUpdateFavorites:"Failed to update favorites",exportDownloaded:"Export downloaded",exportFailed:"Export failed"},menu:{print:"Print",schedule:"Schedule",openInBambuStudio:"Open in Slicer",slice:"Slice",externalLink:"External Link",viewOnMakerWorld:"View on MakerWorld",preview3d:"3D Preview",viewTimelapse:"View Timelapse",scanForTimelapse:"Scan for Timelapse",uploadTimelapse:"Upload Timelapse",removeTimelapse:"Remove Timelapse",downloadSource3mf:"Download Source 3MF",uploadSource3mf:"Upload Source 3MF",replaceSource3mf:"Replace Source 3MF",removeSource3mf:"Remove Source 3MF",uploadF3d:"Upload F3D",replaceF3d:"Replace F3D",downloadF3d:"Download F3D",removeF3d:"Remove F3D",download:"Download",copyDownloadLink:"Copy Download Link",qrCode:"QR Code",viewPhotos:"View Photos",viewPhotosCount:"View Photos ({{count}})",projectPage:"Project Page",addToFavorites:"Add to Favorites",removeFromFavorites:"Remove from Favorites",edit:"Edit",goToProject:"Go to Project: {{name}}",addToProject:"Add to Project",removeFromProject:"Remove from Project",loading:"Loading...",noProjectsAvailable:"No projects available",select:"Select",deselect:"Deselect",delete:"Delete"},permission:{noReprint:"You do not have permission to reprint this archive",noAddToQueue:"You do not have permission to add to queue",noUpdateArchives:"You do not have permission to update archives",noUploadFiles:"You do not have permission to upload files",noDownload:"You do not have permission to download archives",noCopyLink:"You do not have permission to copy download links",noDelete:"You do not have permission to delete this archive",noCreate:"You do not have permission to create archives"},card:{previousPlate:"Previous plate",nextPlate:"Next plate",plateNumber:"Plate {{index}}",moreOptions:"Right-click for more options",addToFavorites:"Add to favorites",removeFromFavorites:"Remove from favorites",cancelled:"cancelled",failed:"failed",duplicate:"duplicate",duplicateTitle:"This model has been printed before",openSource3mf:"Open source 3MF in Bambu Studio (right-click for more options)",downloadF3d:"Download Fusion 360 design file",viewTimelapse:"View timelapse",viewPhoto:"View 1 photo",viewPhotos:"View {{count}} photos",openFolder:"Open folder: {{name}}",slicedFile:"Sliced file - ready to print",sourceFile:"Source file only - no AMS mapping available",gcode:"GCODE",source:"SOURCE",project:"Project: {{name}}",estimated:"Estimated: {{time}}",actual:"Actual: {{time}}",accuracy:"Accuracy: {{percent}}%",filament:"{{weight}}g",layer:"{{count}} layer",layers:"{{count}} layers",object:"{{count}} object",objects:"{{count}} objects",slicedFor:"Sliced for {{model}}",uploadedBy:"Uploaded By",noPermissionReprint:"You do not have permission to reprint",noFileForReprint:"No 3MF file available — the file could not be downloaded from the printer when the print was recorded",noPermissionEdit:"You do not have permission to edit archives",noPermissionDelete:"You do not have permission to delete archives",reprint:"Reprint",schedulePrint:"Schedule Print",schedule:"Schedule",openInBambuStudio:"Open in Slicer",openInBambuStudioToSlice:"Open in Slicer to slice",slice:"Slice",externalLink:"External Link",makerWorld:"MakerWorld: {{designer}}",viewProject:"View project",noExternalLink:"No external link",preview3d:"3D Preview",download:"Download",edit:"Edit",delete:"Delete"},modal:{deleteArchive:"Delete Archive",deleteConfirm:'Are you sure you want to delete "{{name}}"? This action cannot be undone.',deleteButton:"Delete",removeSource3mf:"Remove Source 3MF",removeSource3mfConfirm:'Are you sure you want to remove the source 3MF file from "{{name}}"? This will delete the original slicer project file.',removeButton:"Remove",removeF3d:"Remove F3D",removeF3dConfirm:'Are you sure you want to remove the Fusion 360 design file from "{{name}}"?',removeTimelapse:"Remove Timelapse",removeTimelapseConfirm:'Are you sure you want to remove the timelapse video from "{{name}}"?',timelapse:"{{name}} - Timelapse",selectTimelapse:"Select Timelapse",selectTimelapseDesc:"No auto-match found. Select the timelapse for this print:",deleteArchives:"Delete Archives",deleteArchivesConfirm:"Are you sure you want to delete {{count}} archive(s)? This action cannot be undone.",deleteCount:"Delete {{count}}"},page:{title:"Archives",printsCount:"{{filtered}} of {{total}} prints",dropFilesHere:"Drop .3mf files here",releaseToUpload:"Release to upload",only3mfSupported:"Only .3mf files are supported",close:"Close",selected:"{{count}} selected",selectAll:"Select All",tags:"Tags",project:"Project",favorite:"Favorite",delete:"Delete",toggledFavorites:"Toggled favorites for {{count}} archive(s)",failedUpdateFavorites:"Failed to update favorites",archivesDeleted:"{{count}} archive(s) deleted",failedDeleteArchives:"Failed to delete archives",photoDeleted:"Photo deleted",failedDeletePhoto:"Failed to delete photo"},list:{name:"Name",printer:"Printer",date:"Date",size:"Size",actions:"Actions",hasTimelapse:"Has timelapse"},log:{date:"Date",printName:"Print Name",printer:"Printer",user:"User",status:"Status",duration:"Duration",filament:"Filament",allPrinters:"All Printers",allUsers:"All Users",allStatuses:"All Statuses",cancelled:"Cancelled",skipped:"Skipped",dateFrom:"From",dateTo:"To",noEntries:"No print log entries found",showing:"Showing {{count}} of {{total}} entries",rowsPerPage:"Rows",page:"Page",prev:"Prev",next:"Next",clearLog:"Clear Log",clearLogTitle:"Clear Print Log",clearLogConfirm:"All print log entries will be permanently deleted. Archives and queue items are not affected. This action cannot be undone. Are you sure?",clearLogButton:"Clear All",cleared:"{{count}} log entries cleared",clearFailed:"Failed to clear print log"}},queue:{title:"Print Queue",subtitle:"Schedule and manage your print jobs",addToQueue:"Add to Queue",print:"Print",reprint:"Re-print",schedulePrint:"Schedule Print",editQueueItem:"Edit Queue Item",printToPrinters:"Print to {{count}} Printers",queueToPrinters:"Queue to {{count}} Printers",queueSelectedPlates:"Queue {{count}} Plates",selectAllPlates:"Select All {{count}} Plates",deselectAll:"Deselect All",printQueued:"Print queued",itemsQueued:"{{count}} items queued",sending:"Sending...",sendingProgress:"Sending {{current}}/{{total}}...",adding:"Adding...",addingProgress:"Adding {{current}}/{{total}}...",savingProgress:"Saving {{current}}/{{total}}...",clearQueue:"Clear Queue",clearHistory:"Clear History",emptyQueue:"Queue is empty",position:"Position",scheduledTime:"Scheduled Time",moveUp:"Move Up",moveDown:"Move Down",startNow:"Start Now",printingInProgress:"Printing in progress...",viewArchive:"View archive",viewInFileManager:"View in File Manager",itemCount:"{{count}} item",itemCount_plural:"{{count}} items",dragToReorder:"Drag to reorder (ASAP only)",reorderHint:"Position only affects ASAP items. Scheduled items run at their set time.",sjf:{label:"SJF",tooltip:"Shortest Job First — scheduler prioritizes shorter prints"},addedBy:"Added by {{name}}",nextInQueue:"Next in queue",clearPlate:"Clear Plate & Start Next",clearPlateSuccess:"Plate cleared — ready for next print",plateReady:"Plate cleared — ready for next print",plateNumber:"Plate {{index}}",quantity:"Quantity",quantityHint:"Creates {{count}} queue items",activeBatches:"Active Batches",batchProgress:"{{completed}} of {{total}} completed",cancelBatch:"Cancel Remaining",batchCancelled:"Remaining batch items cancelled",cancelBatchConfirmTitle:"Cancel Batch",cancelBatchConfirmMessage:"Cancel all remaining pending items in this batch?",batch:"Batch",sections:{currentlyPrinting:"Currently Printing",queued:"Queued",history:"History"},status:{pending:"Pending",waiting:"Waiting",printing:"Printing",paused:"Paused",completed:"Completed",failed:"Failed",skipped:"Skipped",cancelled:"Cancelled"},summary:{printing:"Printing",queued:"Queued",totalTime:"Total Queue Time",totalWeight:"Total Queue Weight",history:"History"},filter:{allPrinters:"All Printers",unassigned:"Unassigned",allStatus:"All Status",allLocations:"All Locations",any:"Any"},sort:{byPosition:"Sort by Position",byName:"Sort by Name",byPrinter:"Sort by Printer",bySchedule:"Sort by Schedule",byDate:"Sort by Date",ascendingOldest:"Ascending (oldest first)",descendingNewest:"Descending (newest first)"},badges:{staged:"Staged",requiresPrevious:"Requires previous success",autoPowerOff:"Auto power off",gcodeInjection:"G-code"},empty:{title:"No prints scheduled",description:'Schedule a print from the Archives page using the "Schedule" option in the context menu, or drag and drop files to get started.'},time:{asap:"ASAP",overdue:"Overdue",now:"Now",lessThanMinute:"In less than a minute",inMinutes:"In {{count}} min",inHours:"In {{count}} hours"},actions:{stopPrint:"Stop Print",startPrint:"Start Print",requeue:"Re-queue"},bulkEdit:{title:"Edit {{count}} Item",title_plural:"Edit {{count}} Items",description:"Only changed settings will be applied to selected items.",printer:"Printer",noChange:"— No change —",queueOptions:"Queue Options",staged:"Staged (manual start)",autoPowerOff:"Auto power off after print",requirePrevious:"Require previous success",printOptions:"Print Options",bedLevelling:"Bed levelling",flowCalibration:"Flow calibration",vibrationCalibration:"Vibration calibration",layerInspection:"First layer inspection",timelapse:"Timelapse",useAms:"Use AMS",applyChanges:"Apply Changes",selectAll:"Select All",deselectAll:"Deselect All",selected:"{{count}} selected",editSelected:"Edit Selected",cancelSelected:"Cancel Selected"},confirm:{cancelTitle:"Cancel Scheduled Print",cancelMessage:'Are you sure you want to cancel "{{name}}"?',stopTitle:"Stop Print",stopMessage:'Are you sure you want to stop the current print "{{name}}"? This will cancel the print job on the printer.',removeTitle:"Remove from History",removeMessage:'Are you sure you want to remove "{{name}}" from the queue history?',clearHistoryTitle:"Clear History",clearHistoryMessage:"Are you sure you want to remove all {{count}} item(s) from the history?",cancelButton:"Cancel Print",stopButton:"Stop Print",thisPrint:"this print",thisItem:"this item"},toast:{cancelled:"Queue item cancelled",cancelFailed:"Failed to cancel item",removed:"Queue item removed",removeFailed:"Failed to remove item",stopped:"Print stopped",stopFailed:"Failed to stop print",released:"Print released to queue",startFailed:"Failed to start print",reorderFailed:"Failed to reorder queue",historyCleared:"Cleared {{count}} history item(s)",clearHistoryFailed:"Failed to clear history",updateFailed:"Failed to update items",bulkCancelled:"Cancelled {{count}} item(s)",bulkCancelFailed:"Failed to cancel items"},timeline:{listView:"List",timelineView:"Timeline",unassigned:"Unassigned",noData:"No scheduled prints for this day",allDoneBy:"All prints estimated done by {{time}}",staged:"Staged",filterAll:"Show All",filterPrinting:"Printing",filterQueued:"Queued",time:{anyMoment:"any moment",minutesLeft:"{{minutes}}m left",hoursLeft:"{{hours}}h left",hoursMinutesLeft:"{{hours}}h {{minutes}}m left"},day:{previous:"Previous day",next:"Next day",today:"Today"}},permissions:{noStopPrint:"You do not have permission to stop prints",noStartPrint:"You do not have permission to start prints",noEdit:"You do not have permission to edit this queue item",noCancel:"You do not have permission to cancel this queue item",noRequeue:"You do not have permission to re-queue items",noRemove:"You do not have permission to remove this queue item",noClearHistory:"You do not have permission to clear all history",noEditItems:"You do not have permission to edit queue items",noCancelItems:"You do not have permission to cancel queue items"}},backgroundDispatch:{unknownFile:"Unknown file",unknownPrinter:"Unknown printer",startingPrints:"Starting prints",progressSummary:"{{complete}}/{{total}} complete • Dispatched: {{dispatched}} • Processing: {{processing}}",expandDetails:"Expand dispatch details",collapseDetails:"Collapse dispatch details",dismissToast:"Dismiss dispatch toast",cancelDispatchJob:"Cancel dispatch job",cancel:"Cancel",cancelling:"Cancelling…",status:{dispatched:"Dispatched",processing:"Processing",completed:"Completed",failed:"Failed",cancelled:"Cancelled"},toast:{cancellingUpload:"Cancelling upload...",cancelled:"Dispatch cancelled",cancelFailed:"Failed to cancel dispatch",completeWithFailures:"Background dispatch complete: {{completed}} succeeded, {{failed}} failed",completeSuccess:"Background dispatch complete: {{completed}} succeeded",printStartedRemaining:"{{completed}} print(s) started, {{remaining}} more sending..."}},stats:{title:"Dashboard",subtitle:"Drag widgets to rearrange. Click the eye icon to hide.",overview:"Overview",totalPrints:"Total Prints",successRate:"Success Rate",totalPrintTime:"Total Print Time",printTime:"Print Time",totalFilament:"Total Filament Used",filamentUsed:"Filament Used",filamentCost:"Filament Cost",totalCost:"Total Cost",energyUsed:"Energy Used",energyCost:"Energy Cost",energyWarmingUpTooltip:"Energy tracking is still collecting hourly snapshots. Date-range totals will become accurate once at least one snapshot exists before the selected range. Early values may undercount.",averagePrintTime:"Average Print Time",printsPerDay:"Prints per Day",byPrinter:"By Printer",printsByPrinter:"Prints by Printer",byMaterial:"By Material",byMonth:"By Month",last7Days:"Last 7 Days",last30Days:"Last 30 Days",last90Days:"Last 90 Days",allTime:"All Time",quickStats:"Quick Stats",printActivity:"Print Activity",filamentTypes:"Filament Types",filamentTrends:"Filament Trends",failureAnalysis:"Failure Analysis",timeAccuracy:"Time Accuracy",successful:"Successful:",failed:"Failed:",perfectEstimate:"100% = perfect estimate",noTimeAccuracyData:"No time accuracy data yet",noFilamentData:"No filament data available",noPrinterData:"No printer data available",noPrintData:"No print data available",noPrintDataLast30Days:"No print data in the last 30 days",failureReasons:"Failure Reasons",topFailureReasons:"Top Failure Reasons",failedPrintsCount:"{{failed}} / {{total}} prints failed",lastWeekRate:"Last week: {{rate}}%",resetLayout:"Reset Layout",recalculateCosts:"Recalculate Costs",recalculateCostsHint:"Recalculate all archive costs using current filament prices",exportStats:"Export Stats",exportAsCsv:"Export as CSV",exportAsExcel:"Export as Excel",hiddenCount:"{{count}} Hidden",exportDownloaded:"Export downloaded",exportFailed:"Export failed",layoutReset:"Layout reset",recalculatedCosts:"Recalculated costs for {{count}} archives",recalculateFailed:"Failed to recalculate costs",loadingStats:"Loading statistics...",noPermissionResetLayout:"You do not have permission to reset layout",noPermissionRecalculate:"You do not have permission to recalculate costs",noPrintDataInRange:"No print data in selected range",periodFilament:"Period Filament",periodCost:"Period Cost",avgPerPrint:"Avg per Print",usageOverTime:"Usage Over Time",filamentByWeight:"Weight",printDuration:"Print Duration",printerUtilization:"Printer Utilization",filamentSuccess:"Success by Material",printHabits:"Print Habits",printTimeOfDay:"Print Time of Day",colorDistribution:"Color Distribution",noColorData:"No color data available",records:"Records",longestPrint:"Longest Print",heaviestPrint:"Heaviest Print",mostExpensivePrint:"Most Expensive",busiestDay:"Busiest Day",successStreak:"Success Streak",streakPrint:"consecutive print",streakPrints:"{{count}} consecutive prints",printerStats:"Printer Stats",hours:"hours",avgPrints:"Avg. prints",noArchiveData:"No print data available",filamentByTime:"Time",avgWeight:"Avg. weight",avgTime:"Avg. time",filamentByPrints:"Prints",timeframe:{today:"Today","this-week":"This Week","this-month":"This Month","last-7":"Last 7 Days","last-30":"Last 30 Days","last-90":"Last 90 Days","this-year":"This Year","all-time":"All Time",custom:"Custom Range",from:"From",to:"To"},allUsers:"All Users",noUser:"No User (System)",filterByUser:"Filter by User"},maintenance:{title:"Maintenance",overview:"Overview",allOk:"All maintenance up to date",dueCount:"{{count}} item due",dueCount_plural:"{{count}} items due",warningCount:"{{count}} warning",warningCount_plural:"{{count}} warnings",totalPrintTime:"Total Print Time",nextMaintenance:"Next Maintenance",nothingDue:"Nothing due",tasks:"Tasks",lastPerformed:"Last performed",interval:"Interval",hoursRemaining:"{{hours}}h remaining",hoursOverdue:"{{hours}}h overdue",markDone:"Mark as Done",performMaintenance:"Perform Maintenance",history:"History",noHistory:"No maintenance history",editPrintHours:"Edit Print Hours",currentHours:"Current Hours",statusTab:"Status",settingsTab:"Settings",overdueCount:"{{count}} overdue",dueSoonCount:"{{count}} due soon",dueSoon:"Due soon",allGood:"All good",overdueBy:"Overdue by {{duration}}",dueIn:"Due in {{duration}}",timeLeft:"{{duration}} left",day:"1 day",days:"{{count}} days",week:"1 week",weeks:"{{count}} weeks",month:"1 month",months:"{{count}} months",year:"1 year",maintenanceTypes:"Maintenance Types",maintenanceTypesDescription:"System types and your custom maintenance tasks",addCustomType:"Add Custom Type",restoreDefaults:"Restore Default Tasks",intervalType:"Interval Type",intervalValue:"Interval ({{type}})",icon:"Icon",documentationLink:"Documentation Link (optional)",assignToPrinters:"Assign to Printers",selectAtLeastOnePrinter:"Select at least one printer",addType:"Add Type",custom:"Custom",printHours:"Print Hours",calendarDays:"Calendar Days",exampleName:"e.g., Replace HEPA Filter",viewDocumentation:"View documentation",timeBasedInterval:"Time-based interval",intervalOverrides:"Interval Overrides",intervalOverridesDescription:"Customize intervals for specific printers",assignedToPrinters:"Assigned to printers:",noPrintersAssigned:"No printers assigned",addPrinterShort:"Add:",printersAssignedClick:"{{count}} printer(s) assigned - click to manage",removeFromPrinter:"Remove from this printer",types:{lubricateCarbonRods:"Lubricate Carbon Rods",lubricateRails:"Lubricate Linear Rails",cleanNozzle:"Clean Nozzle/Hotend",checkBelts:"Check Belt Tension",cleanBuildPlate:"Clean Build Plate",checkExtruder:"Check Extruder Gears",checkCooling:"Check Cooling Fans",generalInspection:"General Inspection",cleanCarbonRods:"Clean Carbon Rods",lubricateSteelRods:"Lubricate Steel Rods",cleanSteelRods:"Clean Steel Rods",cleanLinearRails:"Clean Linear Rails",checkPtfeTube:"Check PTFE Tube",replaceHepaFilter:"Replace HEPA Filter",replaceCarbonFilter:"Replace Carbon Filter",lubricateLeftNozzleRail:"Lubricate Left Nozzle Rail"},maintenanceComplete:"Maintenance marked as complete",typeUpdated:"Maintenance type updated",typeDeleted:"Maintenance type deleted",defaultsRestored:"Restored {{count}} default task(s)",printHoursUpdated:"Print hours updated",printerAssigned:"Printer assigned",printerRemoved:"Printer removed",deleteTypeConfirm:'Delete "{{name}}"?',deleteSystemTypeTitle:"Delete default maintenance task?",deleteSystemTypeMessage:'Are you sure you want to delete the default maintenance task "{{name}}"?',noPermissionUpdate:"You do not have permission to update maintenance items",noPermissionPerform:"You do not have permission to perform maintenance",noPermissionEditTypes:"You do not have permission to edit maintenance types",noPermissionDeleteTypes:"You do not have permission to delete maintenance types",noPermissionEditHours:"You do not have permission to edit print hours",noPermissionRemovePrinter:"You do not have permission to remove printer assignments",noPermissionAssignPrinter:"You do not have permission to assign printers",noPermissionEditIntervals:"You do not have permission to edit intervals",configureSettings:"Configure maintenance types and intervals"},settings:{title:"Settings",general:"General",tabs:{general:"General",smartPlugs:"Smart Plugs",notifications:"Notifications",queue:"Workflow",filament:"Filament",network:"Network",apiKeys:"API Keys",virtualPrinter:"Virtual Printer",spoolbuddy:"SpoolBuddy",failureDetection:"Failure Detection",users:"Authentication",backup:"Backup",emailAuth:"Email Authentication",ldap:"LDAP",twoFa:"Two-Factor Auth",oidc:"SSO / OIDC"},spoolbuddy:{infoTitle:"SpoolBuddy devices",infoBody:"SpoolBuddy kiosks register themselves automatically via heartbeat. Unregister a device here if it is no longer in use or if a stale duplicate was left behind by a daemon crash.",duplicatesTitle:"{{count}} devices registered",duplicatesBody:"Only the first registered device is used by the kiosk UI. If one of these is a stale duplicate from a crash, unregister it — an online device will re-register itself on its next heartbeat.",empty:"No SpoolBuddy devices registered yet.",online:"Online",offline:"Offline",unregister:"Unregister",unregisterSuccess:"Device unregistered",unregisterError:"Failed to unregister device",confirmTitle:"Unregister SpoolBuddy device?",confirmBody:'This will remove "{{hostname}}" ({{deviceId}}) from the database. If the device is online, it will re-register itself on its next heartbeat.',ipAddress:"IP address",firmware:"Firmware",lastSeen:"Last seen",daemonUptime:"Daemon uptime",systemUptime:"System uptime",never:"never",nfc:"NFC",scale:"Scale",cpuTemp:"CPU temp",memory:"Memory",disk:"Disk",update:"Update",updateConfirmTitle:"Update Spoolbuddy daemon?",updateConfirmBody:'Trigger a software update on "{{hostname}}"? The daemon will restart once the update is applied.',restartBrowser:"Restart Browser",restartBrowserConfirmTitle:"Restart kiosk browser?",restartBrowserConfirmBody:'Restart the kiosk browser on "{{hostname}}"? The display will blank briefly.',restartDaemon:"Restart Daemon",restartDaemonConfirmTitle:"Restart Spoolbuddy daemon?",restartDaemonConfirmBody:'Restart the Spoolbuddy daemon on "{{hostname}}"? The device will go offline for a few seconds.',reboot:"Reboot",rebootConfirmTitle:"Reboot device?",rebootConfirmBody:'Reboot "{{hostname}}"? The device will be offline for around a minute.',shutdown:"Shutdown",shutdownConfirmTitle:"Shutdown device?",shutdownConfirmBody:'Shutdown "{{hostname}}"? You will need physical access to power it back on.',commandConfirm:"Confirm",commandQueued:"Command queued",commandError:"Failed to send command"},ldap:{title:"LDAP Authentication",enabledDesc:"LDAP authentication is enabled",disabledDesc:"LDAP authentication is disabled",disabledHint:"Configure and save LDAP settings below, then enable.",enabled:"LDAP authentication enabled",disabled:"LDAP authentication disabled",feature1:"Users can login with LDAP credentials",feature2:"Local admin account remains as fallback",feature3:"LDAP groups are mapped to BamBuddy groups on login",serverConfig:"LDAP Server Configuration",serverUrl:"Server URL",serverUrlHint:"Use ldaps:// for SSL or ldap:// with StartTLS",security:"Security",securityHint:"StartTLS upgrades a plain connection to TLS. LDAPS uses TLS from the start.",bindDn:"Bind DN (Service Account)",bindPassword:"Bind Password",searchBase:"Search Base DN",userFilter:"User Search Filter",userFilterHint:"{username} is replaced with the login username. Use (uid={username}) for OpenLDAP.",autoProvision:"Auto-provision users",autoProvisionHint:"Automatically create a BamBuddy account on first LDAP login",defaultGroup:"Default group",defaultGroupNone:"— None (no fallback) —",defaultGroupHint:"Fallback group assigned when an LDAP user authenticates but is not listed in any mapped LDAP group. Leave empty to leave unmapped users without permissions.",groupMapping:"Group Mapping (JSON)",groupMappingHint:"Map LDAP group DNs to BamBuddy groups. Available groups: ",testConnection:"Test Connection",settingsSaved:"LDAP settings saved",errors:{serverRequired:"LDAP server URL is required",searchBaseRequired:"Search base DN is required",enableAuthFirst:"Enable authentication first",configureLdapFirst:"Save LDAP settings first"}},email:{smtpSettings:"SMTP Configuration",smtpHost:"SMTP Server",smtpPort:"SMTP Port",security:"Security",authentication:"Authentication",username:"Username",password:"Password",fromEmail:"From Email",fromName:"From Name",testConnection:"Test SMTP Connection",testRecipient:"Test Recipient Email",sendTest:"Send Test Email",sending:"Sending...",save:"Save Settings",saving:"Saving...",advancedAuth:"Advanced Authentication",advancedAuthEnabled:"Advanced Authentication is enabled",advancedAuthEnabledDesc:"Email-based user management features are active. New users will receive auto-generated passwords via email, and users can reset their passwords through the forgot password feature.",advancedAuthDisabled:"Advanced Authentication is disabled",advancedAuthDisabledDesc:"Enable advanced authentication to activate email-based features for user management.",enable:"Enable",disable:"Disable",feature1:"Passwords are auto-generated and emailed to new users",feature2:"Users can login with username or email",feature3:"Forgot password feature is available",feature4:"Admins can reset user passwords via email",errors:{requiredFields:"Please fill in all required fields",usernameRequired:"Username is required when authentication is enabled",enterTestEmail:"Please enter a test email address",smtpServerAndEmail:"Please fill in SMTP Server and From Email before testing",usernamePasswordRequired:"Username and Password are required when authentication is enabled",configureSmtpFirst:"Please configure and test SMTP settings first",enableAuthFirst:"Please enable authentication first to use email-based features."},success:{settingsSaved:"SMTP settings saved successfully"},securityOptions:{starttls:"STARTTLS (Port 587)",ssl:"SSL/TLS (Port 465)",none:"None (Port 25)"},authOptions:{enabled:"Enabled",disabled:"Disabled"}},appearance:"Appearance",notifications:"Notifications",smartPlugs:"Smart Plugs",spoolman:"Spoolman",updates:"Updates",language:"Language",languageDescription:"Select your preferred language",theme:"Theme",themeLight:"Light",themeDark:"Dark",themeSystem:"System",defaultView:"Default View",defaultViewDescription:"Page to show when opening the app",checkForUpdates:"Check for Updates",autoUpdate:"Auto Update",currentVersion:"Current Version",latestVersion:"Latest Version",upToDate:"You are up to date",updateAvailable:"Update available",notificationLanguage:"Notification Language",notificationLanguageDescription:"Language for push notifications",bedCooledThreshold:"Bed Cooled Threshold",bedCooledThresholdDescription:"Temperature below which the bed is considered cooled after a print",userNotificationsEnabled:"User Notifications",userNotificationsEnabledDescription:"Enable the user notifications menu and email notifications for print job events. Requires Advanced Authentication.",userNotificationsDisabledHint:"Enable Advanced Authentication to use user notifications.",notificationProviders:"Notification Providers",addProvider:"Add Provider",editProvider:"Edit Provider",providerType:"Provider Type",testNotification:"Test Notification",testSuccess:"Test notification sent successfully",testFailed:"Failed to send test notification",quietHours:"Quiet Hours",quietHoursDescription:"Do not disturb during these hours",quietHoursStart:"Start",quietHoursEnd:"End",events:{title:"Notification Events",printStart:"Print Started",printComplete:"Print Completed",printFailed:"Print Failed",printStopped:"Print Stopped",printProgress:"Progress Milestones",printProgressDescription:"Notify at 25%, 50%, 75%",printerOffline:"Printer Offline",printerError:"Printer Error",filamentLow:"Low Filament",maintenanceDue:"Maintenance Due",maintenanceDueDescription:"Notify when maintenance is needed"},smartPlug:{title:"Smart Plugs",add:"Add Smart Plug",edit:"Edit Smart Plug",name:"Name",ipAddress:"IP Address",linkedPrinter:"Linked Printer",autoOn:"Auto Power On",autoOnDescription:"Turn on when print starts",autoOff:"Auto Power Off",autoOffDescription:"Turn off after print completes",offDelay:"Off Delay",offDelayMinutes:"Minutes after print",offDelayTemp:"When nozzle below temperature",currentState:"Current State",turnOn:"Turn On",turnOff:"Turn Off"},filamentTracking:"Filament Tracking",filamentTrackingDesc:"Choose how to track your filament spools. You can use the built-in inventory or connect an external Spoolman server.",filamentChecks:"Filament checks",disableFilamentWarnings:"Disable filament warnings",disableFilamentWarningsDesc:"Don't show warnings about insufficient filament when printing or queueing",preferLowestFilament:"Prefer lowest remaining filament",preferLowestFilamentDesc:"When multiple spools match, use the one with the least filament remaining",trackingModeBuiltIn:"Built-in Inventory",trackingModeBuiltInDesc:"RFID auto-matching and usage tracking included",trackingModeSpoolmanDesc:"External filament management server",builtInFeatureRfid:"Automatically detects Bambu Lab RFID spools in AMS",builtInFeatureUsage:"Tracks filament consumption per print",builtInFeatureCatalog:"Manage spools, colors, and K-factor profiles",builtInFeatureThirdParty:"Third-party spools can be assigned to inventory spools",amsSyncButton:"Sync Weights from AMS",amsSyncTitle:"Sync Spool Weights from AMS",amsSyncMessage:"This will overwrite all inventory spool weights with the current AMS remain% values from connected printers. Use this to recover from corrupted weight data. Printers must be online.",amsSyncing:"Syncing...",amsSyncSuccess:"{{synced}} spool(s) synced, {{skipped}} skipped",amsSyncError:"Failed to sync weights from AMS",spoolmanUrl:"Spoolman URL",spoolmanUrlHint:"URL of your Spoolman server (e.g., http://localhost:7912)",spoolmanConnected:"Connected",spoolmanDisconnected:"Disconnected",status:"Status",connect:"Connect",disconnect:"Disconnect",howSyncWorks:"How Sync Works",syncInfoRfidOnly:"Only official Bambu Lab spools with RFID are synced",syncInfoAutoCreate:"New spools are auto-created in Spoolman on first sync",syncInfoThirdPartySkipped:"Non-Bambu Lab spools (third-party, refilled) are skipped",linkingExistingSpools:"Linking Existing Spools",linkingExistingSpoolsDesc:'To link existing Spoolman spools to your AMS, hover over an AMS slot and click "Link to Spoolman".',syncMode:"Sync Mode",syncModeAuto:"Automatic",syncModeManual:"Manual Only",syncModeAutoDesc:"AMS data syncs automatically when changes are detected",syncModeManualDesc:"Only sync when manually triggered",syncAmsData:"Sync AMS Data",syncAmsDataDesc:"Manually sync printer AMS data to Spoolman",allPrinters:"All Printers",noDefaultPrinter:"No default (ask each time)",sidebarOrder:"Sidebar order",saveThumbnails:"Save thumbnails",captureFinishPhoto:"Capture finish photo",noPrintersConfigured:"No printers configured",archiveMode:{always:"Always create archive entry",never:"Never create archive entry",ask:"Ask each time"},checkForUpdatesLabel:"Check for updates",checkPrinterFirmware:"Check printer firmware",includeBetaUpdates:"Include beta versions",includeBetaUpdatesDesc:"Notify about beta and prerelease versions when checking for updates",enableRetry:"Enable retry",homeAssistantDescription:"Control smart plugs via Home Assistant",environmentManagedLabel:"(Environment Managed)",autoEnabledViaEnv:"Automatically enabled via environment variables",urlFromEnvReadOnly:"Value set by HA_URL environment variable (read-only)",tokenFromEnvReadOnly:"Value set by HA_TOKEN environment variable (read-only)",mqttConnectedTo:"Connected to",prometheusDescription:"Expose printer data in Prometheus format",noSmartPlugsTitle:"No smart plugs configured",noSmartPlugsDescription:"Add a Tasmota-based smart plug to track energy usage and automate power control.",noProvidersTitle:"No providers configured",noProvidersDescription:"Add a provider to receive alerts.",noTemplatesAvailable:"No templates available. Restart the backend to seed default templates.",apiPermissionView:"View printer status and queue",apiPermissionEdit:"Add and remove items from print queue",apiKeysEmptyTitle:"No API keys",apiKeysEmptyDescription:"Create an API key to integrate with external services.",noUsersFound:"No users found",noGroupsFound:"No groups found",noGroupsAvailable:"No groups available",passwordsDoNotMatch:"Passwords do not match",systemGroupWarning:"System group names cannot be changed",authDisabledTitle:"Authentication is Disabled",authDisabledFeature1:"Require login to access the system",authDisabledFeature2:"Create multiple users with group-based permissions",authDisabledFeature3:"Control access with 50+ granular permissions",userHasCreated:"This user has created:",userItemsQuestion:"What would you like to do with these items?",deleteUserConfirm:"Are you sure you want to delete this user?",actionCannotBeUndone:"This action cannot be undone.",addFirstSmartPlug:"Add Your First Smart Plug",providers:"Providers",log:"Log",testAll:"Test All",testResults:"Test Results",testPassedCount:"{{count}} passed",testFailedCount:"{{count}} failed",messageTemplates:"Message Templates",messageTemplatesDescription:"Customize notification messages for each event.",apiKeys:"API Keys",apiKeysDescription:"Create API keys for external integrations and webhooks.",createKey:"Create Key",apiKeyCreated:"API Key Created Successfully",apiKeyCopyWarning:"Copy this key now - it won't be shown again!",useInApiBrowser:"Use in API Browser",createNewApiKey:"Create New API Key",keyName:"Key Name",keyNamePlaceholder:"e.g., Home Assistant, OctoPrint",readStatus:"Read Status",readStatusDescription:"View printer status and queue",manageQueue:"Manage Queue",manageQueueDescription:"Add and remove items from print queue",controlPrinter:"Control Printer",controlPrinterDescription:"Pause, resume, and stop prints",unnamedKey:"Unnamed Key",lastUsed:"Last used",read:"Read",control:"Control",createFirstKey:"Create Your First Key",webhookEndpoints:"Webhook Endpoints",webhookApiKeyHint:"Use your API key in the X-API-Key header.",webhook:{getAllStatus:"Get all printer status",getSpecificStatus:"Get specific printer status",addToQueue:"Add to print queue",pausePrint:"Pause print",resumePrint:"Resume print",stopPrint:"Stop print"},apiBrowser:"API Browser",apiBrowserDescription:"Explore and test all available API endpoints.",apiKeyForTesting:"API Key for Testing",apiKeyPlaceholder:"Paste your API key here to test authenticated endpoints...",apiKeyHint:"This key will be sent as X-API-Key header with requests.",deleteApiKeyTitle:"Delete API Key",deleteApiKeyMessage:"Are you sure you want to delete this API key? Any integrations using this key will stop working.",deleteKey:"Delete Key",amsDisplayThresholds:"AMS Display Thresholds",amsThresholdsDescription:"Configure color thresholds for AMS humidity and temperature indicators.",humidity:"Humidity",goodGreen:"Good (green)",fairOrange:"Fair (orange)",aboveFairBad:"Above fair threshold shows as red (bad)",fairAlsoDryingThreshold:"This threshold is also used to trigger auto-drying when enabled",temperature:"Temperature",goodBlue:"Good (blue)",aboveFairHot:"Above fair threshold shows as red (hot)",historyRetention:"History Retention",keepSensorHistory:"Keep sensor history for",historyRetentionDescription:"Older humidity and temperature data will be automatically deleted",defaultPrintOptions:"Default Print Options",defaultPrintOptionsDescription:"Set default values for print options when starting new prints. These can be overridden per print in the print dialog.",defaultBedLevelling:"Bed Levelling",defaultBedLevellingDesc:"Auto-level bed before print",defaultFlowCali:"Flow Calibration",defaultFlowCaliDesc:"Calibrate extrusion flow",defaultVibrationCali:"Vibration Calibration",defaultVibrationCaliDesc:"Reduce ringing artifacts",defaultLayerInspect:"First Layer Inspection",defaultLayerInspectDesc:"AI inspection of first layer",defaultTimelapse:"Timelapse",defaultTimelapseDesc:"Record timelapse video",staggeredStart:"Staggered Start",staggeredStartDescription:"Default group size and interval when staggering multi-printer batch starts. Can be overridden per batch in the print modal.",plateClear:"Plate-Clear Confirmation",requirePlateClear:"Require plate-clear confirmation",requirePlateClearDescription:'When enabled, the scheduler waits for per-printer plate-clear confirmation before starting queued prints on printers with finished jobs. Disabling this also hides the plate status badge and the "Mark plate as cleared" button on printer cards.',gcodeInjection:"G-code Injection",gcodeInjectionDescription:'Configure custom G-code to inject at the start and/or end of prints for auto-print systems like Farmloop, SwapMod, AutoClear, and Printflow 3D. Snippets are configured per printer model and applied when "Inject G-code" is enabled on a queue item.',gcodeInjectionNoPrinters:"No printers found. Add printers to configure G-code snippets.",gcodeStartLabel:"Start G-code",gcodeEndLabel:"End G-code",gcodeStartPlaceholder:"G-code prepended before the print starts...",gcodeEndPlaceholder:"G-code appended after the print ends...",staggerGroupSize:"Group size",staggerGroupSizeHelp:"Printers to start simultaneously per group",staggerInterval:"Interval (minutes)",staggerIntervalHelp:"Delay between each group starting",queueDrying:"Queue Auto-Drying",queueDryingDescription:"Automatically dry AMS filament when printer is idle between queued prints. Uses humidity threshold above to trigger drying.",queueDryingEnabled:"Enable auto-drying",queueDryingEnabledDescription:"Start AMS drying automatically when printer is idle and humidity is above threshold",queueDryingBlock:"Wait for drying to complete",queueDryingBlockDescription:"Block the print queue until drying finishes. When off, prints take priority over drying.",ambientDryingEnabled:"Ambient drying",ambientDryingEnabledDescription:"Automatically dry filament on idle printers when humidity exceeds threshold, even without queued prints.",dryingPresets:"Drying Presets",dryingPresetsDescription:"Temperature and duration per filament type. AMS 2 Pro uses lower temps, AMS-HT supports higher temps.",dryingFilament:"Filament",printModal:"Print Modal",expandCustomMapping:"Expand custom mapping by default",expandCustomMappingDescription:"When printing to multiple printers, show per-printer AMS mapping expanded",authentication:"Authentication",authEnabledDescription:"Your instance is secured with user authentication",authDisabledDescription:"Enable to require login and manage user access",authDisabledMessage:"Enable authentication to create user accounts, manage permissions, and secure your Bambuddy instance.",enableAuthentication:"Enable Authentication",currentUser:"Current User",changePassword:"Change Password",admin:"Admin",users:"Users",addUser:"Add User",groups:"Groups",addGroup:"Add Group",system:"System",noDescription:"No description",userCount:"{{count}} users",permissionCount:"{{count}} permissions",createUser:"Create User",username:"Username",enterUsername:"Enter username",password:"Password",enterPassword:"Enter password (min 6 characters)",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm password",viewReleaseOnGitHub:"View release on GitHub",turnAllPlugsOn:"Turn all plugs on",turnAllPlugsOff:"Turn all plugs off",clearNotificationLogs:"Clear Notification Logs",clearLogsMessage:"This will permanently delete all notification logs older than 30 days. This action cannot be undone.",clearLogs:"Clear Logs",resetUiPreferences:"Reset UI Preferences",resetUiPreferencesMessage:"This will reset all UI preferences to defaults: sidebar order, theme, dashboard layout, view modes, and sorting preferences. Your printers, archives, and server settings will NOT be affected. The page will reload after clearing.",resetPreferences:"Reset Preferences",deleteGroupTitle:"Delete Group",deleteGroupMessage:"Are you sure you want to delete this group? Users in this group will lose these permissions.",deleteGroup:"Delete Group",disableAuthenticationTitle:"Disable Authentication",disableAuthenticationMessage:"Are you sure you want to disable authentication? This will make your Bambuddy instance accessible without login. All users will remain in the database but authentication will be disabled.",disableAuthentication:"Disable Authentication",configureBambuddy:"Configure Bambuddy",systemDefault:"System Default",archiveSettings:"Archive Settings",newWindow:"New Window",embeddedOverlay:"Embedded Overlay",preferredSlicer:"Preferred Slicer",preferredSlicerDescription:"Choose which slicer application to open files with",externalCameras:"External Cameras",costTracking:"Cost Tracking",printsOnly:"Prints Only",totalConsumption:"Total Consumption",dataManagement:"Data Management",storageUsage:"Storage Usage",storageUsageDescription:"Breakdown of data usage by category",storageUsageTotal:"Total",storageUsageErrors:"Errors",storageUsageOtherBreakdown:"Other (includes static assets, scripts, and configuration files)",storageUsageSystem:"System",storageUsageData:"Data",storageUsageUnavailable:"Storage usage information unavailable",clearNotificationLogsDescription:"Delete notification logs older than 30 days",resetUiPreferencesDescription:"Reset sidebar order, theme, view modes, and layout preferences. Printers, archives, and settings are not affected.",enableHomeAssistant:"Enable Home Assistant",enableMqtt:"Enable MQTT",useTls:"Use TLS",enableMetricsEndpoint:"Enable Metrics Endpoint",availableMetrics:"Available Metrics",editUser:"Edit User",deleteUserTitle:"Delete User",groupName:"Group Name",leaveEmptyForAnonymous:"Leave empty for anonymous",leaveEmptyForNoAuth:"Leave empty for no authentication",enterNewPassword:"Enter new password",confirmNewPassword:"Confirm new password",enterGroupName:"Enter group name",enterDescriptionOptional:"Enter description (optional)",enterCurrentPassword:"Enter current password",enterNewPasswordMin6:"Enter new password (min 6 characters)",toast:{keyCopied:"Key copied to clipboard",copyFailed:"Failed to copy key",keyAddedToBrowser:"Key added to API Browser",clearLogsFailed:"Failed to clear logs",uiPreferencesReset:"UI preferences reset. Refreshing...",authDisabled:"Authentication disabled successfully",authDisableFailed:"Failed to disable authentication",apiKeyCreated:"API key created",apiKeyDeleted:"API key deleted",userCreated:"User created successfully",userUpdated:"User updated successfully",userDeleted:"User deleted successfully",groupCreated:"Group created successfully",groupUpdated:"Group updated successfully",groupDeleted:"Group deleted successfully",fillRequiredFields:"Please fill in all required fields",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters",enterGroupName:"Please enter a group name",settingsSaved:"Settings saved",cameraSettingsSaved:"Camera settings saved",enterCameraUrl:"Please enter a camera URL",passwordChanged:"Password changed successfully",connectionFailed:"Connection failed",testFailed:"Test failed",cameraConnected:"Camera connected{{resolution}}"},testConnection:"Test Connection",catalog:{spoolCatalog:"Spool Catalog",spoolCatalogDescription:"Empty spool weights by brand/type. Used for automatic weight lookup when adding spools.",searchCatalog:"Search catalog...",addNewEntry:"Add New Entry",namePlaceholder:"Name (e.g., Bambu Lab - Plastic)",weight:"Weight",type:"Type",default:"Default",custom:"Custom",noMatch:"No entries match your search",empty:"No entries in catalog",deleteEntry:"Delete Entry",deleteConfirm:'Are you sure you want to delete "{{name}}"?',resetCatalog:"Reset Catalog",resetConfirm:"Reset catalog to defaults? This will remove all custom entries.",loadFailed:"Failed to load spool catalog",nameWeightRequired:"Name and weight are required",entryAdded:"Entry added",addFailed:"Failed to add entry",entryUpdated:"Entry updated",updateFailed:"Failed to update entry",entryDeleted:"Entry deleted",deleteFailed:"Failed to delete entry",resetSuccess:"Catalog reset to defaults",resetFailed:"Failed to reset catalog",exported:"Exported {{count}} entries",imported:"Imported {{added}} entries ({{skipped}} skipped)",importFailed:"Failed to import: invalid JSON format",exportTooltip:"Export catalog to JSON",importTooltip:"Import catalog from JSON",resetTooltip:"Reset to defaults",selectedCount:"{{count}} selected",deleteSelected:"Delete Selected",bulkDeleteConfirm:"Are you sure you want to delete {{count}} entries?",bulkDeleted:"Deleted {{count}} entries",bulkDeleteFailed:"Failed to delete entries"},colorCatalog:{title:"Color Catalog",description:"Filament colors by manufacturer/material. Used for automatic color lookup when adding spools.",searchColors:"Search colors...",allManufacturers:"All manufacturers",addNewColor:"Add New Color",manufacturer:"Manufacturer",colorName:"Color Name",hex:"Hex",materialOptional:"Material (optional)",showing:"Showing {{filtered}} of {{total}} colors",noMatch:"No colors match your search",empty:"No colors in catalog",deleteColor:"Delete Color",deleteConfirm:'Are you sure you want to delete "{{name}}"?',resetCatalog:"Reset Color Catalog",resetConfirm:"Reset catalog to defaults? This will remove all custom colors.",sync:"Sync",starting:"Starting...",syncTooltip:"Sync from FilamentColors.xyz (2000+ colors, may take a minute)",loadFailed:"Failed to load color catalog",fieldsRequired:"Manufacturer, color name, and hex color are required",colorAdded:"Color added",addFailed:"Failed to add color",colorUpdated:"Color updated",updateFailed:"Failed to update color",colorDeleted:"Color deleted",deleteFailed:"Failed to delete color",resetSuccess:"Color catalog reset to defaults",resetFailed:"Failed to reset catalog",syncUpToDate:"Already up to date ({{count}} colors checked)",syncComplete:"Added {{added}} new colors ({{skipped}} already existed)",syncError:"Sync error",syncFailed:"Failed to sync from FilamentColors.xyz",exported:"Exported {{count}} colors",imported:"Imported {{added}} colors ({{skipped}} skipped)",importFailed:"Failed to import: invalid JSON format",selectedCount:"{{count}} selected",deleteSelected:"Delete Selected",bulkDeleteConfirm:"Are you sure you want to delete {{count}} colors?",bulkDeleted:"Deleted {{count}} colors",bulkDeleteFailed:"Failed to delete colors"},dateFormat:"Date Format",dateFormatUs:"US (MM/DD/YYYY)",dateFormatEu:"EU (DD/MM/YYYY)",dateFormatIso:"ISO (YYYY-MM-DD)",timeFormat:"Time Format",timeFormat12:"12-hour (3:30 PM)",timeFormat24:"24-hour (15:30)",defaultPrinter:"Default Printer",defaultPrinterDescription:"Pre-select this printer for uploads, reprints, and other operations.",slicerBambuStudio:"Bambu Studio",slicerOrcaSlicer:"OrcaSlicer",sidebarOrderDescription:"Drag items in the sidebar to reorder. Reset to default order here.",setDefault:"Set Default",sidebarOrderSetDefaultHint:"Set default applies the current menu order to users who haven't customized theirs.",sidebarDefaultSet:"Default menu order has been set.",sidebarDefaultCleared:"Default menu order cleared.",sidebarDefaultFailed:"Failed to set default menu order.",reset:"Reset",darkMode:"Dark Mode",lightMode:"Light Mode",active:"(active)",background:"Background",accent:"Accent",style:"Style",bgNeutral:"Neutral",bgWarm:"Warm",bgCool:"Cool",bgOled:"OLED Black",bgSlate:"Slate Blue",bgForest:"Forest Green",accentGreen:"Green",accentTeal:"Teal",accentBlue:"Blue",accentOrange:"Orange",accentPurple:"Purple",accentRed:"Red",styleClassic:"Classic",styleGlow:"Glow",styleVibrant:"Vibrant",themeToggleHint:"Toggle between dark and light mode using the sun/moon icon in the sidebar.",autoArchivePrints:"Auto-archive prints",autoArchiveDescription:"Automatically save 3MF files when prints complete",saveThumbnailsDescription:"Extract and save preview images from 3MF files",captureFinishPhotoDescription:"Take a photo from printer camera when print completes",ffmpegNotInstalled:"ffmpeg not installed",ffmpegRequired:"Camera capture requires ffmpeg. Install it via brew install ffmpeg (macOS) or apt install ffmpeg (Linux).",camera:"Camera",cameraViewMode:"Camera View Mode",cameraOverlayDescription:"Camera opens in a resizable overlay on the main screen",cameraWindowDescription:"Camera opens in a separate browser window",externalCamerasDescription:"Configure external cameras to replace the built-in printer camera. Supports MJPEG streams, RTSP, HTTP snapshots, and USB cameras (V4L2). When enabled, the external camera is used for live view and finish photos.",cameraPlaceholderUsb:"Device path (/dev/video0)",cameraPlaceholderUrl:"Camera URL (rtsp://... or http://...)",cameraTypeMjpeg:"MJPEG Stream",cameraTypeRtsp:"RTSP Stream",cameraTypeSnapshot:"HTTP Snapshot",cameraTypeUsb:"USB Camera (V4L2)",cameraRotation:"Rotation",test:"Test",connected:"Connected",disconnected:"Disconnected",currency:"Currency",defaultFilamentCost:"Default filament cost (per kg)",electricityCost:"Electricity cost per kWh",energyDisplayMode:"Energy display mode",energyModePrintDescription:"Dashboard shows sum of energy used during prints",energyModeTotalDescription:"Dashboard shows lifetime energy from smart plugs",fileManager:"File Manager",createArchiveEntry:"Create Archive Entry When Printing",createArchiveEntryDescription:"When printing from File Manager, optionally create an archive entry",lowDiskSpaceWarning:"Low Disk Space Warning",lowDiskSpaceDescription:"Show warning when free disk space falls below this threshold",printerFirmware:"Printer Firmware",checkFirmwareDescription:"Check for printer firmware updates from Bambu Lab",bambuddySoftware:"Bambuddy Software",autoCheckDescription:"Automatically check for new versions on startup",checkNow:"Check now",updateAvailableVersion:"Update available: v{{version}}",releaseNotes:"Release Notes",updateViaDocker:"Update via Docker Compose:",installUpdate:"Install Update",latestVersionRunning:"You're running the latest version",failedToCheckUpdates:"Failed to check for updates: {{error}}",backupRestore:"Backup & Restore",backupRestoreDescription:"Export/import settings and configure GitHub backup",goToBackup:"Go to Backup",externalUrl:"External URL",externalUrlDescription:"The external URL where Bambuddy is accessible. Used for notification images and external integrations.",bambuddyUrl:"Bambuddy URL",externalUrlHint:"Include protocol and port (e.g., http://192.168.1.100:8000)",ftpRetry:"FTP Retry",ftpRetryDescription:"Retry FTP operations when printer WiFi is unreliable. Applies to 3MF downloads, print uploads, timelapse downloads, and firmware updates.",autoRetryDescription:"Automatically retry failed FTP operations",retryAttempts:"Retry attempts",retryDelay:"Retry delay",connectionTimeout:"Connection timeout",time_one:"{{count}} time",time_other:"{{count}} times",second_one:"{{count}} second",second_other:"{{count}} seconds",nSeconds:"{{count}} seconds",increaseForWeakWifi:"Increase for printers with weak WiFi",homeAssistant:"Home Assistant",homeAssistantFullDescription:"Connect to Home Assistant to control smart plugs via HA's REST API. Supports switch, light, input_boolean, and script entities.",homeAssistantUrl:"Home Assistant URL",longLivedAccessToken:"Long-Lived Access Token",haTokenHint:"Create a token in HA: Profile → Long-Lived Access Tokens → Create Token",connectionSuccessful:"Connection Successful",connectionFailed:"Connection Failed",haConnectionSuccess:"Successfully connected to Home Assistant.",haConnectionFailed:"Failed to connect to Home Assistant.",mqttPublishing:"MQTT Publishing",mqttDescription:"Publish BamBuddy events to an external MQTT broker for integration with Node-RED, Home Assistant, and other automation systems.",mqttEnableDescription:"Publish events to external MQTT broker",brokerHostname:"Broker hostname",port:"Port",usernameOptional:"Username (optional)",passwordOptional:"Password (optional)",topicPrefix:"Topic prefix",topicPrefixHint:"Topics will be: {{prefix}}/printers//status, etc.",prometheusMetrics:"Prometheus Metrics",prometheusEndpointDescription:"Expose printer metrics at /api/v1/metrics for Prometheus/Grafana monitoring.",bearerTokenOptional:"Bearer Token (optional)",bearerTokenHint:"If set, requests must include Authorization: Bearer ",metricsConnectionStatus:"Connection status",metricsPrinterState:"Printer state (idle/printing/etc)",metricsPrintProgress:"Print progress 0-100%",metricsBedTemp:"Bed temperature",metricsNozzleTemp:"Nozzle temperature",metricsPrintsTotal:"Total prints by result",metricsMore:"...and more (layers, fans, queue, filament usage)",smartPlugsDescription:"Connect smart plugs (Tasmota or Home Assistant) to automate power control and track energy usage for your printers.",allOn:"All On",allOff:"All Off",addSmartPlug:"Add Smart Plug",energySummary:"Energy Summary",currentPower:"Current Power",plugsOnline:"{{reachable}}/{{total}} plugs online",today:"Today",yesterday:"Yesterday",total:"Total",enablePlugsForSummary:"Enable plugs to see energy summary",addNotificationProvider:"Add",systemBadge:"(System)",creating:"Creating...",changing:"Changing...",deleteUserAndItems:"Delete user AND their items",deleteUserKeepItems:"Delete user, keep items (become ownerless)",ok:"OK",twoFa:{totpTitle:"Authenticator App (TOTP)",totpDesc:"Use an authenticator app like Google Authenticator, Aegis or Authy.",emailOtpTitle:"Email OTP",emailOtpDesc:"Send a one-time code to {{email}} when you log in.",emailOtpNoEmail:"Add an email address to your account to enable this method.",addEmailFirst:"Your account has no email address. Ask an admin to add one before enabling Email OTP.",setupTotp:"Set up Authenticator App",setupAuthApp:"Set up Authenticator App",setupInstructions:"Scan the QR code below with your authenticator app, then confirm with a code.",manualEntry:"Can't scan? Enter this secret manually:",scannedContinue:"I've scanned the code — continue",enterCodeToConfirm:"Enter the 6-digit code from your authenticator app to confirm setup.",activate:"Activate",disableTotp:"Disable Authenticator",disableConfirmHint:"Enter a valid TOTP code or a backup code to disable the authenticator.",totpDisabled:"Authenticator app disabled.",emailOtpEnabled:"Email OTP enabled.",emailOtpDisabled:"Email OTP disabled.",smtpRequired:"Please configure and test SMTP settings first.",invalidCode:"Invalid code. Please try again.",enableEmailOtp:"Enable Email OTP",disableEmailOtp:"Disable Email OTP",emailSetupEnterCode:"A verification code has been sent to your email address. Enter it below to confirm you own this inbox.",verifyAndEnable:"Verify & Enable",emailDisablePasswordHint:"Enter your account password to confirm disabling email OTP.",passwordPlaceholder:"Enter your password",backupCodesTitle:"Save your backup codes",backupCodesWarning:"Save these codes somewhere safe. Each code can only be used once and they will not be shown again.",backupCodesRemaining:"{{count}} backup codes remaining",savedCodes:"I've saved my codes",regenBackup:"Regenerate Backup Codes",regenBackupHint:"Enter your current TOTP code to generate 10 new backup codes. All existing backup codes will be invalidated.",newBackupCodes:"New backup codes",linkedAccounts:"Linked SSO Accounts",linkedAccountsDesc:"These external identity providers are linked to your account.",oidcUnlinked:"Account unlinked."},oidc:{title:"SSO / OIDC Providers",desc:"Configure OpenID Connect providers to allow single sign-on via external identity providers.",addProvider:"Add Provider",newProvider:"New Provider",empty:"No OIDC providers configured yet.",created:"Provider created.",updated:"Provider updated.",deleted:"Provider deleted.",deleteTitle:"Delete Provider",deleteMessage:'Delete "{{name}}"? All linked user accounts will be disconnected.',form:{name:"Display Name",issuerUrl:"Issuer URL",clientId:"Client ID",clientSecret:"Client Secret",scopes:"Scopes",iconUrl:"Icon URL (optional)",enabled:"Enabled",autoCreate:"Auto-create users",autoCreateDesc:"Automatically create a local account on first login.",autoLink:"Auto-link existing accounts",autoLinkDesc:"Link existing local accounts by matching email on first login.",secretHint:"leave blank to keep current",secretPlaceholder:"new secret"}}},notification:{printStarted:{title:"Print Started",body:"{{printer}}: {{filename}} has started printing"},printCompleted:{title:"Print Completed",body:"{{printer}}: {{filename}} completed successfully"},printFailed:{title:"Print Failed",body:"{{printer}}: {{filename}} has failed"},printStopped:{title:"Print Stopped",body:"{{printer}}: {{filename}} was stopped"},printProgress:{title:"Print Progress",body:"{{printer}}: {{filename}} is {{percent}}% complete"},printerOffline:{title:"Printer Offline",body:"{{printer}} is offline"},printerError:{title:"Printer Error",body:"{{printer}}: {{error}}"},filamentLow:{title:"Low Filament",body:"{{printer}}: Filament is running low"},maintenanceDue:{title:"Maintenance Due",body:"{{printer}}: {{items}} need attention"}},errors:{generic:"Something went wrong",networkError:"Network error. Please check your connection.",notFound:"Not found",unauthorized:"Unauthorized",serverError:"Server error",validationError:"Please check your input",printerConnectionFailed:"Failed to connect to printer",saveFailed:"Failed to save changes",deleteFailed:"Failed to delete",loadFailed:"Failed to load data"},hmsErrors:{title:"Errors - {{name}}",noErrors:"No errors",viewOnWiki:"View on Bambu Lab Wiki",clearInstructions:"Clear errors on the printer to dismiss them here.",clearErrors:"Clear Errors",clearSuccess:"HMS errors cleared",clearFailed:"Failed to clear HMS errors"},mqttDebug:{title:"MQTT Debug Log",searchPlaceholder:"Search topic or payload...",noMessages:"No messages logged yet",startLoggingHint:'Click "Start Logging" to begin capturing MQTT messages',noMessagesMatch:"No messages match your filter",adjustFilterHint:"Try adjusting your search or filter criteria",incoming:"Incoming",outgoing:"Outgoing",loggingStopped:"Logging stopped",loggingActive:"Logging active - messages will auto-refresh",startLogging:"Start Logging",stopLogging:"Stop Logging",clearLog:"Clear Log",topic:"Topic",timestamp:"Timestamp",direction:"Direction",all:"All"},printerFiles:{title:"File Manager",storageUsed:"Used:",storageFree:"Free:",filterPlaceholder:"Filter files...",deleteButton:"Delete",deleteFiles:"Delete {{count}} Files",deleteFileConfirm:'Delete "{{name}}"? This cannot be undone.',deleteFilesConfirm:"Delete {{count}} selected files? This cannot be undone.",noFiles:"No files on printer",loadingFiles:"Loading files...",failedToLoad:"Failed to load files",toast:{filesDeleted:"Deleted {{count}} file(s)",deleteFailed:"Delete failed: {{error}}"}},confirm:{delete:"Are you sure you want to delete this?",unsavedChanges:"You have unsaved changes. Are you sure you want to leave?",clearQueue:"Are you sure you want to clear the queue?"},login:{title:"Bambuddy Login",subtitle:"Sign in to your account",username:"Username",usernamePlaceholder:"Enter your username",usernameOrEmail:"Username or Email",usernameOrEmailPlaceholder:"Username or @ Email",password:"Password",passwordPlaceholder:"Enter your password",signIn:"Sign in",signingIn:"Logging in...",forgotPassword:"Forgot your password?",loginSuccess:"Logged in successfully",loginFailed:"Login failed",enterCredentials:"Please enter username and password",enterEmail:"Please enter your email address",oidcLoginFailed:"OIDC login failed",oidcErrors:{providerError:"The identity provider returned an error",missingParameters:"OIDC callback is missing required parameters",invalidState:"OIDC state is invalid or has already been used",stateExpired:"OIDC login session expired — please try again",providerNotFound:"OIDC provider not found",discoveryFailed:"Failed to fetch OIDC discovery document",invalidDiscovery:"OIDC discovery document is invalid",networkError:"Network error during OIDC token exchange",badResponse:"Unexpected response during OIDC token exchange",noIdToken:"OIDC provider did not return an ID token",validationFailed:"OIDC token validation failed",nonceMismatch:"OIDC nonce mismatch — possible replay attack",missingSubClaim:"OIDC token is missing the sub claim",noLinkedAccount:"No local account is linked to this OIDC identity",accountInactive:"Your account is inactive",userResolutionFailed:"Failed to resolve your account",internalError:"An internal error occurred during OIDC login",tokenExchangeFailed:"OIDC token exchange failed"},forgotPasswordTitle:"Forgot Password",forgotPasswordMessage:"If you've forgotten your password, please contact your system administrator to reset it.",forgotPasswordEmailMessage:"Enter your email address and we'll send you a new password.",emailAddress:"Email Address",emailPlaceholder:"your.email@example.com",cancel:"Cancel",sending:"Sending...",sendResetEmail:"Send Reset Email",howToReset:"How to reset your password:",resetStep1:"Contact your Bambuddy administrator",resetStep2:"Ask them to reset your password in User Management",resetStep3:"They can set a new temporary password for you",resetStep4:"Log in with the new password and change it in Settings",gotIt:"Got it",resetPassword:{title:"Set New Password",subtitle:"Enter and confirm your new password below.",newPassword:"New Password",newPasswordPlaceholder:"At least 8 characters",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Repeat new password",saving:"Saving…",submit:"Set New Password",backToLogin:"Back to login",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 8 characters",resetFailed:"Password reset failed. The link may have expired."},twoFA:{title:"Two-Factor Authentication",subtitle:"Your account is protected with 2FA. Enter the verification code below.",methodAuthenticator:"Authenticator App",methodEmail:"Email Code",methodBackup:"Backup Code",instructionsTotp:"Open your authenticator app and enter the 6-digit code for Bambuddy.",instructionsEmail:"A 6-digit code has been sent to your email address. It expires in 10 minutes.",instructionsEmailNotSent:"Click the button below to receive a verification code via email.",instructionsBackup:"Enter one of your 8-character backup recovery codes. Each code can only be used once.",sendCodeButton:"Send Code via Email",sendingCode:"Sending...",resendCode:"Resend code",codeLabel:"Verification Code",backupCodeLabel:"Backup Code",codePlaceholder:"000000",backupCodePlaceholder:"XXXXXXXX",verifyButton:"Verify",verifyingButton:"Verifying...",backToLogin:"← Back to login",orContinueWith:"or continue with",signInWith:"Sign in with {{provider}}",enterCode:"Please enter the verification code",sendCodeFailed:"Failed to send verification code",invalidCode:"Invalid code. Please try again."}},setup:{title:"Bambuddy Setup",subtitle:"Configure authentication for your Bambuddy instance",enableAuth:"Enable Authentication",adminAccount:"Admin Account",adminAccountDesc:"If admin users already exist, authentication will be enabled using the existing admin accounts. Leave the fields below empty to use existing admins, or enter new credentials to create a new admin user.",adminUsername:"Admin Username",adminPassword:"Admin Password",optionalIfAdminExists:"(optional if admin users exist)",adminUsernamePlaceholder:"Enter admin username (optional)",adminPasswordPlaceholder:"Enter admin password (optional)",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm admin password",settingUp:"Setting up...",completeSetup:"Complete Setup",toast:{authEnabledAdminCreated:"Authentication enabled and admin user created",authEnabledExistingAdmins:"Authentication enabled using existing admin users",setupCompleted:"Setup completed",enterBothCredentials:"Please enter both admin username and password, or leave both empty to use existing admin users",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters"}},changePassword:{title:"Change Password",currentPassword:"Current Password",currentPasswordPlaceholder:"Enter current password",newPassword:"New Password",newPasswordPlaceholder:"Enter new password (min 6 characters)",confirmPassword:"Confirm New Password",confirmPasswordPlaceholder:"Confirm new password",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters",changing:"Changing...",success:"Password changed successfully",failed:"Failed to change password"},plateAlert:{title:"Print Paused!",message:"Objects detected on build plate. The print has been automatically paused. Please clear the plate and resume the print.",understand:"I Understand"},camera:{title:"Camera View",invalidPrinterId:"Invalid printer ID",live:"Live",snapshot:"Snapshot",restartStream:"Restart stream",refreshSnapshot:"Refresh snapshot",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",connectingToCamera:"Connecting to camera...",capturingSnapshot:"Capturing snapshot...",connectionLost:"Connection lost",connectionFailed:"Camera connection failed",reconnecting:"Reconnecting in {{countdown}}s... (attempt {{attempt}}/{{max}})",reconnectNow:"Reconnect now",cameraUnavailable:"Camera unavailable",cameraUnavailableDesc:"Make sure the printer is powered on and connected.",noCamera:"No camera available",retry:"Retry",cameraStream:"Camera stream",zoomOut:"Zoom out",zoomIn:"Zoom in",resetZoom:"Reset zoom",recording:"Recording",startRecording:"Start Recording",stopRecording:"Stop Recording",chamberLight:"Toggle chamber light"},groups:{title:"Group Management",subtitle:"Manage permission groups for access control",backToSettings:"Back to Settings",createGroup:"Create Group",noPermission:"You do not have permission to access this page.",system:"System",noDescription:"No description",usersCount:"{{count}} users",permissionsCount:"{{count}} permissions",edit:"Edit",delete:"Delete",toast:{created:"Group created successfully",updated:"Group updated successfully",deleted:"Group deleted successfully",enterGroupName:"Please enter a group name"},modal:{editGroup:"Edit Group",createGroup:"Create Group",cancel:"Cancel",saving:"Saving...",creating:"Creating...",saveChanges:"Save Changes"},form:{groupName:"Group Name",groupNamePlaceholder:"Enter group name",systemGroupWarning:"System group names cannot be changed",description:"Description",descriptionPlaceholder:"Enter description (optional)",permissions:"Permissions ({{count}} selected)"},deleteModal:{title:"Delete Group",message:"Are you sure you want to delete this group? Users in this group will lose these permissions.",confirm:"Delete Group"},editor:{title:"Edit Group",createTitle:"Create Group",search:"Search permissions...",selectAll:"Select All",clearAll:"Clear All",permissionsSelected:"{{count}} selected",noResults:"No permissions match your search"}},users:{title:"User Management",subtitle:"Manage users and their access to your Bambuddy instance",backToSettings:"Back to Settings",createUser:"Create User",noPermission:"You do not have permission to access this page.",admin:"Admin",noGroups:"No groups",active:"Active",inactive:"Inactive",edit:"Edit",delete:"Delete",system:"System",noGroupsAvailable:"No groups available",table:{username:"Username",groups:"Groups",status:"Status",actions:"Actions"},toast:{created:"User created successfully",updated:"User updated successfully",deleted:"User deleted successfully",fillRequired:"Please fill in all required fields",passwordsDoNotMatch:"Passwords do not match",passwordTooShort:"Password must be at least 6 characters"},modal:{createUser:"Create User",editUser:"Edit User",cancel:"Cancel",creating:"Creating...",saving:"Saving...",saveChanges:"Save Changes",advancedAuthSubtitle:"with Advanced Authentication"},form:{username:"Username",usernamePlaceholder:"Enter username",email:"Email",emailPlaceholder:"user@example.com",password:"Password",passwordPlaceholder:"Enter password",confirmPassword:"Confirm Password",confirmPasswordPlaceholder:"Confirm password",newPasswordPlaceholder:"Enter new password",confirmNewPasswordPlaceholder:"Confirm new password",leaveBlankToKeep:"leave blank to keep current",groups:"Groups",optional:"optional",autoGeneratedPassword:"A secure password will be automatically generated and emailed to the user.",passwordManagedByAdvancedAuth:'Password is managed by Advanced Authentication. Use "Reset Password" to send a new password to the user via email.',resetPassword:"Reset Password",resettingPassword:"Resetting Password..."},deleteModal:{title:"Delete User",message:"Are you sure you want to delete this user? This action cannot be undone.",confirm:"Delete User"}},streamOverlay:{title:"Stream Overlay",invalidPrinterId:"Invalid printer ID",cameraStream:"Camera stream",progress:"Progress",eta:"ETA",printerIdle:"Printer is idle",printerOffline:"Printer offline",status:{printing:"Printing",paused:"Paused",finished:"Finished",failed:"Failed",idle:"Idle",unknown:"Unknown"}},profiles:{title:"Profiles",subtitle:"Manage your slicer presets and pressure advance calibrations",tabs:{cloud:"Cloud Profiles",local:"Local Profiles",kprofiles:"K-Profiles"},localProfiles:{title:"Local Profiles",subtitle:"Import and manage slicer presets from OrcaSlicer",import:"Import Profiles",importDesc:"Drop .bbscfg, .bbsflmt, .orca_filament, .zip, or .json files here",importing:"Importing...",search:"Search local presets...",noPresets:"No local presets yet",badge:"Local",edit:"Edit",delete:"Delete",cancel:"Cancel",deleteConfirmTitle:"Delete Preset",deleteConfirm:"Are you sure you want to delete this preset? This cannot be undone.",source:"Source",inheritsFrom:"Inherits",filamentType:"Type",vendor:"Vendor",compatiblePrinters:"Printers",nozzleTemp:"Nozzle Temp",cost:"Cost",density:"Density",pressureAdvance:"Pressure Advance",filament:"Filament",process:"Process",printer:"Printer",toast:{importSuccess:"{{count}} preset(s) imported",importSkipped:"{{count}} preset(s) skipped (duplicates)",importError:"{{count}} error(s) during import",deleted:"Preset deleted",updated:"Preset updated"}},connectedAs:"Connected as",logout:"Logout",noLogoutPermission:"You do not have permission to logout",failedToLoad:"Failed to load profiles",retry:"Retry",time:{justNow:"Just now",minsAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",daysAgo:"{{count}}d ago"},toast:{loggedOut:"Logged out"},login:{title:"Connect to Bambu Cloud",subtitle:"Sync your slicer presets across devices",email:"Email",password:"Password",region:"Region",regionGlobal:"Global",regionChina:"China",verificationCode:"Verification Code",totpCode:"Authenticator Code",checkEmail:"Check your email ({{email}}) for a 6-digit code",enterTotpHint:"Enter the 6-digit code from your authenticator app",accessToken:"Access Token",accessTokenHint:"Paste your Bambu Lab access token (from Bambu Studio)",back:"Back",loginButton:"Login",verifyButton:"Verify",setTokenButton:"Set Token",useToken:"Use access token instead",useEmail:"Login with email instead",toast:{loggedIn:"Logged in successfully",codeSent:"Verification code sent to your email",enterTotp:"Enter code from your authenticator app",tokenSet:"Token set successfully"}},presets:{myPreset:"My preset (editable)",duplicate:"Duplicate",editable:"Editable",failedToLoadDetails:"Failed to load preset details",deleteConfirm:"Delete this preset?",deleteWarning:'This will permanently delete "{{name}}" from Bambu Cloud. This cannot be undone.',noDuplicatePermission:"You do not have permission to duplicate presets",noEditPermission:"You do not have permission to edit presets",noDeletePermission:"You do not have permission to delete presets",types:{filament:"Filament preset",printer:"Printer preset",process:"Process preset"},toast:{deleted:"Preset deleted",created:"Preset created",updated:"Preset updated",duplicated:"Preset duplicated",fieldAdded:'Field "{{key}}" added',exported:"Preset exported"},baseLabel:"Base: {{name}}",currentLabel:"Current: {{name}}",newPreset:"New Preset",editPreset:"Edit Preset",duplicatePreset:"Duplicate Preset",createNewPreset:"Create New Preset",customizeSettings:"Customize settings for your new preset",compareWithBase:"Compare with base preset",compare:"Compare",basePreset:"Base Preset",selectBasePreset:"Select base preset...",presetName:"Preset Name",myCustomPreset:"My custom preset",inheritsFrom:"Inherits from",dropJsonToImport:"Drop JSON to import",tabs:{common:"Common",allFields:"All Fields"},availableFields:"Available Fields",searchFieldsPlaceholder:"Search fields...",noMatchingFields:"No matching fields",allFieldsAdded:"All fields added",addCustomField:"Add custom field",yourOverrides:"Your Overrides",noOverridesYet:"No overrides yet",clickFieldsToAdd:"Click fields on the left to add them",saveAsTemplate:"Save as template",jsonTip:"Tip: Drag & drop a .json file anywhere on this modal to import settings"},cloudView:{searchPlaceholder:"Search presets...",templates:"Templates",refresh:"Refresh",newPreset:"New Preset",clearFilters:"Clear filters",compareMode:"Compare Mode",selectAnotherPreset:"Select another {{type}} preset",clickTwoPresets:"Click two presets of the same type to compare",selectFirst:"1. Select first",selectSecond:"2. Select second",compareNow:"Compare Now",lastSynced:"Last synced:",showingCount:"Showing {{showing}} of {{total}} presets",noPresetsFound:"No presets found",columns:{filament:"Filament",process:"Process",printer:"Printer"},noFilamentPresets:"No filament presets",noProcessPresets:"No process presets",noPrinterPresets:"No printer presets",filters:{type:"Type",owner:"Owner",printer:"Printer",nozzle:"Nozzle",filament:"Filament",layer:"Layer",all:"All",myPresets:"My Presets",builtIn:"Built-in",process:"Process"},noTemplatesPermission:"You do not have permission to manage templates",noRefreshPermission:"You do not have permission to refresh profiles",noCreatePermission:"You do not have permission to create presets"},templates:{title:"Quick Templates",noTemplates:"No templates yet",createFirst:"Create templates from the preset editor",typeFilter:"Type:",deleteTitle:"Delete Template",deleteWarning:"This action cannot be undone",deleteConfirm:'Are you sure you want to delete "{{name}}"?',namePlaceholder:"Template name",descriptionPlaceholder:"Description",settingsJson:"Settings (JSON)",fieldsCount:"{{count}} fields",shownInModals:"Shown in modals",hiddenInModals:"Hidden in modals",apply:"Apply",toast:{deleted:"Template deleted",updated:"Template updated",created:"Template created",applied:"Template applied"}}},support:{debugLoggingActive:"Debug logging is active",manageLogs:"Manage",collectItem7:"Printer connectivity and firmware versions",collectItem8:"Integration status (Spoolman, MQTT, HA)",collectItem9:"Network interfaces (subnets only)",collectItem10:"Python package versions",collectItem11:"Database health checks",collectItem12:"Docker environment details"},fileManager:{title:"File Manager",subtitle:"Organize and manage your print files",uploadFiles:"Upload Files",newFolder:"New Folder",folderName:"Folder Name",folderNamePlaceholder:"e.g., Functional Parts",renameFile:"Rename File",renameFolder:"Rename Folder",moveFiles:"Move {{count}} File(s)",rootNoFolder:"Root (No Folder)",current:"current",linkFolder:"Link Folder",linkFolderDescription:'Link "{{name}}" to a project or archive for quick access.',project:"Project",archive:"Archive",noProjectsFound:"No projects found",noArchivesFound:"No archives found",unlink:"Unlink",link:"Link",dragDropFiles:"Drag & drop files here",dropFilesHere:"Drop files here",orClickToBrowse:"or click to browse",allFileTypesSupported:"All file types supported. ZIP files will be extracted.",zipFilesDetected:"ZIP files detected",zipExtractOptions:"ZIP files will be extracted. Choose how to handle folder structure:",preserveZipStructure:"Preserve folder structure from ZIP",createFolderFromZip:"Create folder from ZIP filename",stlThumbnailGeneration:"STL thumbnail generation",zipMayContainStl:"ZIP files may contain STL files. Thumbnails can be generated during extraction.",thumbnailsCanBeGenerated:"Thumbnails can be generated for STL files. Large models may take longer to process.",generateThumbnailsForStl:"Generate thumbnails for STL files",threemfDetected:"3MF files detected",threemfExtractionInfo:"Printer model, material, color, and print settings will be automatically extracted from 3MF files.",willBeExtracted:"Will be extracted",filesExtracted:"{{count}} files extracted",uploadComplete:"Upload complete: {{succeeded}} succeeded",uploadFailed:"Upload failed",zipFilesFailed:"{{count}} files failed",uploading:"Uploading...",changeLink:"Change Link...",linkTo:"Link to...",linkToProjectOrArchive:"Link to project or archive",addToQueue:"Add to Queue",schedulePrint:"Schedule",generateThumbnail:"Generate Thumbnail",generateThumbnails:"Generate Thumbnails",generateThumbnailsForMissing:"Generate thumbnails for STL files missing them",gridView:"Grid view",listView:"List view",lowDiskSpaceWarning:"Low disk space warning",lowDiskSpaceDetails:"Only {{free}} free of {{total}} total. Threshold is set to {{threshold}} GB in settings.",files:"Files",folders:"Folders",size:"Size",free:"Free",allFiles:"All Files",wrap:"Wrap",enableTextWrapping:"Enable text wrapping",disableTextWrapping:"Disable text wrapping",collapse:"Collapse",collapseFoldersByDefault:"Collapse folders by default",expandFoldersByDefault:"Expand folders by default",dragToResizeTooltip:"Drag to resize, double-click to reset",searchFiles:"Search files...",allTypes:"All types",prints:"Prints",ascending:"Ascending",descending:"Descending",resultsCount:"{{showing}} of {{total}} files",selectAll:"Select All",deselectAll:"Deselect All",selected:"{{count}} selected",adding:"Adding...",loadingFiles:"Loading files...",folderIsEmpty:"Folder is empty",noFilesYet:"No files yet",folderEmptyDescription:"Upload files or move files into this folder to get started.",noFilesDescription:"Upload files to start organizing your print-related files.",noMatchingFiles:"No matching files",noMatchingFilesDescription:"No files match your current search or filter criteria.",clearFilters:"Clear filters",printedCount:"Printed {{count}}x",uploadedBy:"Uploaded By",deleteFolder:"Delete Folder",deleteFile:"Delete File",deleteFilesCount:"Delete {{count}} Files",deleteFolderConfirm:"Are you sure you want to delete this folder? All files inside will also be deleted.",deleteFileConfirm:"Are you sure you want to delete this file?",deleteFilesConfirm:"Are you sure you want to delete {{count}} selected files? This action cannot be undone.",deleting:"Deleting...",noPermissionRenameFolder:"You do not have permission to rename folders",noPermissionLinkFolder:"You do not have permission to link folders",noPermissionDeleteFolder:"You do not have permission to delete folders",noPermissionPrint:"You do not have permission to print",noPermissionAddToQueue:"You do not have permission to add to queue",noPermissionDownload:"You do not have permission to download files",noPermissionRenameFile:"You do not have permission to rename this file",noPermissionGenerateThumbnail:"You do not have permission to generate thumbnails",noPermissionDeleteFile:"You do not have permission to delete this file",noPermissionCreateFolder:"You do not have permission to create folders",noPermissionUpload:"You do not have permission to upload files",noPermissionMoveFiles:"You do not have permission to move files",noPermissionDeleteFiles:"You do not have permission to delete files",linkExternal:"Link External",linkExternalFolder:"Link External Folder",linkExternalFolderDescription:"Mount a host directory (NAS, USB, network share) into the File Manager. Files are not copied — they are accessed directly from the original path.",externalFolderNamePlaceholder:"e.g., NAS Prints",externalPath:"Host Path",externalPathHelp:"Absolute path to the directory on the Docker host. Must be bind-mounted into the container.",readOnly:"Read Only",readOnlyHelp:"prevents uploads and deletions",showHiddenFiles:"Show hidden files (dotfiles)",externalFolder:"External Folder",scanFolder:"Scan",toast:{folderCreated:"Folder created",folderDeleted:"Folder deleted",fileDeleted:"File deleted",filesDeleted:"Deleted {{count}} files",filesMoved:"Files moved",folderLinked:"Folder linked",folderUnlinked:"Folder unlinked",externalFolderLinked:"External folder linked and scanned",folderScanned:"Scan complete: {{added}} added, {{removed}} removed",addedToQueue:"Added {{count}} file(s) to queue",addedToQueuePartial:"Added {{added}} file(s), {{failed}} failed",failedToAddToQueue:"Failed to add files: {{error}}",fileRenamed:"File renamed",folderRenamed:"Folder renamed",thumbnailsGenerated:"Generated {{count}} thumbnail(s)",thumbnailsGeneratedPartial:"Generated {{succeeded}} thumbnail(s), {{failed}} failed",noStlMissingThumbnails:"No STL files missing thumbnails",failedToGenerateThumbnails:"Failed to generate thumbnails: {{error}}",thumbnailGenerated:"Thumbnail generated",failedToGenerateThumbnail:"Failed to generate thumbnail: {{error}}"}},projects:{title:"Projects",subtitle:"Organize and track your 3D printing projects",newProject:"New Project",editProject:"Edit Project",deleteProject:"Delete Project",projectName:"Project Name",description:"Description",noProjects:"No projects yet",noProjectsFiltered:"No {{status}} projects",noProjectsFilteredHelp:"You don't have any {{status}} projects. Projects will appear here when their status changes.",createFirst:"Create your first project to start organizing related prints, tracking progress, and managing your builds.",createFirstButton:"Create Your First Project",create:"Create",files:"Files",prints:"Prints",plates:"plates",parts:"parts",lastModified:"Last Modified",deleteConfirm:"Are you sure you want to delete this project? Archives and queue items will be unlinked but not deleted.",addFiles:"Add Files",removeFile:"Remove File",viewDetails:"View Details",namePlaceholder:"e.g., Voron 2.4 Build",descriptionPlaceholder:"Optional description...",color:"Color",targetPlates:"Target Plates",targetPlatesPlaceholder:"e.g., 25",targetPlatesHelp:"Number of print jobs",targetParts:"Target Parts",targetPartsPlaceholder:"e.g., 150",targetPartsHelp:"Total objects needed",tagsLabel:"Tags (comma-separated)",tagsPlaceholder:"e.g., voron, functional, gift",dueDate:"Due Date",priority:"Priority",priorityLow:"Low",priorityNormal:"Normal",priorityHigh:"High",priorityUrgent:"Urgent",statusActive:"Active",statusCompleted:"Completed",statusArchived:"Archived",done:"Done",completed:"completed",failed:"failed",inQueue:"in queue",noPrintsYet:"No prints yet",printJobs:"Print jobs (plates)",partsPrinted:"Parts printed",failedParts:"Failed parts",import:"Import",export:"Export",importProject:"Import project",exportAll:"Export all projects",loading:"Loading projects...",noEditPermission:"You do not have permission to edit projects",noDeletePermission:"You do not have permission to delete projects",noCreatePermission:"You do not have permission to create projects",noImportPermission:"You do not have permission to import projects",noExportPermission:"You do not have permission to export projects",toast:{created:"Project created",updated:"Project updated",deleted:"Project deleted",imported:"Project imported",multipleImported:"{{count}} projects imported",importFailed:"Import failed",exported:"Projects exported (metadata only)"}},projectDetail:{notFound:"Project not found",backToProjects:"Back to Projects",export:"Export",exportProject:"Export project",noExportPermission:"You do not have permission to export projects",noEditPermission:"You do not have permission to edit projects",partOf:"Part of:",priorityLabel:"Priority:",noPrints:"No prints in this project yet",status:{active:"Active",completed:"Completed",archived:"Archived"},priority:{low:"Low",normal:"Normal",high:"High",urgent:"Urgent"},dueDate:{overdue:"Overdue",today:"Due today",daysLeft:"{{count}} days left"},progress:{platesProgress:"Plates Progress",partsProgress:"Parts Progress",printJobs:"print jobs",parts:"parts",percentComplete:"{{percent}}% complete",remaining:"{{count}} remaining"},stats:{printJobs:"Print Jobs",total:"total",failed:"{{count}} failed",partsPrinted:"{{count}} parts printed",printTime:"Print Time",filamentUsed:"Filament Used"},cost:{title:"Cost Tracking",filamentCost:"Filament Cost",energy:"Energy",totalCost:"Total Cost",total:"Total",includesBom:"incl. BOM",budget:"Budget",remaining:"Remaining"},subProjects:{title:"Sub-projects ({{count}})"},notes:{title:"Notes",noEditPermission:"You do not have permission to edit notes",placeholder:"Add notes about this project...",empty:"No notes yet. Click Edit to add notes."},files:{title:"Files",linkFolders:"Link folders from the File Manager",forQuickAccess:"to this project for quick access.",fileCount:"{{count}} file(s)",empty:"No folders linked. Go to File Manager and link a folder to this project.",noFiles:"No files in this folder.",print:"Print Now",addToQueue:"Add to Queue"},bom:{title:"Bill of Materials",acquired:"{{completed}}/{{total}} acquired",showAll:"Show all",hideDone:"Hide done",addPart:"Add Part",noAddPermission:"You do not have permission to add parts",partNamePlaceholder:"Part name (e.g., M3x8 screws)",partName:"Part name",qty:"Qty",price:"Price ({{currency}})",sourcingUrlPlaceholder:"Sourcing URL (optional)",remarksPlaceholder:"Remarks (optional)",deletePart:"Delete Part",deleteConfirm:'Are you sure you want to delete "{{name}}"?',noUpdatePermission:"You do not have permission to update parts",noEditPermission:"You do not have permission to edit parts",noDeletePermission:"You do not have permission to delete parts",totalCost:"Total cost:",empty:"No parts in the bill of materials. Add hardware, electronics, or other components to track what needs to be sourced."},timeline:{title:"Activity Timeline",empty:"No activity yet."},template:{saveAsTemplate:"Save as Template",noCreatePermission:"You do not have permission to create templates"},queue:{title:"Queue",viewAll:"View all",printing:"{{count}} printing",queued:"{{count}} queued"},prints:{title:"Prints ({{count}})"},toast:{projectUpdated:"Project updated",partAdded:"Part added",partRemoved:"Part removed",exportFailed:"Export failed",projectExported:"Project exported",templateCreated:"Template created"}},system:{title:"System Information",version:"Version",uptime:"Uptime",cpuUsage:"CPU Usage",memoryUsage:"Memory Usage",diskUsage:"Disk Usage",networkInfo:"Network Info",logs:"Logs",debugMode:"Debug Mode",enableDebug:"Enable Debug Logging",disableDebug:"Disable Debug Logging",downloadLogs:"Download Logs",clearLogs:"Clear Logs",dockerInfo:"Docker Info",containerName:"Container Name",imageName:"Image Name",platform:"Platform",architecture:"Architecture"},library:{title:"Filament Library",addFilament:"Add Filament",editFilament:"Edit Filament",deleteFilament:"Delete Filament",vendor:"Vendor",material:"Material",color:"Color",kFactor:"K Factor",temperature:"Temperature",noFilaments:"No filaments in library",deleteConfirm:"Are you sure you want to delete this filament?",importFromPrinter:"Import from Printer",exportToFile:"Export to File"},spoolman:{title:"Spoolman Integration",enabled:"Spoolman Enabled",url:"Spoolman URL",connected:"Connected",disconnected:"Not Connected",testConnection:"Test Connection",sync:"Sync",syncing:"Syncing...",lastSync:"Last Sync",linkToSpoolman:"Link to Spoolman",openInSpoolman:"Open in Spoolman",unlinkSpool:"Unlink Spool",unlinkConfirmTitle:"Unlink Spool?",unlinkConfirmMessage:"This will disconnect the spool from Spoolman. The spool data in Spoolman will remain unchanged.",selectSpool:"Select Spool",noUnlinkedSpools:"No unlinked spools available",linkSuccess:"Spool linked to Spoolman successfully",linkFailed:"Failed to link spool",unlinkSuccess:"Spool unlinked from Spoolman successfully",unlinkFailed:"Failed to unlink spool",spoolId:"Spool ID",fillSourceLabel:"(Spoolman)",weight:"Weight",remaining:"Remaining",disableWeightSync:"Disable AMS Estimated Weight Sync",disableWeightSyncDesc:"Don't update remaining capacity from AMS estimates. Use this if you prefer Spoolman's usage tracking over AMS percentage-based estimates. New spools will still use the AMS estimate as their initial weight.",reportPartialUsage:"Report Partial Usage for Failed Prints",reportPartialUsageDesc:"When a print fails or is cancelled, report the estimated filament used up to that point based on layer progress."},inventory:{title:"Spool Inventory",addSpool:"Add Spool",editSpool:"Edit Spool",material:"Material",selectMaterial:"Select material...",subtype:"Subtype",brand:"Brand",searchBrand:"Search brand...",useCustomBrand:'Use "{{brand}}"',useCustomMaterial:"Use custom material: {{material}}",colorName:"Color Name",colorNamePlaceholder:"Jade White, Fire Red...",color:"Color",hexColor:"Hex Color",pickColor:"Pick custom color",labelWeight:"Label Weight",coreWeight:"Empty Spool Weight",searchSpoolWeight:"Search spool weight...",weightUsed:"Used",currentWeight:"Remaining Weight",measuredWeight:"Measured Weight",spoolName:"Spool",costPerKg:"Cost per kg",measuredWeightError:"Measured weight must be between {{min}}g and {{max}}g.",slicerFilament:"Slicer Filament",slicerFilamentName:"Slicer Preset Name",slicerPreset:"Slicer Preset",searchPresets:"Search filament presets...",selectedPreset:"Selected",noPresetsFound:"No presets found",tempOverrides:"Temperature Overrides",note:"Note",notePlaceholder:"Any additional notes about this spool...",archive:"Archive",restore:"Restore",noSpools:"No spools yet. Add your first spool to get started.",noManualSpools:"No manually added spools available. Add a spool to your inventory first.",kProfiles:"K-Profiles",addKProfile:"Add K-Profile",assignSpool:"Assign Spool",unassignSpool:"Unassign",assignSuccess:"Spool assigned and AMS slot configured",assignFailed:"Failed to assign spool",selectSpool:"Select a spool to assign to this slot",assigned:"Assigned",assigning:"Assigning...",searchSpools:"Search spools...",showAllSpools:"Show all spools",allMaterials:"All Materials",filterByBrand:"Filter by brand...",showArchived:"Show archived",quickAdd:"Quick Add (Stock)",quantity:"Quantity",stock:"Stock",configured:"Configured",spoolsCreated:"{{count}} spools created",spoolCreated:"Spool created",spoolUpdated:"Spool updated",spoolDeleted:"Spool deleted",spoolArchived:"Spool archived",spoolRestored:"Spool restored",deleteConfirm:"Are you sure you want to delete this spool? This cannot be undone.",archiveConfirm:"Are you sure you want to archive this spool?",advancedSettings:"Advanced Settings",filamentInfoTab:"Filament Info",paProfileTab:"PA Profile",filamentInfo:"Filament",additional:"Additional",loadingPresets:"Loading cloud presets...",cloudConnected:"Cloud connected",cloudNotConnected:"Cloud not connected (using defaults)",recentColors:"Recent",searchColors:"Search colors...",searchResults:"Search results",allColors:"All colors",commonColors:"Common colors",showLess:"Show less",showAll:"Show all",noColorsFound:"No colors match your search",noResults:"No matches found",selectMaterialFirst:"Please select a material first in the Filament Info tab.",noPrintersConfigured:"No printers configured. Add printers to use PA profiles.",matchingFilter:"Matching",anyBrand:"Any brand",anyVariant:"Any variant",autoSelect:"Auto-select",matches:"matches",match:"match",noMatches:"No matches",connected:"Connected",offline:"Offline",printerOffline:"Printer is offline. Connect to view calibration profiles.",noKProfilesMatch:"No K-profiles match the selected filament.",leftNozzle:"Left Nozzle",rightNozzle:"Right Nozzle",profilesSelected:"calibration profile(s) selected",totalInventory:"Total Inventory",totalConsumed:"Total Consumed",byMaterial:"By Material",inPrinter:"In Printer",lowStock:"Low Stock",sinceTracking:"Since tracking started",loadedInAms:"Loaded in AMS/Ext",remaining:"Remaining",weightCheck:"Weight Check",lastWeighed:"Last weighed",neverWeighed:"Never weighed",search:"Search spools...",showing:"Showing",to:"to",of:"of",show:"Show",spools:"spools",spool:"spool",page:"Page",noSpoolsMatch:"No results found",noSpoolsMatchDesc:"Try adjusting your search or filters to find what you're looking for.",active:"Active",archived:"Archived",all:"All",used:"Used",new:"New",clearFilters:"Clear filters",table:"Table",cards:"Cards",net:"Net",groupSimilar:"Group",groupedSpools:"{{count}} identical spools",groupedRows:"rows",columns:"Columns",configureColumns:"Configure Columns",configureColumnsDesc:"Drag to reorder columns or use arrows. Toggle visibility with the eye icon.",visible:"visible",reset:"Reset",cancel:"Cancel",applyChanges:"Apply Changes",moveUp:"Move up",moveDown:"Move down",hideColumn:"Hide column",showColumn:"Show column",linkToSpool:"Link to Spool",tagLinked:"Tag linked to spool",tagLinkFailed:"Failed to link tag",tagAlreadyLinked:"Tag already linked to another spool",unknownTag:"Unknown RFID tag detected",usageHistory:"Usage History",noUsageHistory:"No usage recorded yet",printName:"Print Name",weightConsumed:"Weight Consumed",clearHistory:"Clear",historyCleared:"Usage history cleared",fillSourceLabel:"(Inv)",lowStockThresholdError:"Threshold must be between 0.1 and 99.9",assignMismatchTitle:"Material mismatch",assignMismatchMessage:'The selected spool material "{{spoolMaterial}}" does not match the tray material "{{trayMaterial}}" for {{location}}. Assign anyway?',assignMismatchConfirm:"Assign Anyway",assignPartialMismatchMessage:'The spool material "{{spoolMaterial}}" is similar to but not exactly matching "{{trayMaterial}}" in {{location}}. Do you want to proceed?',assignProfileMismatchMessage:'The spool profile "{{spoolProfile}}" does not match the tray profile "{{trayProfile}}" in {{location}}. Do you want to proceed?'},timelapse:{title:"Timelapse",create:"Create Timelapse",download:"Download",delete:"Delete",preview:"Preview",frameRate:"Frame Rate",quality:"Quality",processing:"Processing...",noTimelapses:"No timelapses available"},ams:{title:"AMS",slot:"Slot",empty:"Empty",emptySlot:"Empty slot",unknown:"Unknown",humidity:"Humidity",temperature:"Temperature",filamentType:"Filament Type",filamentColor:"Color",remaining:"Remaining",history:"AMS History",noHistory:"No history available",configureSlot:"Configure Slot",externalSpool:"External Spool",profile:"Profile",kFactor:"K Factor",fill:"Fill",configure:"Configure",used:"used",remainingUnit:"remaining"},printModal:{title:"Start Print",selectPrinter:"Select Printer",selectPlate:"Select Plate",filamentMapping:"Filament Mapping",totalCost:"Total cost:",slotRemainingShort:" - {{grams}}g left",printSettings:"Print Settings",bedLeveling:"Bed Leveling",flowCalibration:"Flow Calibration",vibrationCalibration:"Vibration Calibration",layerInspection:"First Layer Inspection",timelapse:"Timelapse",startPrint:"Start Print",addToQueue:"Add to Queue",cancel:"Cancel",noPrintersAvailable:"No printers available",printerBusy:"Printer is busy",printerOffline:"Printer is offline",sameTypeDifferentColor:"Same type, different color",filamentTypeNotLoaded:"Filament type not loaded",openCalendar:"Open calendar",leftNozzle:"L",rightNozzle:"R",leftNozzleTooltip:"Left nozzle",rightNozzleTooltip:"Right nozzle",filamentOverride:"Filament Override",filamentOverrideHint:"Optionally override filaments for model-based assignment. The scheduler will match against your selected filaments instead of the original 3MF values.",originalFilament:"Original",overrideWith:"Override with",resetToOriginal:"Reset to original",insufficientFilamentTitle:"Not enough filament",insufficientFilamentMessage:"Some assigned spools have less filament remaining than this print needs:",insufficientFilamentLine:"{{printer}} - {{slot}}: needs {{required}}g, remaining {{remaining}}g",printAnyway:"Print anyway",forceColorMatch:"Force color match",staggerPrinterStarts:"Stagger printer starts",staggerGroupSize:"Group size",staggerInterval:"Interval (min)",staggerPreview:"{{printers}} printers → {{groups}} groups of {{size}}, starting every {{interval}} min",staggerLastGroup:"last group: {{count}}",staggerTotal:"total: {{minutes}} min",staggerToPrinters:"Stagger to {{count}} printers",gcodeInjection:"Inject auto-print G-code"},backup:{title:"Backup & Restore",createBackup:"Create Backup",restoreBackup:"Restore Backup",restoreDescription:"Replace all data from a backup file",downloadBackup:"Download Backup",uploadBackup:"Upload Backup",lastBackup:"Last Backup",autoBackup:"Auto Backup",backupNow:"Backup Now",restoreWarning:"Warning: Restoring a backup will overwrite all current data.",includeArchives:"Include Archives",includeSettings:"Include Settings",includeProfiles:"Include Profiles",backupSuccess:"Backup created successfully",restoreSuccess:"Backup restored successfully",backupFailed:"Backup failed",restoreFailed:"Restore failed",restoreNote:"Virtual Printer will be stopped during restore",githubBackup:"GitHub Backup",enabled:"Enabled",cloudLoginRequired:"Bambu Cloud login required. Sign in under Profiles → Cloud Profiles to enable GitHub backup.",cloudLoginRequiredShort:"Cloud login required",githubDescription:"Automatically sync your profiles to a private GitHub repository for backup and version history.",repositoryUrl:"Repository URL",personalAccessToken:"Personal Access Token",tokenSaved:"(saved)",enterNewToken:"Enter new token to update",tokenHint:"Fine-grained token with Contents read/write permission",branch:"Branch",manualOnly:"Manual only",hourly:"Hourly",daily:"Daily",weekly:"Weekly",includeInBackup:"Include in backup",kProfiles:"K-Profiles",kProfilesDescription:"Pressure advance calibration from connected printers",noPrintersConnected:"No printers connected",printersConnected:"{{connected}}/{{total}} connected",cloudProfiles:"Cloud Profiles",cloudProfilesDescription:"Filament, printer, and process presets from Bambu Cloud",appSettings:"App Settings",appSettingsDescription:"Bambuddy configuration (complete database)",spoolInventory:"Spool Inventory",spoolInventoryDescription:"Filament spools, usage history, and cost tracking",printArchives:"Print Archives",printArchivesDescription:"Print history metadata (no gcode/3MF files)",lastBackupAt:"Last backup:",noBackupsYet:"No backups yet",next:"Next:",startingBackup:"Starting backup...",test:"Test",enableBackup:"Enable Backup",testConnection:"Test Connection",enterRepoUrl:"Enter repository URL",enterRepoAndToken:"Enter repository URL and access token",repoRequired:"Repository URL is required",tokenRequired:"Access token is required",githubBackupEnabled:"GitHub backup enabled",tokenUpdated:"Token updated",settingsSaved:"Settings saved",failedToSave:"Failed to save: {{message}}",backupCompleteFiles:"Backup complete - {{count}} files updated",backupSkippedNoChanges:"Backup skipped - no changes",backupFailed2:"Backup failed: {{message}}",clearedLogs:"Cleared {{count}} logs",failedToClearLogs:"Failed to clear logs: {{message}}",history:"History",clear:"Clear",date:"Date",status:"Status",commit:"Commit",localBackup:"Local Backup",localBackupDescription:"Create a complete backup of your Bambuddy data including the database, archives, uploads, and all files.",downloadBackupLabel:"Download Backup",completeBackupZip:"Complete backup: database + all files (ZIP)",download:"Download",preparingBackup:"Preparing backup...",creatingArchive:"Creating backup archive... This may take a while for large archives.",downloadingFile:"Downloading backup file...",backupDownloaded:"Backup downloaded successfully",failedToCreateBackup:"Failed to create backup: {{message}}",restore:"Restore",restoreReplacesAll:"Restore replaces all data.",restoreReplacesAllDetail:"Your current database and files will be completely replaced. A restart is required after restore.",restoreConfirmTitle:"Restore Backup",restoreConfirmMessage:'Are you sure you want to restore from "{{filename}}"? This will completely replace your current database and all files. The application will need to be restarted after restore.',restoreConfirmButton:"Restore Backup",uploadingFile:"Uploading backup file...",backupRestoredRestart:"Backup restored. Please restart Bambuddy.",failedToRestore:"Failed to restore backup. Please check the file format.",reloadNow:"Reload Now",creatingBackup:"Creating Backup",restoringBackup:"Restoring Backup",preparing:"Preparing...",processing:"Processing...",doNotClosePage:"Please do not close this page or navigate away. This operation may take several minutes for large backups.",restoring:"Restoring...",restoreComplete:"Restore Complete",restoreFailed2:"Restore Failed",importSettings:"Import settings from a backup file",pleaseWaitRestoring:"Please wait while your data is being restored",selectBackupFile:"Click to select backup file (.json or .zip)",duplicateHandling:"How duplicate handling works:",matchPrinters:"Printers",matchPrintersBy:"matched by serial number",matchSmartPlugs:"Smart Plugs",matchSmartPlugsBy:"matched by IP address",matchNotificationProviders:"Notification Providers",matchNotificationProvidersBy:"matched by name",matchFilaments:"Filaments",matchFilamentsBy:"matched by name + type + brand",matchArchives:"Archives",matchArchivesBy:"matched by content hash (always skipped)",matchPendingUploads:"Pending Uploads",matchPendingUploadsBy:"matched by filename",matchSettingsTemplates:"Settings & Templates",matchSettingsTemplatesBy:"always overwritten",replaceExisting:"Replace existing data",keepExisting:"Keep existing data",overwriteDescription:"Overwrite items that already exist with backup data",keepDescription:"Only restore items that don't already exist",overwriteCaution:"Caution:",overwriteWarning:"Overwriting will replace your current configurations with data from the backup. Printer access codes are never overwritten for security.",cancel:"Cancel",processingBackup:"Processing backup file...",itemsRestored:"Items Restored",itemsSkipped:"Items Skipped",restored:"Restored",skippedAlreadyExist:"Skipped (already exist)",filesCategory:"Files (3MF, thumbnails, etc.)",andMore:"...and {{count}} more",newApiKeysGenerated:"New API Keys Generated",keysShownOnce:"These keys are only shown once. Copy them now!",copy:"Copy",noDataFound:"No data was found to restore in the backup file.",close:"Close",scheduledBackup:"Scheduled Backups",scheduledBackupDescription:"Automatically create backup snapshots on a schedule. Output directory can be mounted to a NAS or external storage.",frequency:"Frequency",backupTime:"Time",retention:"Retention",retentionDescription:"Number of backups to keep",outputPath:"Output Path",outputPathPlaceholder:"Default: {{path}}",outputPathDescription:"Leave empty for default location",runNow:"Run Now",backupFiles:"Backup Files",noScheduledBackups:"No backups yet",deleteBackup:"Delete",deleteBackupConfirm:"Delete this backup file?",backupRunning:"Backup in progress...",scheduledBackupComplete:"Backup completed successfully",scheduledBackupFailed:"Backup failed",nextBackup:"Next backup",backupSize:"Size",utc:"UTC",defaultPathLabel:"Default:",categories:{settings:"Settings",notification_providers:"Notification Providers",notification_templates:"Notification Templates",smart_plugs:"Smart Plugs",printers:"Printers",filaments:"Filaments",maintenance_types:"Maintenance Types",archives:"Archives",projects:"Projects",pending_uploads:"Pending Uploads",external_links:"External Links",api_keys:"API Keys"}},tags:{title:"Tags",addTag:"Add Tag",editTag:"Edit Tag",deleteTag:"Delete Tag",tagName:"Tag Name",tagColor:"Tag Color",noTags:"No tags",deleteConfirm:"Are you sure you want to delete this tag?",manageTags:"Manage Tags"},uploadModal:{title:"Upload 3MF Files",dragDrop:"Drag & drop .3mf files here",or:"or",browseFiles:"Browse Files",extractionInfo:"The printer model will be automatically extracted from the 3MF file metadata.",uploaded:"uploaded",failed:"failed",uploading:"Uploading...",upload:"Upload",uploadFailed:"Upload failed"},editArchive:{title:"Edit Archive",name:"Name",namePlaceholder:"Print name",printer:"Printer",noPrinter:"No printer",project:"Project",noProject:"No project",itemsPrinted:"Items Printed",itemsPrintedHelp:"Number of items produced in this print job",notes:"Notes",notesPlaceholder:"Add notes about this print...",externalLink:"External Link",externalLinkPlaceholder:"https://printables.com/model/...",externalLinkHelp:"Link to Printables, Thingiverse, or other source",tags:"Tags",tagsPlaceholder:"Add tags...",addMoreTags:"Add more tags...",matchingTags:'Matching "{{query}}"',existingTags:"Existing tags",clickToAdd:"(click to add)",status:"Status",failureReason:"Failure Reason",selectReason:"Select reason...",photos:"Photos of Printed Result",photosHelp:"Click + to add photos of your printed result",printResult:"Print result",saving:"Saving...",failureReasons:{adhesionFailure:"Adhesion failure",spaghettiDetached:"Spaghetti / Detached",layerShift:"Layer shift",cloggedNozzle:"Clogged nozzle",filamentRunout:"Filament runout",warping:"Warping",stringing:"Stringing",underExtrusion:"Under-extrusion",powerFailure:"Power failure",userCancelled:"User cancelled",other:"Other"},statuses:{completed:"Completed",failed:"Failed",aborted:"Cancelled",printing:"Printing"}},kProfiles:{title:"K-Profiles",noPrintersConfigured:"No Printers Configured",addPrinterInSettings:"Add a printer in Settings to manage K-profiles",noActivePrinters:"No Active Printers",enablePrinterConnection:"Enable a printer connection to view its K-profiles",loadingProfiles:"Loading K-Profiles...",printerOffline:"Printer Offline",printerOfflineDesc:"The selected printer is not connected. Power it on to view K-profiles.",noMatchingProfiles:"No Matching Profiles",noMatchingProfilesDesc:"No profiles match your search criteria",noKProfiles:"No K-Profiles",noKProfilesDesc:"No pressure advance profiles found for {{diameter}}mm nozzle",createFirstProfile:"Create First Profile",printer:"Printer",nozzle:"Nozzle",refresh:"Refresh",addProfile:"Add Profile",export:"Export",import:"Import",select:"Select",selectAll:"Select All",delete:"Delete",searchPlaceholder:"Search by name or filament...",allExtruders:"All Extruders",leftOnly:"Left Only",rightOnly:"Right Only",allFlow:"All Flow",hfOnly:"HF Only",sOnly:"S Only",sortName:"Sort: Name",sortKValue:"Sort: K-Value",sortFilament:"Sort: Filament",leftExtruder:"Left Extruder",rightExtruder:"Right Extruder",modal:{addTitle:"Add K-Profile",editTitle:"Edit K-Profile",profileName:"Profile Name",profileNamePlaceholder:"My PLA Profile",kValue:"K-Value",kValuePlaceholder:"0.020",kValueHelp:"Typical range: 0.01 - 0.06 for PLA, 0.02 - 0.10 for PETG",filament:"Filament",selectFilament:"Select filament...",noFilamentsHelp:"No filaments found. Create a K-profile in Bambu Studio first.",flowType:"Flow Type",highFlow:"High Flow",standard:"Standard",nozzleSize:"Nozzle Size",extruder:"Extruder",extruders:"Extruders",left:"Left",right:"Right",notes:"Notes (stored locally)",notesPlaceholder:"Add notes about this profile...",notesHelp:"Notes are saved in Bambuddy, not on the printer",syncing:"Syncing with printer...",savingExtruder:"Saving to extruder {{current}}/{{total}}...",pleaseWait:"Please wait"},deleteConfirm:{title:"Delete Profile",cannotUndo:"This cannot be undone",message:'Are you sure you want to delete "{{name}}" from the printer?'},bulkDelete:{title:"Delete Profiles",cannotUndo:"This cannot be undone",message:"Are you sure you want to delete {{count}} selected profiles from the printer?"},toast:{profileSaved:"K-profile saved",profilesSaved:"K-profile saved to {{count}} extruders",selectAtLeastOneExtruder:"Please select at least one extruder",profileDeleted:"K-profile deleted",profilesDeleted:"Deleted {{count}} profiles",exportedProfiles:"Exported {{count}} profiles",importedProfiles:"Imported {{count}} of {{total}} profiles",noProfilesToExport:"No profiles to export",invalidFileFormat:"Invalid file format",failedToParseImport:"Failed to parse import file",failedToSaveBatch:"Failed to save K-profiles",noteSaved:"Note saved",failedToSaveNote:"Failed to save note"},permission:{noRead:"You do not have permission to refresh profiles",noCreate:"You do not have permission to add profiles",noUpdate:"You do not have permission to update K-profiles",noDelete:"You do not have permission to delete K-profiles",noExport:"You do not have permission to export profiles",noImport:"You do not have permission to import profiles"}},virtualPrinter:{title:"Virtual Printer",running:"Running",stopped:"Stopped",description:{default:"Enable a virtual printer that appears in Bambu Studio and OrcaSlicer. Files sent to this printer will be archived directly without printing.",proxy:"Enable a proxy that relays slicer traffic to a real printer, allowing remote printing over any network."},enable:{title:"Enable Virtual Printer",visibleInSlicer:'Visible as "Bambuddy" in slicer discovery',proxyingTo:"Proxying to {{name}}",notActive:"Not active"},model:{title:"Printer Model",description:"Select which printer model to emulate.",restartWarning:"Changing the model will restart the virtual printer"},accessCode:{title:"Access Code",isSet:"Access code is set",notSet:"No access code set - required to enable",placeholder:"Enter 8-char code",placeholderChange:"Enter new code to change",hint:"Must be exactly 8 characters. Used by slicers to authenticate.",charCount:"({{count}}/8)"},targetPrinter:{title:"Target Printer",configured:"Proxy target configured",notConfigured:"No target printer selected - required for proxy mode",placeholder:"Select a printer...",hint:"Select the printer to proxy slicer traffic to. The printer must be in LAN mode.",noPrinters:"No printers configured. Add a printer first to use proxy mode."},remoteInterface:{title:"Network Interface Override",configured:"Interface override active",optional:"Optional - use if auto-detected IP is wrong (e.g. multiple NICs, Docker, VPN)",placeholder:"Auto-detect (default)...",hint:"Override the IP address advertised via SSDP and used in the TLS certificate. Useful when Bambuddy has multiple network interfaces."},mode:{title:"Mode",archive:"Archive",archiveDesc:"Archive files immediately",review:"Review",reviewDesc:"Review before archiving",queue:"Queue",queueDesc:"Archive and add to queue",proxy:"Proxy",proxyDesc:"Relay to real printer"},autoDispatch:{title:"Auto-dispatch",description:"Automatically start prints when added to queue. When off, prints wait for manual dispatch."},setupRequired:{title:"Setup Required",description:"The virtual printer feature requires additional system configuration before it will work. This includes port forwarding, firewall rules, and platform-specific settings.",readGuide:"Read the setup guide before enabling"},howItWorks:{title:"How it works",step1:"On the same LAN, virtual printers appear in your slicer (Bambu Studio / OrcaSlicer) automatically via discovery. From other networks, add them manually by IP address and access code.",step2:'In Archive, Review, and Queue modes, use the "Send" button in your slicer to upload 3MF files to Bambuddy. The slicer will show "Print success" — the file is stored, not printed.',step3:"In Proxy mode, the virtual printer relays all traffic to a real printer — prints start immediately as if connected directly."},status:{title:"Status Details",printerName:"Printer Name",model:"Model",serialNumber:"Serial Number",mode:"Mode",pendingFiles:"Pending Files",targetPrinter:"Target Printer",ftpPort:"FTP Port",mqttPort:"MQTT Port",ftpConnections:"FTP Connections",mqttConnections:"MQTT Connections"},toast:{updated:"Virtual printer settings updated",failedToUpdate:"Failed to update settings",accessCodeRequired:"Please set an access code first",targetPrinterRequired:"Please select a target printer first",bindIpRequired:"Please set a bind IP first",accessCodeEmpty:"Access code cannot be empty",accessCodeLength:"Access code must be exactly 8 characters",created:"Virtual printer created",failedToCreate:"Failed to create virtual printer",deleted:"Virtual printer deleted",failedToDelete:"Failed to delete virtual printer"},list:{title:"Virtual Printers",add:"Add",addFirst:"Add Virtual Printer",empty:"No virtual printers configured. Add one to get started."},bindIp:{title:"Bind Interface",placeholder:"Select interface...",hint:"Network interface for this virtual printer to bind to. Must be unique per printer."},proxy:{accessCodeHint:"In proxy mode, use your target printer's access code in the slicer. The connection is forwarded transparently to the real printer."},addDialog:{title:"Add Virtual Printer",name:"Name",hint:"You can configure access code, target printer, and other settings after creating.",create:"Create"},deleteConfirm:{title:"Delete Virtual Printer",message:'Are you sure you want to delete "{{name}}"? This will stop all services for this printer.'}},modelViewer:{openInSlicer:"Open in Slicer",tabs:{model:"3D Model",gcode:"G-code Preview"},notAvailable:"not available",notSliced:"not sliced",plates:"Plates",allPlates:"All Plates",plateNumber:"Plate {{number}}",plateCount:"{{count}} plate",plateCount_other:"{{count}} plates",objectCount:"{{count}} object",objectCount_other:"{{count}} objects",filamentCount:"{{count}} filament",filamentCount_other:"{{count}} filaments",eta:"ETA {{minutes}} min",noPreview:"No preview available for this file",pagination:{pageOf:"Page {{current}} of {{total}}",prev:"Prev",next:"Next"},errors:{failedToLoad:"Failed to load file",noMeshes:"No meshes found in 3MF file",unsupportedFormat:"Unsupported file format"}},maintenanceDescriptions:{lubricateCarbonRods:"Apply lubricant to carbon rods for smooth motion",lubricateRails:"Apply lubricant to linear rails for smooth motion",cleanNozzle:"Clean hotend and nozzle to prevent clogs",checkBelts:"Verify belt tension for accurate prints",cleanBuildPlate:"Clean build plate for better adhesion",checkExtruder:"Inspect extruder gears for wear",checkCooling:"Ensure cooling fans are working properly",generalInspection:"General printer inspection",cleanCarbonRods:"Clean carbon rods to reduce friction",lubricateSteelRods:"Apply lubricant to steel rods for smooth motion",cleanSteelRods:"Clean steel rods to reduce friction",cleanLinearRails:"Wipe linear rails to remove dust and debris",checkPtfeTube:"Inspect PTFE tube for wear or damage",replaceHepaFilter:"Replace HEPA filter for air quality",replaceCarbonFilter:"Replace activated carbon filter",lubricateLeftNozzleRail:"Lubricate left nozzle rail (H2 series)"},smartPlugs:{offline:"Offline",admin:"Admin",openPlugAdminPage:"Open plug admin page",deleteSmartPlug:"Delete Smart Plug",turnOnSmartPlug:"Turn On Smart Plug",turnOffSmartPlug:"Turn Off Smart Plug",turnOn:"Turn On",turnOff:"Turn Off",addSmartPlug:{scanningNetwork:"Scanning network...",chooseEntity:"Choose an entity...",connectionFailed:"Connection failed",searchEntities:"Search entities...",searchPowerSensors:"Search power sensors...",searchEnergySensors:"Search energy sensors...",placeholders:{plugName:"Living Room Plug",mqttStateOnValue:"ON, true, 1",mqttSameAsPower:"Same as power topic, or different"}},linkedTo:"Linked to:",monitorOnly:"Monitor Only",alerts:"Alerts",scheduleOn:"On {{time}}",scheduleOff:"Off {{time}}",on:"On",off:"Off",power:"Power",kwhToday:"kWh Today",settings:"Settings",automationSettings:"Automation Settings",showInSwitchbar:"Show in Switchbar",quickAccessSidebar:"Quick access from sidebar",enabled:"Enabled",enableAutomation:"Enable automation for this plug",autoOn:"Auto On",autoOnDescription:"Turn on when print starts",autoOff:"Auto Off",autoOffDescription:"Turn off when print completes (one-shot)",autoOffPersistent:"Keep Enabled",autoOffPersistentDescription:"Stay enabled between prints instead of one-shot",turnOffDelayMode:"Turn Off Delay Mode",time:"Time",temp:"Temp",delayMinutes:"Delay (minutes)",tempThreshold:"Temperature threshold (°C)",tempThresholdDescription:"Turns off when nozzle cools below this temperature",edit:"Edit",deleteConfirm:'Are you sure you want to delete "{{name}}"? This cannot be undone.',turnOnConfirm:'Are you sure you want to turn on "{{name}}"?',turnOffConfirm:'Are you sure you want to turn off "{{name}}"? This will cut power to the connected device.',failedToTurn:'Failed to turn {{action}} "{{name}}"',unknown:"Unknown",addTitle:"Add Smart Plug",editTitle:"Edit Smart Plug",stopScanning:"Stop Scanning",discoverTasmota:"Discover Tasmota Devices",foundDevices:"Found {{count}} device(s) - click to select:",noDevicesFound:"No Tasmota devices found on your network",haNotConfigured:"Home Assistant is not configured. Set it up in",haSettingsPath:"Settings → Network → Home Assistant",selectEntity:"Select Entity *",ipAddress:"IP Address *",nameLabel:"Name *",username:"Username",password:"Password",authHint:"Leave empty if your Tasmota device doesn't require authentication",linkToPrinter:"Link to Printer",noPrinter:"No printer (manual control only)",linkingDescription:"Linking enables automatic on/off when prints start/complete",powerAlerts:"Power Alerts",alertAbove:"Alert if above (W)",alertBelow:"Alert if below (W)",alertDescription:"Get notified when power consumption crosses these thresholds. Leave empty to disable that direction.",dailySchedule:"Daily Schedule",turnOnAt:"Turn On at",turnOffAt:"Turn Off at",scheduleDescription:"Automatically turn the plug on/off at these times daily. Leave empty to skip that action.",showOnPrinterCard:"Show on Printer Card",displayOnPrinterCard:"Display button on printer card",connectedResult:"Connected!",deviceLabel:"Device: {{name}} - ",stateLabel:"State: {{state}}",test:"Test",delete:"Delete",save:"Save",add:"Add",cancel:"Cancel",failedToStartScan:"Failed to start scan",nameRequired:"Name is required",entityRequired:"Entity is required for Home Assistant plugs",mqttTopicRequired:"At least one MQTT topic must be configured for power, energy, or state monitoring",loadingEntities:"Loading entities...",loading:"Loading...",failedToLoadEntities:"Failed to load entities: {{error}}",noEntitiesMatching:'No entities found matching "{{search}}"',noEntitiesAvailable:"No entities available",searchingEntities:"Searching all entities ({{count}} found)",showingEntities:"Showing switch, light, input_boolean ({{count}} available)",energyMonitoringOptional:"Energy Monitoring (Optional)",energyMonitoringHint:"Search and select sensors that provide power/energy data.",powerSensorW:"Power Sensor (W)",energyTodayKwh:"Energy Today (kWh)",totalEnergyKwh:"Total Energy (kWh)",noMatchingSensors:"No matching sensors",none:"None",mqttNotConfigured:"MQTT broker not configured. Set broker address in",mqttSettingsPath:"Settings → Network → MQTT Publishing",mqttNotConfiguredSuffix:"(you don't need to enable publishing, just fill in the broker details).",mqttMonitorOnlyDescription:"MQTT plugs receive power/energy data via MQTT subscription. On/off control is not available - use your MQTT broker or home automation system.",powerMonitoring:"Power Monitoring",energyMonitoring:"Energy Monitoring",stateMonitoring:"State Monitoring",optional:"optional",topic:"Topic",jsonPath:"JSON Path",multiplier:"Multiplier",onValue:"ON Value",mqttPowerHint:`JSON path extracts value from JSON payload (e.g., "power_l1"). Leave empty if topic publishes raw numeric values. Use multiplier 0.001 for mW→W, 1000 for kW→W.`,mqttEnergyHint:`JSON path extracts value from JSON payload. Leave empty for raw values. Use multiplier 0.001 for Wh→kWh, 1000 for MWh→kWh.`,mqttStateHint:`JSON path extracts value from JSON payload. Leave empty for raw values. ON value: the exact string that means "ON". Leave empty for auto-detect (ON, true, 1).`,restControl:"Control",restOnUrl:"Turn ON URL",restOffUrl:"Turn OFF URL",restOnBody:"ON Request Body",restOffBody:"OFF Request Body",restMethod:"HTTP Method",restHeaders:"Custom Headers (JSON)",restStatusUrl:"Status URL",restStatusPath:"State JSON Path",restStatusOnValue:"ON Value",restPowerUrl:"Power URL",restPowerPath:"Power JSON Path",restPowerMultiplier:"Power Multiplier",restEnergyUrl:"Energy URL",restEnergyPath:"Energy JSON Path",restEnergyMultiplier:"Energy Multiplier",restUrlRequired:"At least one URL (ON or OFF) is required for REST plugs",restHeadersHint:'e.g. {"Authorization": "Bearer your-token"}',restBodyHint:'e.g. ON, {"state": "on"}',restStatusHint:"URL to poll for current state",restPathHint:"e.g. state or data.power.status",restPowerUrlHint:"Separate URL for power data (uses Status URL if empty)",restEnergyUrlHint:"Separate URL for energy data (uses Status URL if empty)",restEnergyHint:"Each value can use its own URL or fall back to the Status URL. Use multipliers for unit conversion (e.g. 0.001 to convert Wh to kWh).",testConnection:"Test Connection",connectionSuccess:"Connection successful",noSwitchesInSwitchbar:"No switches in switchbar",enableSwitchbarHint:'Enable "Show in Switchbar" in Settings > Smart Plugs'},notifications:{providerTypes:{callmebot:"CallMeBot/WhatsApp",ntfy:"ntfy",pushover:"Pushover",telegram:"Telegram",email:"Email",discord:"Discord",webhook:"Webhook",homeassistant:"Home Assistant"},providerDescriptions:{email:"SMTP email notifications",telegram:"Notifications via Telegram bot",discord:"Send to Discord channel via webhook",ntfy:"Free, self-hostable push notifications",pushover:"Simple, reliable push notifications",callmebot:"Free WhatsApp notifications via CallMeBot",webhook:"Generic HTTP POST to any URL",homeassistant:"Persistent notifications in Home Assistant dashboard"},lastSuccess:"Last: {{date}}",error:"Error",printer:"Printer:",allPrinters:"All printers",sendTestNotification:"Send Test Notification",eventSettings:"Event Settings",enabled:"Enabled",sendFromProvider:"Send notifications from this provider",printEvents:"Print Events",printerStatus:"Printer Status",amsAlarms:"AMS Alarms",amsHtAlarms:"AMS-HT Alarms",printQueue:"Print Queue",start:"Start",plateCheck:"Plate Check",complete:"Complete",failed:"Failed",stopped:"Stopped",progress:"Progress",offline:"Offline",lowFilament:"Low Filament",maintenance:"Maintenance",amsHumidity:"AMS Humidity",amsTemp:"AMS Temp",amsHtHumidity:"AMS-HT Humidity",amsHtTemp:"AMS-HT Temp",bedCooled:"Bed Cooled",firstLayer:"First Layer",quiet:"Quiet",digest:"Digest {{time}}",printStarted:"Print Started",plateNotEmpty:"Plate Not Empty",plateNotEmptyDescription:"Objects detected before print",printCompleted:"Print Completed",bedCooledLabel:"Bed Cooled",bedCooledDescription:"Bed cooled below threshold after print",firstLayerCompleteLabel:"First Layer Complete",firstLayerCompleteDescription:"Notify with snapshot when first layer finishes",missingSpoolAssignmentLabel:"Missing Spool Assignment",missingSpoolAssignmentDescription:"Notify when print starts and required trays have no assigned spool",printFailed:"Print Failed",printStopped:"Print Stopped",progressMilestones:"Progress Milestones",progressMilestonesDescription:"Notify at 25%, 50%, 75%",printerOffline:"Printer Offline",printerError:"Printer Error",lowFilamentLabel:"Low Filament",maintenanceDue:"Maintenance Due",maintenanceDueDescription:"Notify when maintenance is needed",amsHumidityHigh:"AMS Humidity High",amsHumidityHighDescription:"Regular AMS humidity exceeds threshold",amsTemperatureHigh:"AMS Temperature High",amsTemperatureHighDescription:"Regular AMS temperature exceeds threshold",amsHtHumidityHigh:"AMS-HT Humidity High",amsHtHumidityHighDescription:"AMS-HT humidity exceeds threshold",amsHtTemperatureHigh:"AMS-HT Temperature High",amsHtTemperatureHighDescription:"AMS-HT temperature exceeds threshold",jobAdded:"Job Added",jobAddedDescription:"Job added to queue",jobAssigned:"Job Assigned",jobAssignedDescription:"Model-based job assigned to printer",jobStarted:"Job Started",jobStartedDescription:"Queue job started printing",jobWaiting:"Job Waiting",jobWaitingDescription:"Job waiting for filament or printer",jobSkipped:"Job Skipped",jobSkippedDescription:"Job skipped (previous failed)",jobFailed:"Job Failed",jobFailedDescription:"Job failed to start",queueComplete:"Queue Complete",queueCompleteDescription:"All queue jobs finished",quietHours:"Quiet Hours",noNotificationsDuring:"No notifications during these hours",editProviderToChangeQuietHours:"Edit provider to change quiet hours",dailyDigest:"Daily Digest",batchNotifications:"Batch notifications into a single daily summary",sendAt:"Send at {{time}}",editProviderToChangeDigestTime:"Edit provider to change digest time",edit:"Edit",deleteProvider:"Delete Notification Provider",deleteConfirm:'Are you sure you want to delete "{{name}}"? This cannot be undone.',delete:"Delete",addTitle:"Add Notification Provider",editTitle:"Edit Notification Provider",nameLabel:"Name *",namePlaceholder:"My Notifications",providerTypeLabel:"Provider Type *",configuration:"Configuration",testConfiguration:"Test Configuration",printerFilter:"Printer Filter",onlyFromPrinter:"Only send notifications for events from this printer",quietHoursDnd:"Quiet Hours (Do Not Disturb)",quietStart:"Start",quietEnd:"End",dailyDigestLabel:"Daily Digest",sendDigestAt:"Send digest at",digestCollected:"Events will be collected and sent as a single summary at this time",notificationEvents:"Notification Events",progressPercent:"(25%, 50%, 75%)",bedCooledAfterPrint:"(after print completes)",cancel:"Cancel",save:"Save",add:"Add",nameRequired:"Name is required",fieldRequired:"{{field}} is required",phoneNumber:"Phone Number",apiKey:"API Key",serverUrl:"Server URL",topic:"Topic",authToken:"Auth Token",userKey:"User Key",appToken:"App Token",priority:"Priority",botToken:"Bot Token",chatId:"Chat ID",smtpServer:"SMTP Server",smtpPort:"SMTP Port",security:"Security",authentication:"Authentication",username:"Username",password:"Password",fromEmail:"From Email",toEmail:"To Email",webhookUrl:"Webhook URL",payloadFormat:"Payload Format",authorization:"Authorization",titleFieldName:"Title Field Name",messageFieldName:"Message Field Name",editTemplate:"Edit Template: {{name}}",titleLabel:"Title",bodyLabel:"Body",titlePlaceholder:"Notification title...",bodyPlaceholder:"Notification body...",availableVariables:"Available Variables",clickToInsert:"Click to insert at cursor position in body",livePreview:"Live Preview",hide:"Hide",show:"Show",loadingPreview:"Loading preview...",enterTemplateContent:"Enter template content to see preview",titlePreview:"Title:",bodyPreview:"Body:",resetToDefault:"Reset to Default",titleRequired:"Title is required",bodyRequired:"Body is required",notificationLog:"Notification Log",showFailedOnly:"Failed only",last24Hours:"Last 24 hours",last7Days:"Last 7 days",last30Days:"Last 30 days",last90Days:"Last 90 days",justNow:"Just now",noFailedNotifications:"No failed notifications",noNotificationsLogged:"No notifications logged",unknownProvider:"Unknown Provider",logTitle:"Title",logMessage:"Message",logError:"Error",logProvider:"Provider: {{type}}",logTime:"Time: {{time}}",refresh:"Refresh",clearOld:"Clear Old",statsSummary:"Last {{days}} days:",statsNotifications:"notifications",statsSent:"{{count}} sent",statsFailed:"{{count}} failed",eventTypes:{print_start:"Print Started",print_complete:"Print Complete",print_failed:"Print Failed",print_stopped:"Print Stopped",print_progress:"Progress",printer_offline:"Printer Offline",printer_error:"Printer Error",filament_low:"Low Filament",maintenance_due:"Maintenance Due",test:"Test"},userEmail:{title:"Notifications",emailNotifications:"Email Notifications",emailNotificationsDesc:"Receive email notifications for your own print jobs. Emails are sent using the system SMTP settings configured in Advanced Authentication.",sendingTo:"Notifications will be sent to",noEmailWarning:"Your account does not have an email address. Contact an administrator to add one.",printJobNotifications:"Print Job Notifications",printJobNotificationsDesc:"Choose which events trigger email notifications for print jobs you submit.",printJobStarts:"Print Job Starts",printJobStartsDesc:"Get notified when your print job begins.",printJobFinishes:"Print Job Finishes",printJobFinishesDesc:"Get notified when your print job completes successfully.",printErrors:"Print Errors",printErrorsDesc:"Get notified when your print job fails or encounters an error.",printJobStops:"Print Job Stops",printJobStopsDesc:"Get notified when your print job is cancelled or stopped.",saveSuccess:"Notification preferences saved.",saveError:"Failed to save notification preferences."}},richTextEditor:{bold:"Bold",italic:"Italic",underline:"Underline",bulletList:"Bullet List",numberedList:"Numbered List",alignLeft:"Align Left",alignCenter:"Align Center",alignRight:"Align Right",addLink:"Add Link",removeLink:"Remove Link"},externalLinks:{noLinksConfigured:"No external links configured",deleteLink:"Delete Link",removeCustomIcon:"Remove custom icon",openInNewTab:"Open in new tab",placeholders:{linkName:"My Link"}},keyboardShortcuts:{title:"Keyboard Shortcuts",navigation:"Navigation",archivesSection:"Archives",kProfilesSection:"K-Profiles",generalSection:"General",shortcuts:{goToPrinters:"Go to Printers",goToArchives:"Go to Archives",goToQueue:"Go to Queue",goToStats:"Go to Statistics",goToProfiles:"Go to Cloud Profiles",goToSettings:"Go to Settings",focusSearch:"Focus search",openUploadModal:"Open upload modal",clearSelection:"Clear selection / blur input",contextMenu:"Context menu on cards",refreshProfiles:"Refresh profiles",newProfile:"New profile",exitSelectionMode:"Exit selection mode",showHelp:"Show this help"},footer:"Press Esc or click outside to close"},notificationLog:{title:"Notification Log",events:{printStarted:"Print Started",printComplete:"Print Complete",printFailed:"Print Failed",printStopped:"Print Stopped",progress:"Progress",printerOffline:"Printer Offline",printerError:"Printer Error",lowFilament:"Low Filament",maintenanceDue:"Maintenance Due",test:"Test"},timeAgo:{justNow:"Just now",minutesAgo:"{{minutes}}m ago",hoursAgo:"{{hours}}h ago"}},restoreBackup:{title:"Restore Backup",restoring:"Restoring...",restoreComplete:"Restore Complete",restoreFailed:"Restore Failed",importSettings:"Import settings from a backup file",pleaseWait:"Please wait while your data is being restored",clickToSelect:"Click to select backup file (.json or .zip)",howDuplicateHandling:"How duplicate handling works:",categories:{printers:"Printers",smartPlugs:"Smart Plugs",notificationProviders:"Notification Providers",filaments:"Filaments",archives:"Archives",pendingUploads:"Pending Uploads",settingsTemplates:"Settings & Templates"},matchingInfo:{printers:"matched by serial number",smartPlugs:"matched by IP address",notificationProviders:"matched by name",filaments:"matched by name + type + brand",archives:"matched by content hash",pendingUploads:"matched by filename",settingsTemplates:"always overwritten"},replaceExisting:"Replace existing data",keepExisting:"Keep existing data",replaceDescription:"Overwrite items that already exist with backup data",keepDescription:"Only restore items that don't already exist",caution:"Caution:",cautionText:"Overwriting will replace your current configurations with backup data. Printer access codes are never overwritten for security.",itemsRestored:"Items Restored",itemsSkipped:"Items Skipped",restored:"Restored",skipped:"Skipped (already exist)",filesLabel:"Files (3MF, thumbnails, etc.)",newApiKeysGenerated:"New API Keys Generated",newApiKeysWarning:"These keys are only shown once. Copy them now!",processingBackup:"Processing backup file...",noDataFound:"No data was found to restore in the backup file.",failedToRestore:"Failed to restore backup. Please check the file format."},backupExport:{title:"Export Backup",selectData:"Select data to include",selectAll:"Select All",selectNone:"Select None",categoryDescriptions:{settings:"Language, theme, update preferences",notifications:"ntfy, Pushover, Discord, etc.",templates:"Custom message templates",smartPlugs:"Tasmota plug configurations",externalLinks:"Sidebar links to external services",printers:"Printer info (access codes excluded)",plateDetection:"Empty plate reference images",filaments:"Filament types and costs",maintenance:"Custom maintenance schedules",archives:"All print data + files (3MF, thumbnails, photos)",projects:"Projects, BOM items, and attachments",pendingUploads:"Virtual printer uploads awaiting review",apiKeys:"Webhook API keys (new keys generated on import)"},requiresPrinters:"Requires Printers to be selected",zipFileWarning:"ZIP file will be created.",zipFileDescription:"Includes all 3MF files, thumbnails, timelapses, and photos. This may take a while and result in a large file.",includeAccessCodes:"Include Access Codes",includeAccessCodesDescription:"For transferring to another machine",includeAccessCodesWarning:"Access codes will be included in plain text. Keep this backup file secure!",categoriesSelected:"{{selectedCount}} categories selected"},pendingUploads:{placeholders:{notes:"Add notes about this print..."},discardUpload:"Discard Upload",archiveAllUploads:"Archive All Uploads",discardAllUploads:"Discard All Uploads",archive:"Archive",timeAgo:{justNow:"Just now",minutesAgo:"{{minutes}}m ago",hoursAgo:"{{hours}}h ago",daysAgo:"{{days}}d ago"}},apiBrowser:{placeholders:{requestBody:"JSON request body...",searchEndpoints:"Search endpoints..."}},configureAmsSlot:{title:"Configure AMS Slot",slotConfigured:"Slot Configured!",configuringSlot:"Configuring slot:",slotLabel:"{{ams}} Slot {{slot}}",searchPresets:"Search presets...",colorPlaceholder:"Color name or hex (e.g., brown, FF8800)",clearCustomColor:"Clear custom color",noCloudPresets:"No cloud presets. Login to Bambu Cloud to sync.",noPresetsAvailable:"No presets available. Login to Bambu Cloud or import local profiles.",noMatchingPresets:"No matching presets found.",custom:"Custom",builtin:"Built-in",settingsSentToPrinter:"Settings sent to printer",filamentProfile:"Filament Profile",kProfileLabel:"K Profile (Pressure Advance)",filteringFor:"Filtering for: {{material}}",noKProfile:"No K profile (use default 0.020)",noMatchingKProfiles:"No matching K profiles found. Default K=0.020 will be used.",selectFilamentFirst:"Select a filament profile first",kFromCalibration:"K={{value}} from printer calibration",customColorLabel:"Custom Color (optional)",presetColors:"{{name}} colors:",showLessColors:"Show less colors",showMoreColors:"Show more colors",clear:"Clear",hexLabel:"Hex: #{{hex}}",resetting:"Resetting...",resetSlot:"Reset Slot",cancel:"Cancel",configuring:"Configuring...",configureSlot:"Configure Slot"},githubBackup:{title:"GitHub Backup",history:"History",downloadBackup:"Download Backup",restoreBackup:"Restore Backup",noBackupsYet:"No backups yet"},emailSettings:{placeholders:{fromName:"BamBuddy"}},tagManagement:{searchTags:"Search tags...",renameTag:"Rename tag",deleteTag:"Delete tag"},notificationTemplates:{placeholders:{title:"Notification title...",body:"Notification body..."}},batchTag:{placeholders:{newTag:"Enter new tag..."}},photoGallery:{deletePhoto:"Delete Photo"},filamentHoverCard:{copySpoolUuid:"Copy spool UUID"},kProfilesView:{hasNote:"Has note",copyProfile:"Copy profile"},layout:{openMenu:"Open menu",noPermissionSystemInfo:"You do not have permission to view system information"},dashboard:{dragToReorder:"Drag to reorder",hideWidget:"Hide widget"},notificationProviderCard:{deleteNotificationProvider:"Delete Notification Provider"},fileManagerModal:{closeFileManager:"Close file manager",sortFiles:"Sort files",goToParentFolder:"Go to parent folder",threeView:"3D View"},embeddedCameraViewer:{refreshStream:"Refresh stream",close:"Close",zoomOut:"Zoom out",resetZoom:"Reset zoom",zoomIn:"Zoom in",dragToResize:"Drag to resize"},timelapseViewer:{skipBack5s:"Skip back 5s",skipForward5s:"Skip forward 5s"},notificationProviders:{descriptions:{email:"SMTP email notifications",telegram:"Notifications via Telegram bot",discord:"Send to Discord channel via webhook",ntfy:"Free, self-hostable push notifications",pushover:"Simple, reliable push notifications",callmebot:"Free WhatsApp notifications via CallMeBot",webhook:"Generic HTTP POST to any URL"}},logViewer:{searchPlaceholder:"Search message or logger name...",noLogEntries:"No log entries found"},switchbarPopover:{noSwitchesInSwitchbar:"No switches in switchbar"},projectPageModal:{placeholders:{title:"Title",designer:"Designer",license:"License",description:"Enter description...",profileTitle:"Profile Title",profileDescription:"Profile description..."}},spoolmanSettings:{},time:{unknown:"-",waiting:"Waiting",justNow:"Just now",now:"Now",minsAgo:"{{count}}m ago",inMins:"in {{count}}m",hoursAgo:"{{count}}h ago",inHours:"in {{count}}h",daysAgo:"{{count}}d ago",inDays:"in {{count}}d"},spoolbuddy:{nav:{dashboard:"Dashboard",ams:"AMS",inventory:"Inventory",writeTag:"Write",settings:"Settings"},status:{nfcReady:"NFC Ready",nfcOff:"NFC Off",offline:"Offline",online:"Online",noPrinters:"No printers",deviceOffline:"Device Offline",waitingConnection:"Waiting for device connection...",systemReady:"System Ready",status:"Status"},dashboard:{readyToScan:"Ready to scan",idleMessage:"Place a spool on the scale to identify it",nfcHint:"NFC tag will be read automatically",device:"Device",syncWeight:"Sync Weight",weightSynced:"Synced!",unknownTag:"Unknown Tag",newTag:"New Tag Detected",onScale:"on scale",linkSpool:"Link to Spool",linkTagTitle:"Link Tag to Spool",linkTag:"Link Tag",selectSpool:"Select a spool to link this tag to:",noUntagged:"No spools without tags found",tagDetected:"Tag detected",noTag:"No tag",tagId:"Tag",grossWeight:"Gross weight",spoolSize:"Spool size",close:"Close",currentSpool:"Current Spool"},modal:{spoolDetected:"Spool Detected",assignToAms:"Assign to AMS",syncWeight:"Sync Weight",weightSynced:"Synced!",syncing:"Syncing...",newTagDetected:"New Tag Detected",addToInventory:"Add to Inventory",assignToAmsTitle:"Assign to AMS",selectSlot:"Select a slot",assign:"Assign",assigning:"Assigning...",assignSuccess:"Assigned!",assignError:"Failed to assign spool. Please try again.",noPrinterSelected:"Select a printer...",noAmsDetected:"No AMS detected on this printer",slot:"Slot"},weight:{noReading:"No reading",stable:"Stable",measuring:"Measuring...",tare:"Tare",calibrate:"Calibrate"},spool:{remaining:"Remaining",material:"Material",brand:"Brand",color:"Color",coreWeight:"Core",labelWeight:"Label",scaleWeight:"Scale",netWeight:"Net",lastUsed:"Last used"},ams:{noData:"No AMS detected",connectAms:"Connect an AMS to see filament slots",noPrinter:"No printer selected",selectPrinter:"Select a printer from the top bar",printerDisconnected:"Printer disconnected",humidity:"Humidity",level:"Level",active:"Active",slot:"Slot",empty:"Empty"},inventory:{search:"Search spools...",empty:"No spools in inventory",noResults:"No matching spools",spools:"spools",addSpool:"Add Spool"},settings:{tabDevice:"Device",tabDisplay:"Display",tabScale:"Scale",tabUpdates:"Updates",nfcReader:"NFC Reader",type:"Type",connection:"Connection",notConnected:"N/A",deviceInfo:"Device Info",hostname:"Host",uptime:"Uptime",systemConfig:"Backend & Auth",backendUrl:"Bambuddy Backend URL",apiToken:"API Token",apiTokenPlaceholder:"Enter API token",saveConfig:"Save Config",systemQueued:"Config queued.",nfcDiagnostic:"NFC Diagnostic",scaleDiagnostic:"Scale Diagnostic",readTagDiagnostic:"Read Tag Diagnostic",testNfc:"Test reader",testScale:"Test accuracy",testReadTag:"Read tag",systemFieldsRequired:"Backend URL is required.",brightness:"Brightness",saved:"Saved",noBacklight:"No DSI backlight detected. Brightness control requires a DSI display.",screenBlank:"Screen Blank Timeout",screenBlankDesc:"Screen turns off after inactivity. Touch to wake.",displayNote:"Brightness is applied as a software filter.",scaleCalibration:"Scale Calibration",currentWeight:"Current weight",tareOffset:"Tare",calFactor:"Factor",knownWeight:"Known weight",calStep1:"Remove all items from the scale and press Set Zero.",calStep2:"Place known weight on scale.",setZero:"Set Zero",calibrateNow:"Calibrate",calibrated:"Calibrated",tareSet:"Tare command sent. Waiting for device...",tareFailed:"Failed to send tare command",zeroSet:"Zero point set. Place known weight on scale.",calibrationDone:"Calibration complete!",calibrationFailed:"Calibration failed",lastCalibrated:"Last calibrated",stable:"Stable",settling:"Settling...",firmware:"Firmware",scale:"Scale",noDevice:"No SpoolBuddy device found",daemonVersion:"Daemon Version",currentVersion:"Current",versionPending:"Waiting for daemon...",checking:"Checking...",checkUpdates:"Check for Updates",updateAvailable:"Update available",updateInstructions:"Update via SSH: run the SpoolBuddy install script to upgrade.",upToDate:"Up to date",includeBeta:"Include beta versions"},writeTag:{tabExisting:"Existing Spool",tabNew:"New Spool",tabReplace:"Replace Tag",searchPlaceholder:"Search by material, color, brand...",noUntaggedSpools:"No spools without tags",noTaggedSpools:"No spools with tags",selectSpool:"Select a spool, then place a blank NTAG on the reader",placeTag:"Place an NTAG on the reader",tagReady:"Tag detected — ready to write",writeTag:"Write Tag",replaceTag:"Replace Tag",writing:"Writing tag...",waiting:"Waiting for SpoolBuddy...",writeSuccess:"Tag written successfully!",writeFailed:"Write failed",queueFailed:"Failed to queue write command",tryAgain:"Try Again",cancel:"Cancel",replaceWarning:"Old tag will be unlinked. New tag will replace it.",deviceOffline:"SpoolBuddy is offline",material:"Material",colorName:"Color Name",color:"Color",brand:"Brand",weight:"Weight (g)",createSpool:"Create Spool",creating:"Creating...",spoolCreated:"Spool created! Ready to write.",createFailed:"Failed to create spool"},quickMenu:{printerPower:"Printer Power",systemControls:"System",restartDaemon:"Restart Daemon",restartBrowser:"Restart Browser",reboot:"Reboot",shutdown:"Shutdown",swipeToClose:"Swipe down to close",confirmTitle:"Confirm",confirmShutdown:"Are you sure you want to shut down the SpoolBuddy? You will need physical access to turn it back on.",confirmReboot:"Are you sure you want to reboot the SpoolBuddy?",confirmRestartDaemon:"Restart the SpoolBuddy daemon? NFC and scale will be temporarily unavailable.",confirmRestartBrowser:"Restart the kiosk browser? The display will briefly go blank.",confirm:"Confirm",confirmPlugOn:"Turn on {{name}}?",confirmPlugOff:"Turn off {{name}}?",turnOn:"Turn On",turnOff:"Turn Off"}},bugReport:{title:"Report a Bug",description:"Description",descriptionPlaceholder:"What went wrong? Please describe the issue...",email:"Email (optional)",emailPlaceholder:"your@email.com",emailPrivacy:"If provided, your email will be included in a collapsed section of the GitHub issue so the maintainer can follow up.",screenshot:"Screenshot",uploadOrPaste:"Upload, paste, or drag an image",dataCollectedSummary:"What data is included in the report?",dataIncluded:"Included:",dataIncludedList:"App version, OS, architecture, Python version, database stats (counts only), printer models, nozzle counts, firmware versions, connectivity status, integration status (Spoolman, MQTT, HA), non-sensitive settings, network interface count, Docker details, dependency versions.",dataNeverIncluded:"Never included:",dataNeverIncludedList:"Printer names, serial numbers, access codes, passwords, IP addresses, email addresses, API keys, tokens, webhook URLs, hostnames, or usernames.",submit:"Submit",startLogging:"Start Debug Logging",stepEnableLogging:"Debug logging enabled",stepReproduce:"Reproduce the issue now",stepStopLogging:"Stop & submit report",stopAndSubmit:"Stop & Submit",maxDuration:"Auto-stops after {{minutes}} min",stoppingLogs:"Collecting logs & submitting...",submitting:"Submitting bug report...",submitSuccess:"Bug report submitted successfully!",submitFailed:"Failed to submit bug report",thankYou:"Thank you!",submitted:"Your bug report has been submitted.",viewIssue:"View Issue",unexpectedError:"An unexpected error occurred"},failureDetection:{title:"AI Failure Detection",description:"Monitor prints with a self-hosted Obico ML API and act on detected failures automatically.",mlUrl:"Obico ML API URL",mlUrlHint:"Base URL of your self-hosted Obico ml_api container (e.g. http://192.168.1.10:3333).",test:"Test",testSuccess:"ML API reachable and healthy.",testFailed:"Could not reach the ML API.",sensitivity:"Sensitivity",sensitivityLow:"Low (fewer false positives)",sensitivityMedium:"Medium (balanced)",sensitivityHigh:"High (detect early, more false positives)",sensitivityHint:"Adjusts the confidence thresholds that trigger warnings and failures.",action:"Action on detected failure",actionNotify:"Notify only",actionPause:"Pause print",actionPauseOff:"Pause and cut power",pollInterval:"Poll interval (seconds)",pollIntervalHint:"How often to check each printer while it is printing. Minimum 5s, maximum 120s.",externalUrlMissing:"External URL is not set.",externalUrlHint:"The ML API fetches the camera snapshot by URL. Set the External URL in General settings so the ML API container can reach Bambuddy.",perPrinterTitle:"Monitored Printers",perPrinterHint:"Choose which printers the detection service watches.",monitorAll:"Monitor all connected printers",statusTitle:"Status",serviceRunning:"Service running",thresholds:"Low / High thresholds",activePrinters:"Active prints",noActivePrints:"No prints currently running.",historyTitle:"Recent Detections",noHistory:"No detections yet."}},Vue={nav:{printers:"Drucker",archives:"Archiv",queue:"Warteschlange",stats:"Statistiken",profiles:"Profile",maintenance:"Wartung",projects:"Projekte",inventory:"Filament",files:"Dateimanager",notifications:"Benachrichtigungen",settings:"Einstellungen",system:"System",collapseSidebar:"Seitenleiste einklappen",expandSidebar:"Seitenleiste ausklappen",update:"Update",updateAvailable:"Update verfügbar: v{{version}}",updateAvailableBanner:"Version {{version}} ist verfügbar!",viewUpdate:"Update anzeigen",viewOnGithub:"Auf GitHub ansehen",keyboardShortcuts:"Tastaturkürzel (?)",switchToLight:"Zum hellen Modus wechseln",switchToDark:"Zum dunklen Modus wechseln",smartSwitches:"Smart Switches",logout:"Abmelden"},common:{save:"Speichern",saving:"Speichern...",cancel:"Abbrechen",delete:"Löschen",edit:"Bearbeiten",add:"Hinzufügen",close:"Schließen",confirm:"Bestätigen",loading:"Lädt...",error:"Fehler",success:"Erfolg",warning:"Warnung",enabled:"Aktiviert",disabled:"Deaktiviert",yes:"Ja",no:"Nein",on:"An",off:"Aus",all:"Alle",none:"Keine",search:"Suchen",filter:"Filtern",sort:"Sortieren",refresh:"Aktualisieren",download:"Herunterladen",upload:"Hochladen",uploading:"Hochladen...",uploadFailed:"Hochladen fehlgeschlagen",actions:"Aktionen",status:"Status",name:"Name",description:"Beschreibung",date:"Datum",time:"Zeit",hours:"Stunden",minutes:"Minuten",seconds:"Sekunden",days:"Tage",enable:"Aktivieren",disable:"Deaktivieren",permissions:"Berechtigungen",noPrinters:"Keine Drucker konfiguriert",noData:"Keine Daten verfügbar",linkNotFound:"Link nicht gefunden",required:"Erforderlich",optional:"Optional",dismiss:"Schließen",apply:"Anwenden",reset:"Zurücksetzen",export:"Exportieren",import:"Importieren",clear:"Leeren",selectAll:"Alle auswählen",deselectAll:"Auswahl aufheben",noChange:"— Keine Änderung —",unchanged:"Unverändert",unassigned:"Nicht zugewiesen",unknown:"Unbekannt",unknownError:"Unbekannter Fehler",today:"Heute",tomorrow:"Morgen",asap:"Sofort",overdue:"Überfällig",now:"Jetzt",collapse:"Einklappen",expand:"Ausklappen",viewArchive:"Archiv anzeigen",viewInFileManager:"Im Dateimanager anzeigen",addedBy:"Hinzugefügt von {{username}}",prints:"Drucke",more:"+{{count}} weitere",ascending:"Aufsteigend",descending:"Absteigend",back:"Zurück",copy:"Kopieren",copied:"Kopiert!",printer:"Drucker",remove:"Entfernen",type:"Typ",print:"Drucken",rename:"Umbenennen",move:"Verschieben",create:"Erstellen",duplicate:"Duplizieren",left:"Links",right:"Rechts"},printers:{title:"Drucker",addPrinter:"Drucker hinzufügen",editPrinter:"Drucker bearbeiten",deletePrinter:"Drucker löschen",printerName:"Druckername",serialNumber:"Seriennummer",ipAddress:"IP-Adresse / Hostname",accessCode:"Zugangscode",model:"Modell",nozzleCount:"Düsenanzahl",autoArchive:"Automatische Archivierung",status:{available:"Verfügbar",idle:"Bereit",printing:"Druckt",paused:"Pausiert",offline:"Offline",problem:"Problem",error:"Fehler",finished:"Fertig",unknown:"Unbekannt"},temperatures:{nozzle:"Düse",bed:"Druckbett",chamber:"Kammer"},progress:"{{percent}}% abgeschlossen",timeRemaining:"Noch {{time}}",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen?',maintenanceOk:"Wartung OK",maintenanceWarning:"{{count}} Warnung",maintenanceWarning_plural:"{{count}} Warnungen",maintenanceDue:"{{count}} fällig",maintenanceDue_plural:"{{count}} fällig",sort:{name:"Name",status:"Status",model:"Modell",location:"Standort",ascending:"Aufsteigend sortieren",descending:"Absteigend sortieren"},cardSize:{small:"Kleine Karten",medium:"Mittlere Karten",large:"Große Karten",extraLarge:"Extra große Karten"},hideOffline:"Offline ausblenden",nextAvailable:"Nächster verfügbar",powerOn:"Einschalten",offlinePrintersWithPlugs:"Offline-Drucker mit Smart-Plugs",noPrintersConfigured:"Noch keine Drucker konfiguriert",search:"Drucker suchen...",noSearchResults:"Keine Drucker entsprechen deiner Suche oder deinen Filtern",filter:{allStatuses:"Alle Status",allLocations:"Alle Standorte"},readyToPrint:"Druckbereit",external:"Extern",extL:"Ext-L",extR:"Ext-R",deleteArchives:"Druckarchive löschen",noLabel:"Keine Bezeichnung",printPreview:"Druckvorschau",width:"Breite",height:"Höhe",noObjectsFound:"Keine Objekte gefunden",objectsLoadedOnPrintStart:"Objekte werden beim Druckstart geladen",willBeSkipped:"Wird übersprungen",name:"Name",serialCannotBeChanged:"Seriennummer kann nicht geändert werden",locationHelp:"Dient zur Gruppierung von Druckern und zum Filtern von Warteschlangenaufträgen",wifiSignal:{veryWeak:"Sehr schwach",weak:"Schwach",fair:"Ausreichend",good:"Gut",excellent:"Ausgezeichnet"},maintenanceUpToDate:"Alle Wartungen aktuell - Klicken zum Anzeigen",chamberLightOn:"Kammerbeleuchtung einschalten",chamberLightOff:"Kammerbeleuchtung ausschalten",files:"Dateien",browseFiles:"Druckerdateien durchsuchen",autoOffAfterPrint:"Automatisches Ausschalten nach Druck",autoOffExecuted:"Auto-off wurde ausgeführt - Drucker einschalten zum Zurücksetzen",hmsErrors:"HMS-Fehler",viewHmsErrors:"{{count}} HMS-Fehler anzeigen",resume:"Fortsetzen",pause:"Pausieren",stop:"Stoppen",camera:"Kamera",skipObject:"Objekt überspringen",reconnect:"Neu verbinden",forceRefresh:"Aktualisierung erzwingen",forceRefreshSuccess:"Aktualisierung angefordert",mqttDebug:"MQTT-Debug",printerInformation:"Druckerinformationen",copyToClipboard:"Kopieren",copied:"Kopiert!",state:"Zustand",wifiSignalLabel:"WLAN-Signal",developerMode:"Entwicklermodus",enabled:"Aktiviert",disabled:"Deaktiviert",addedOn:"Hinzugefügt",sdCard:"SD-Karte",inserted:"Eingelegt",notInserted:"Nicht eingelegt",totalPrintHours:"Druckstunden",activeNozzle:"Aktiv: {{nozzle}} Düse",nozzleRack:"Düsenhalter",nozzleDocked:"Angedockt",nozzleMounted:"Montiert",nozzleActive:"Aktiv",nozzleIdle:"Inaktiv",nozzleDiameter:"Durchmesser",nozzleType:"Typ",nozzleStatus:"Status",nozzleFilament:"Filament",nozzleWear:"Verschleiß",nozzleMaxTemp:"Max Temp",nozzleSerial:"Seriennr.",nozzleHardenedSteel:"Gehärteter Stahl",nozzleStainlessSteel:"Edelstahl",nozzleTungstenCarbide:"Wolframkarbid",nozzleFlow:"Durchfluss",nozzleHighFlow:"High Flow",nozzleStandardFlow:"Standard",firmwareUpdate:"Firmware-Update",firmwareInstructions:"Gehen Sie auf dem Touchscreen des Druckers zu",firmwareNav:"Navigieren Sie zu",settings:"Einstellungen",firmware:"Firmware",discoverPrinters:"Drucker entdecken",searching:"Suche...",manualEntry:"Manuelle Eingabe",addFromCloud:"Aus Cloud hinzufügen",toast:{printerDeleted:"Drucker gelöscht",missingSpoolAssignment:"Druck gestartet auf {{printer}}. Fehlende Spulenzuordnung für: {{slots}}",printerAdded:"Drucker hinzugefügt",printerUpdated:"Drucker aktualisiert",failedToDelete:"Drucker konnte nicht gelöscht werden",failedToAdd:"Drucker konnte nicht hinzugefügt werden",failedToUpdate:"Drucker konnte nicht aktualisiert werden",commandSent:"Befehl gesendet",failedToSendCommand:"Befehl konnte nicht gesendet werden",turnedOn:"{{name}} eingeschaltet",failedToPowerOn:"{{name}} konnte nicht eingeschaltet werden",scriptTriggered:"Skript ausgelöst",printStopped:"Druck gestoppt",printPaused:"Druck pausiert",printResumed:"Druck fortgesetzt",referenceDeleted:"Referenz gelöscht",detectionAreaSaved:"Erkennungsbereich gespeichert",failedToRunScript:"Skript konnte nicht ausgeführt werden",failedToStopPrint:"Druck konnte nicht gestoppt werden",failedToPausePrint:"Druck konnte nicht pausiert werden",failedToResumePrint:"Druck konnte nicht fortgesetzt werden",failedToControlChamberLight:"Kammerbeleuchtung konnte nicht gesteuert werden",failedToSetSpeed:"Druckgeschwindigkeit konnte nicht eingestellt werden",failedToUpdateSetting:"Einstellung konnte nicht aktualisiert werden",failedToSkipObjects:"Objekte konnten nicht übersprungen werden",failedToRereadRfid:"RFID konnte nicht erneut gelesen werden",failedToCheckPlate:"Platte konnte nicht überprüft werden",failedToUpdateLabel:"Bezeichnung konnte nicht aktualisiert werden",failedToDeleteReference:"Referenz konnte nicht gelöscht werden",failedToSaveDetectionArea:"Erkennungsbereich konnte nicht gespeichert werden",plateCheckEnabled:"Plattenprüfung aktiviert",plateCheckDisabled:"Plattenprüfung deaktiviert",calibrationSaved:"Kalibrierung gespeichert!",calibrationFailed:"Kalibrierung fehlgeschlagen",rfidRereadInitiated:"RFID-Neueinlesen gestartet"},connection:{connected:"Verbunden",offline:"Offline"},plateStatus:{markCleared:"Platte als freigegeben markieren",cleared:"Platte freigegeben",notCleared:"Platte nicht freigegeben",inUse:"Platte in Benutzung"},queue:{inQueue:"{{count}} Druck in Warteschlange",inQueue_plural:"{{count}} Drucke in Warteschlange"},controls:"Steuerung",rfid:{reread:"RFID neu lesen"},bedJog:{title:"Druckbett bewegen",bed:"Bett",step:"Schritt (mm)",up:"Platte hoch",down:"Platte runter",disabledWhilePrinting:"Während des Drucks deaktiviert",notHomedTitle:"Drucker ist nicht referenziert",notHomedMessage:"Die Z-Achse wurde seit dem letzten Druck nicht referenziert. Referenzieren Sie Z zuerst für eine sichere Positionierung oder bewegen Sie trotzdem — die Software-Endschalter werden dabei umgangen.",homeZ:"Z referenzieren",moveAnyway:"Trotzdem bewegen",homingStarted:"Z-Achse wird referenziert…"},permission:{noAdd:"Sie haben keine Berechtigung, Drucker hinzuzufügen",noEdit:"Sie haben keine Berechtigung, Drucker zu bearbeiten",noDelete:"Sie haben keine Berechtigung, Drucker zu löschen",noControl:"Sie haben keine Berechtigung, Drucker zu steuern",noFiles:"Sie haben keine Berechtigung, auf Druckerdateien zuzugreifen",noAmsRfid:"Sie haben keine Berechtigung, AMS-RFID erneut zu lesen",noSmartPlugControl:"Sie haben keine Berechtigung, Smart Plugs zu steuern",noCamera:"Sie haben keine Berechtigung, Kameras anzuzeigen"},modal:{addTitle:"Drucker hinzufügen",editTitle:"Drucker bearbeiten",myPrinter:"Mein Drucker",selectModel:"Modell auswählen...",locationGroup:"Standort / Gruppe (optional)",locationPlaceholder:"z.B. Werkstatt, Büro, Keller",autoArchiveLabel:"Abgeschlossene Drucke automatisch archivieren",fromPrinterSettings:"Aus Druckereinstellungen",modelOptional:"Modell (optional)",saveChanges:"Änderungen speichern"},skipObjects:{tooltip:"Objekte überspringen",onlyWhilePrinting:"Objekte überspringen (nur während des Drucks)",requiresMultiple:"Objekte überspringen (erfordert 2+ Objekte)",title:"Objekte überspringen",matchIdsInfo:"IDs mit Drucker-Display abgleichen",printerShowsIds:"Der Druckerbildschirm zeigt Objekt-IDs auf der Bauplatte",skipSelected:"Ausgewählte überspringen",skipping:"Überspringe...",noObjectsSelected:"Keine Objekte ausgewählt",selectObjectsToSkip:"Wählen Sie Objekte aus, die Sie vom aktuellen Druck überspringen möchten",skipped:"übersprungen",objectsSkipped:"Objekte übersprungen",activeCount:"{{count}} aktiv",waitForLayer:"Warten Sie auf Schicht 2+ zum Überspringen von Objekten (aktuell Schicht {{layer}})",skip:"Überspringen",confirmTitle:"Objekt überspringen?",confirmMessage:'Möchten Sie "{{name}}" wirklich überspringen? Dies kann nicht rückgängig gemacht werden.'},confirm:{deleteTitle:"Drucker löschen",deleteMessage:'Möchten Sie "{{name}}" wirklich löschen? Alle Verbindungseinstellungen werden entfernt.',deleteArchivesNote:"Der gesamte Druckverlauf für diesen Drucker wird dauerhaft gelöscht.",keepArchivesNote:"Der Druckverlauf wird beibehalten, aber nicht mehr mit diesem Drucker verknüpft.",stopTitle:"Druck stoppen",stopMessage:'Möchten Sie den aktuellen Druck auf "{{name}}" wirklich stoppen? Der Druckauftrag wird abgebrochen.',stopButton:"Druck stoppen",pauseTitle:"Druck pausieren",pauseMessage:'Möchten Sie den aktuellen Druck auf "{{name}}" wirklich pausieren?',pauseButton:"Druck pausieren",resumeTitle:"Druck fortsetzen",resumeMessage:'Möchten Sie den Druck auf "{{name}}" fortsetzen?',resumeButton:"Druck fortsetzen",powerOnTitle:"Drucker einschalten",powerOnMessage:'Möchten Sie die Stromversorgung für "{{name}}" wirklich EINSCHALTEN?',powerOnButton:"Einschalten",powerOffTitle:"Drucker ausschalten",powerOffMessage:'Möchten Sie die Stromversorgung für "{{name}}" wirklich AUSSCHALTEN?',powerOffWarning:'WARNUNG: "{{name}}" druckt gerade! Möchten Sie die Stromversorgung wirklich AUSSCHALTEN? Dies unterbricht den Druck und kann den Drucker beschädigen.',powerOffButton:"Ausschalten"},bulk:{select:"Auswählen",selectAll:"Alle auswählen",selectByLocation:"Nach Standort auswählen",selected:"{{count}} ausgewählt",actions:{stop:"Stoppen",pause:"Pausieren",resume:"Fortsetzen",clearPlate:"Druckbett leeren",clearHMS:"Benachrichtigungen löschen"},confirm:{stopTitle:"{{count}} Drucke stoppen",stopMessage:"Dies wird aktive Drucke auf {{count}} Drucker(n) abbrechen. Diese Aktion kann nicht rückgängig gemacht werden.",stopButton:"Alle stoppen",pauseTitle:"{{count}} Drucke pausieren",pauseMessage:"Dies wird aktive Drucke auf {{count}} Drucker(n) pausieren.",pauseButton:"Alle pausieren",clearPlateTitle:"{{count}} Druckbetten leeren",clearPlateMessage:"Dies wird das Druckbett auf {{count}} Drucker(n) leeren und kann wartende Aufträge starten.",clearPlateButton:"Alle leeren"},success:"{{action}} auf {{count}} Drucker(n) abgeschlossen",partial:"{{succeeded}} erfolgreich, {{failed}} fehlgeschlagen",noneApplicable:"Keine ausgewählten Drucker sind im richtigen Zustand für diese Aktion",selectByState:"Nach Status auswählen"},discovery:{title:"Drucker entdecken",searching:"Suche...",scanning:"Scanne...",scanProgress:"Scanne... {{scanned}}/{{total}}",foundPrinters:"{{count}} Drucker gefunden",noPrintersFound:"Keine Drucker gefunden",noPrintersFoundSubnet:"Keine Drucker im angegebenen Subnetz gefunden.",noPrintersFoundNetwork:"Keine Drucker im Netzwerk gefunden.",allConfigured:"Alle erkannten Drucker sind bereits konfiguriert.",alreadyAdded:"Bereits hinzugefügt",select:"Auswählen",manualEntry:"Manuelle Eingabe",addFromCloud:"Aus Cloud hinzufügen",subnetToScan:"Zu scannendes Subnetz",dockerNote:"Docker erkannt. Geben Sie das Subnetz Ihres Druckers in CIDR-Notation ein. Erfordert network_mode: host in docker-compose.yml.",scanSubnet:"Subnetz nach Druckern scannen",discoverNetwork:"Drucker im Netzwerk suchen",scanningSubnet:"Subnetz wird nach Bambu-Druckern gescannt...",scanningNetwork:"Netzwerk wird gescannt...",serialRequired:"Seriennummer erforderlich",unknown:"Unbekannt",failedToStart:"Erkennung konnte nicht gestartet werden"},drying:{start:"Trocknung starten",stop:"Trocknung stoppen",temperature:"Temperatur",duration:"Dauer",hours:"Stunden",timeRemaining:"{{time}} verbleibend",active:"Trocknung",notSupported:"Trocknung nicht unterstützt",powerRequired:"AMS-Netzteil anschließen, um Trocknung zu aktivieren",startingDrying:"Trocknung wird gestartet...",stoppingDrying:"Trocknung wird gestoppt...",rotateTray:"Spule während der Trocknung drehen"},filaments:"Filamente",openCameraOverlay:"Kamera-Overlay öffnen",openCameraWindow:"Kamera in neuem Fenster öffnen",firmwareUpdateAvailable:"Firmware-Update verfügbar: {{current}} → {{latest}}",firmwareUpToDate:"Firmware {{version}} — Aktuell",firmwareUpdateButton:"Update",plateDetection:{noPermission:"Sie haben keine Berechtigung, Drucker zu aktualisieren",enabledClick:"Plattenprüfung aktiviert - Klicken zum Deaktivieren",disabledClick:"Plattenprüfung deaktiviert - Klicken zum Aktivieren",manageCalibration:"Platten-Erkennungskalibrierung verwalten",calibrationRequired:"Kalibrierung erforderlich",calibrationInstructions:"Bitte stellen Sie sicher, dass die Druckplatte vollständig leer ist, und klicken Sie dann auf Kalibrieren.",calibrationDescription:"Die Kalibrierung erfasst ein Referenzbild der leeren Platte. Zukünftige Prüfungen vergleichen mit dieser Referenz, um Objekte zu erkennen.",calibrationTip:"Tipp: Sie können bis zu 5 Kalibrierungen für verschiedene Platten speichern. Das System verwendet automatisch die beste Übereinstimmung bei der Prüfung.",plateEmpty:"Platte erscheint leer",objectsDetected:"Objekte auf Platte erkannt",confidence:"Konfidenz",difference:"Differenz",analysisPreview:"Analysevorschau:",analysisLegend:"Grüner Rahmen = Erkennungsbereich, Rote Überlagerung = Unterschiede zur Kalibrierung",savedReferences:"Gespeicherte Referenzen ({{count}}/{{max}})",deleteReference:"Referenz löschen",labelPlaceholder:"Bezeichnung...",clickToEdit:"{{label}} - Zum Bearbeiten klicken",clickToAddLabel:"Zum Hinzufügen einer Bezeichnung klicken"},speed:{title:"Druckgeschwindigkeit",silent:"Leise (50%)",standard:"Standard (100%)",sport:"Sport (124%)",ludicrous:"Ludicrous (166%)"},airduct:{title:"Luftkanal-Modus",cooling:"Kühlen",heating:"Heizen"},noSdCard:"Keine SD",door:{open:"Offen",closed:"Zu"},fans:{partCooling:"Bauteilkühlung",auxiliary:"Hilfsventilator",chamber:"Kammerventilator"},clickToViewHmsErrors:"Klicken, um HMS-Fehler anzuzeigen",estimatedCompletion:"Geschätzte Fertigstellungszeit",plateNumber:"Platte {{number}}",slotOptions:"Slot-Optionen",amsPopup:{friendlyName:"AMS-Name",friendlyNamePlaceholder:"z. B. AMS-Anzeigename",serialNumber:"Seriennummer",firmwareVersion:"Firmware",save:"Speichern",clear:"Löschen",noEditPermission:"Sie haben keine Berechtigung, AMS-Einheiten umzubenennen"},firmwareModal:{title:"Firmware-Update",titleUpToDate:"Firmware-Info",currentVersion:"Aktuell:",latestVersion:"Neueste:",releaseNotes:"Versionshinweise",checkingPrereqs:"Prüfe Voraussetzungen...",sdCardReady:"SD-Karte bereit. Klicken Sie unten, um die Firmware hochzuladen.",uploadedSuccess:"Firmware auf SD-Karte hochgeladen!",applyInstructions:"So wenden Sie das Update auf Ihrem Drucker an:",step1:"Gehen Sie auf dem Touchscreen des Druckers zu Einstellungen",step2:"Navigieren Sie zu Firmware",step3:"Wählen Sie Update von SD-Karte",step4:"Das Update dauert 10-20 Minuten",done:"Fertig",starting:"Starte...",uploadFirmware:"Firmware hochladen",uploadFailed:"Upload fehlgeschlagen: {{error}}",uploadedToast:"Firmware hochgeladen! Starten Sie das Update vom Druckerbildschirm.",availableVersions:"Verfügbare Versionen",usable:"Installierbar",unavailable:"Nicht verfügbar",installed:"Installiert",newerBadge:"neuer",olderBadge:"älter",currentBadge:"aktuell"},accessCodePlaceholder:"Leer lassen, um den aktuellen zu behalten",roi:{title:"Erkennungsbereich (ROI)",xStart:"X-Start",yStart:"Y-Start",width:"Breite",height:"Höhe",instruction:"Passen Sie den Erkennungsbereich an, um sich auf die Druckplatte zu konzentrieren. Der grüne Rahmen in der Vorschau zeigt den aktuellen Bereich."},developerModeWarning:"Der Entwickler-LAN-Modus ist nicht aktiviert auf: {{names}}. Einige Funktionen funktionieren möglicherweise nicht.",howToEnable:"Aktivieren",incompatibleFile:"Diese Datei wurde für {{slicedFor}} geslicet, aber dieser Drucker ist ein {{printerModel}}",dropNotPrintable:"Nur .gcode- und .gcode.3mf-Dateien können gedruckt werden",dropToPrint:"Zum Drucken ablegen",cannotPrint:"Drucker beschäftigt"},archives:{title:"Druckarchiv",searchPlaceholder:"Archiv durchsuchen...",filterByPrinter:"Nach Drucker filtern",filterByStatus:"Nach Status filtern",sortBy:"Sortieren nach",sortNewest:"Neueste zuerst",sortOldest:"Älteste zuerst",sortName:"Name",sortDuration:"Dauer",sortLargest:"Größte zuerst",sortSmallest:"Kleinste zuerst",sortSize:"Größe",noArchives:"Keine Archive gefunden",noArchivesSearch:"Keine Archive entsprechen Ihrer Suche",originalPrintNotVisible:"Ursprünglicher Druck nicht sichtbar - versuchen Sie, die Filter zu löschen",noArchivesYet:"Noch keine Archive",prints:"Drucke",pagination:{showing:"Zeige",to:"bis",of:"von",show:"Zeige",page:"Seite",all:"Alle"},loadingArchives:"Lade Archive...",releaseToUpload:"Loslassen zum Hochladen",showAll:"Alle anzeigen",showFavoritesOnly:"Nur Favoriten anzeigen",gridView:"Rasteransicht",listView:"Listenansicht",calendarView:"Kalenderansicht",logView:"Druckprotokoll",manageTags:"Tags verwalten",showFailedPrints:"Fehlgeschlagene Drucke anzeigen",hideFailedPrints:"Fehlgeschlagene Drucke ausblenden",hideDuplicates:"Duplikate ausblenden",viewOriginalPrint:"Klicken, um den ursprünglichen Druck anzuzeigen (#{{id}})",printTime:"Druckzeit",filamentUsed:"Verbrauchtes Filament",cost:"Kosten",reprint:"Drucken",preview:"Vorschau",deleteArchive:"Archiv löschen",deleteConfirm:"Möchten Sie dieses Archiv wirklich löschen?",favorite:"Favorit",unfavorite:"Aus Favoriten entfernen",viewDetails:"Details anzeigen",status:{completed:"Abgeschlossen",failed:"Fehlgeschlagen",stopped:"Gestoppt"},toast:{source3mfAttached:"Quell-3MF angehängt: {{filename}}",failedUploadSource3mf:"Fehler beim Hochladen der Quell-3MF",source3mfRemoved:"Quell-3MF entfernt",failedRemoveSource3mf:"Fehler beim Entfernen der Quell-3MF",f3dAttached:"F3D angehängt: {{filename}}",failedUploadF3d:"Fehler beim Hochladen der F3D",f3dRemoved:"F3D entfernt",failedRemoveF3d:"Fehler beim Entfernen der F3D",timelapseAttached:"Zeitraffer angehängt: {{filename}}",timelapseAlreadyAttached:"Zeitraffer bereits angehängt",noMatchingTimelapse:"Kein passender Zeitraffer gefunden",failedScanTimelapse:"Fehler beim Suchen nach Zeitraffer",failedAttachTimelapse:"Fehler beim Anhängen des Zeitraffers",timelapseRemoved:"Zeitraffer entfernt",failedRemoveTimelapse:"Fehler beim Entfernen des Zeitraffers",timelapseUploaded:"Zeitraffer hochgeladen: {{filename}}",failedUploadTimelapse:"Fehler beim Hochladen des Zeitraffers",archiveDeleted:"Archiv gelöscht",failedDeleteArchive:"Fehler beim Löschen des Archivs",addedToFavorites:"Zu Favoriten hinzugefügt",removedFromFavorites:"Aus Favoriten entfernt",projectUpdated:"Projekt aktualisiert",failedUpdateProject:"Fehler beim Aktualisieren des Projekts",linkCopied:"Link in die Zwischenablage kopiert",failedCopyLink:"Fehler beim Kopieren des Links",photoDeleted:"Foto gelöscht",failedDeletePhoto:"Fehler beim Löschen des Fotos",failedDeleteArchives:"Fehler beim Löschen der Archive",failedUpdateFavorites:"Fehler beim Aktualisieren der Favoriten",exportDownloaded:"Export heruntergeladen",exportFailed:"Export fehlgeschlagen"},menu:{print:"Drucken",schedule:"Planen",openInBambuStudio:"Im Slicer öffnen",slice:"Slicen",externalLink:"Externer Link",viewOnMakerWorld:"Auf MakerWorld ansehen",preview3d:"3D-Vorschau",viewTimelapse:"Zeitraffer ansehen",scanForTimelapse:"Nach Zeitraffer suchen",uploadTimelapse:"Zeitraffer hochladen",removeTimelapse:"Zeitraffer entfernen",downloadSource3mf:"Quell-3MF herunterladen",uploadSource3mf:"Quell-3MF hochladen",replaceSource3mf:"Quell-3MF ersetzen",removeSource3mf:"Quell-3MF entfernen",uploadF3d:"F3D hochladen",replaceF3d:"F3D ersetzen",downloadF3d:"F3D herunterladen",removeF3d:"F3D entfernen",download:"Herunterladen",copyDownloadLink:"Download-Link kopieren",qrCode:"QR-Code",viewPhotos:"Fotos ansehen",viewPhotosCount:"Fotos ansehen ({{count}})",projectPage:"Projektseite",addToFavorites:"Zu Favoriten hinzufügen",removeFromFavorites:"Aus Favoriten entfernen",edit:"Bearbeiten",goToProject:"Zum Projekt: {{name}}",addToProject:"Zu Projekt hinzufügen",removeFromProject:"Aus Projekt entfernen",loading:"Laden...",noProjectsAvailable:"Keine Projekte verfügbar",select:"Auswählen",deselect:"Abwählen",delete:"Löschen"},permission:{noReprint:"Sie haben keine Berechtigung, dieses Archiv erneut zu drucken",noAddToQueue:"Sie haben keine Berechtigung, zur Warteschlange hinzuzufügen",noUpdateArchives:"Sie haben keine Berechtigung, Archive zu aktualisieren",noUploadFiles:"Sie haben keine Berechtigung, Dateien hochzuladen",noDownload:"Sie haben keine Berechtigung, Archive herunterzuladen",noCopyLink:"Sie haben keine Berechtigung, Download-Links zu kopieren",noDelete:"Sie haben keine Berechtigung, dieses Archiv zu löschen",noCreate:"Sie haben keine Berechtigung, Archive zu erstellen"},card:{previousPlate:"Vorherige Platte",nextPlate:"Nächste Platte",plateNumber:"Platte {{index}}",moreOptions:"Rechtsklick für mehr Optionen",addToFavorites:"Zu Favoriten hinzufügen",removeFromFavorites:"Aus Favoriten entfernen",cancelled:"abgebrochen",failed:"fehlgeschlagen",duplicate:"Duplikat",duplicateTitle:"Dieses Modell wurde bereits zuvor gedruckt",openSource3mf:"Quell-3MF in Bambu Studio öffnen (Rechtsklick für mehr Optionen)",downloadF3d:"Fusion 360 Designdatei herunterladen",viewTimelapse:"Zeitraffer ansehen",viewPhoto:"1 Foto ansehen",viewPhotos:"{{count}} Fotos ansehen",openFolder:"Ordner öffnen: {{name}}",slicedFile:"Geslicte Datei - druckbereit",sourceFile:"Nur Quelldatei - keine AMS-Zuordnung verfügbar",gcode:"GCODE",source:"QUELLE",project:"Projekt: {{name}}",estimated:"Geschätzt: {{time}}",actual:"Tatsächlich: {{time}}",accuracy:"Genauigkeit: {{percent}}%",filament:"{{weight}}g",layer:"{{count}} Schicht",layers:"{{count}} Schichten",object:"{{count}} Objekt",objects:"{{count}} Objekte",slicedFor:"Geslict für {{model}}",uploadedBy:"Hochgeladen von",noPermissionReprint:"Sie haben keine Berechtigung, erneut zu drucken",noFileForReprint:"Keine 3MF-Datei verfügbar — die Datei konnte beim Aufzeichnen des Drucks nicht vom Drucker heruntergeladen werden",noPermissionEdit:"Sie haben keine Berechtigung, Archive zu bearbeiten",noPermissionDelete:"Sie haben keine Berechtigung, Archive zu löschen",reprint:"Drucken",schedulePrint:"Druck planen",schedule:"Planen",openInBambuStudio:"Im Slicer öffnen",openInBambuStudioToSlice:"Im Slicer öffnen zum Slicen",slice:"Slicen",externalLink:"Externer Link",makerWorld:"MakerWorld: {{designer}}",viewProject:"Projekt ansehen",noExternalLink:"Kein externer Link",preview3d:"3D-Vorschau",download:"Herunterladen",edit:"Bearbeiten",delete:"Löschen"},modal:{deleteArchive:"Archiv löschen",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.',deleteButton:"Löschen",removeSource3mf:"Quell-3MF entfernen",removeSource3mfConfirm:'Möchten Sie die Quell-3MF-Datei wirklich von "{{name}}" entfernen? Die ursprüngliche Slicer-Projektdatei wird gelöscht.',removeButton:"Entfernen",removeF3d:"F3D entfernen",removeF3dConfirm:'Möchten Sie die Fusion 360 Designdatei wirklich von "{{name}}" entfernen?',removeTimelapse:"Zeitraffer entfernen",removeTimelapseConfirm:'Möchten Sie das Zeitraffervideo wirklich von "{{name}}" entfernen?',timelapse:"{{name}} - Zeitraffer",selectTimelapse:"Zeitraffer auswählen",selectTimelapseDesc:"Keine automatische Übereinstimmung gefunden. Wählen Sie den Zeitraffer für diesen Druck:",deleteArchives:"Archive löschen",deleteArchivesConfirm:"Möchten Sie wirklich {{count}} Archiv(e) löschen? Diese Aktion kann nicht rückgängig gemacht werden.",deleteCount:"{{count}} löschen"},page:{title:"Archive",printsCount:"{{filtered}} von {{total}} Drucken",dropFilesHere:".3mf-Dateien hier ablegen",releaseToUpload:"Loslassen zum Hochladen",only3mfSupported:"Nur .3mf-Dateien werden unterstützt",close:"Schließen",selected:"{{count}} ausgewählt",selectAll:"Alle auswählen",tags:"Tags",project:"Projekt",favorite:"Favorit",delete:"Löschen",toggledFavorites:"Favoriten für {{count}} Archiv(e) umgeschaltet",failedUpdateFavorites:"Fehler beim Aktualisieren der Favoriten",archivesDeleted:"{{count}} Archiv(e) gelöscht",failedDeleteArchives:"Fehler beim Löschen der Archive",photoDeleted:"Foto gelöscht",failedDeletePhoto:"Fehler beim Löschen des Fotos"},list:{name:"Name",printer:"Drucker",date:"Datum",size:"Größe",actions:"Aktionen",hasTimelapse:"Hat Zeitraffer"},log:{date:"Datum",printName:"Druckname",printer:"Drucker",user:"Benutzer",status:"Status",duration:"Dauer",filament:"Filament",allPrinters:"Alle Drucker",allUsers:"Alle Benutzer",allStatuses:"Alle Status",cancelled:"Abgebrochen",skipped:"Übersprungen",dateFrom:"Von",dateTo:"Bis",noEntries:"Keine Druckprotokolleinträge gefunden",showing:"{{count}} von {{total}} Einträgen",rowsPerPage:"Zeilen",page:"Seite",prev:"Zurück",next:"Weiter",clearLog:"Protokoll löschen",clearLogTitle:"Druckprotokoll löschen",clearLogConfirm:"Alle Druckprotokolleinträge werden dauerhaft gelöscht. Archive und Warteschlangeneinträge sind nicht betroffen. Diese Aktion kann nicht rückgängig gemacht werden. Sind Sie sicher?",clearLogButton:"Alle löschen",cleared:"{{count}} Protokolleinträge gelöscht",clearFailed:"Druckprotokoll konnte nicht gelöscht werden"}},queue:{title:"Druckwarteschlange",subtitle:"Planen und verwalten Sie Ihre Druckaufträge",addToQueue:"Zur Warteschlange hinzufügen",print:"Drucken",reprint:"Erneut drucken",schedulePrint:"Druck planen",editQueueItem:"Warteschlangeneintrag bearbeiten",printToPrinters:"Auf {{count}} Druckern drucken",queueToPrinters:"Zu {{count}} Druckern hinzufügen",queueSelectedPlates:"{{count}} Platten in die Warteschlange",selectAllPlates:"Alle {{count}} Platten auswählen",deselectAll:"Alle abwählen",printQueued:"Druck in Warteschlange",itemsQueued:"{{count}} Einträge in Warteschlange",sending:"Wird gesendet...",sendingProgress:"Sende {{current}}/{{total}}...",adding:"Wird hinzugefügt...",addingProgress:"Füge hinzu {{current}}/{{total}}...",savingProgress:"Speichere {{current}}/{{total}}...",clearQueue:"Warteschlange leeren",clearHistory:"Verlauf löschen",emptyQueue:"Warteschlange ist leer",position:"Position",scheduledTime:"Geplante Zeit",moveUp:"Nach oben",moveDown:"Nach unten",startNow:"Jetzt starten",printingInProgress:"Druck läuft...",viewArchive:"Archiv anzeigen",viewInFileManager:"Im Dateimanager anzeigen",itemCount:"{{count}} Element",itemCount_plural:"{{count}} Elemente",dragToReorder:"Ziehen zum Neuordnen (nur Sofort)",reorderHint:"Position betrifft nur Sofort-Elemente. Geplante Elemente werden zur festgelegten Zeit ausgeführt.",sjf:{label:"SJF",tooltip:"Kürzester Auftrag zuerst — Scheduler bevorzugt kürzere Drucke"},addedBy:"Hinzugefügt von {{name}}",nextInQueue:"Nächster in der Warteschlange",clearPlate:"Druckplatte freigeben & Nächsten starten",clearPlateSuccess:"Druckplatte freigegeben — bereit für nächsten Druck",plateReady:"Druckplatte freigegeben — bereit für nächsten Druck",plateNumber:"Platte {{index}}",quantity:"Menge",quantityHint:"Erstellt {{count}} Warteschlangeneinträge",activeBatches:"Aktive Stapel",batchProgress:"{{completed}} von {{total}} abgeschlossen",cancelBatch:"Verbleibende abbrechen",batchCancelled:"Verbleibende Stapeleinträge abgebrochen",cancelBatchConfirmTitle:"Stapel abbrechen",cancelBatchConfirmMessage:"Alle verbleibenden ausstehenden Einträge in diesem Stapel abbrechen?",batch:"Stapel",sections:{currentlyPrinting:"Aktuell druckend",queued:"In Warteschlange",history:"Verlauf"},status:{pending:"Ausstehend",waiting:"Wartend",printing:"Druckt",paused:"Pausiert",completed:"Abgeschlossen",failed:"Fehlgeschlagen",skipped:"Übersprungen",cancelled:"Abgebrochen"},summary:{printing:"Druckt",queued:"In Warteschlange",totalTime:"Gesamte Wartezeit",totalWeight:"Gesamtgewicht der Warteschlange",history:"Verlauf"},filter:{allPrinters:"Alle Drucker",unassigned:"Nicht zugewiesen",allStatus:"Alle Status",allLocations:"Alle Standorte",any:"Beliebig"},sort:{byPosition:"Nach Position sortieren",byName:"Nach Name sortieren",byPrinter:"Nach Drucker sortieren",bySchedule:"Nach Zeitplan sortieren",byDate:"Nach Datum sortieren",ascendingOldest:"Aufsteigend (älteste zuerst)",descendingNewest:"Absteigend (neueste zuerst)"},badges:{staged:"Bereitgestellt",requiresPrevious:"Erfordert vorherigen Erfolg",autoPowerOff:"Automatisch ausschalten",gcodeInjection:"G-code"},empty:{title:"Keine Drucke geplant",description:'Planen Sie einen Druck von der Archivseite über die Option "Planen" im Kontextmenü oder ziehen Sie Dateien hierher.'},time:{asap:"Sofort",overdue:"Überfällig",now:"Jetzt",lessThanMinute:"In weniger als einer Minute",inMinutes:"In {{count}} Min",inHours:"In {{count}} Stunden"},actions:{stopPrint:"Druck stoppen",startPrint:"Druck starten",requeue:"Erneut einreihen"},bulkEdit:{title:"{{count}} Element bearbeiten",title_plural:"{{count}} Elemente bearbeiten",description:"Nur geänderte Einstellungen werden auf ausgewählte Elemente angewendet.",printer:"Drucker",noChange:"— Keine Änderung —",queueOptions:"Warteschlangenoptionen",staged:"Bereitgestellt (manueller Start)",autoPowerOff:"Nach Druck automatisch ausschalten",requirePrevious:"Vorherigen Erfolg erfordern",printOptions:"Druckoptionen",bedLevelling:"Bett-Nivellierung",flowCalibration:"Fluss-Kalibrierung",vibrationCalibration:"Vibrations-Kalibrierung",layerInspection:"Erste-Schicht-Prüfung",timelapse:"Zeitraffer",useAms:"AMS verwenden",applyChanges:"Änderungen übernehmen",selectAll:"Alle auswählen",deselectAll:"Auswahl aufheben",selected:"{{count}} ausgewählt",editSelected:"Ausgewählte bearbeiten",cancelSelected:"Ausgewählte abbrechen"},confirm:{cancelTitle:"Geplanten Druck abbrechen",cancelMessage:'Möchten Sie "{{name}}" wirklich abbrechen?',stopTitle:"Druck stoppen",stopMessage:'Möchten Sie den aktuellen Druck "{{name}}" wirklich stoppen? Der Druckauftrag wird am Drucker abgebrochen.',removeTitle:"Aus Verlauf entfernen",removeMessage:'Möchten Sie "{{name}}" wirklich aus dem Warteschlangenverlauf entfernen?',clearHistoryTitle:"Verlauf löschen",clearHistoryMessage:"Möchten Sie alle {{count}} Element(e) aus dem Verlauf entfernen?",cancelButton:"Druck abbrechen",stopButton:"Druck stoppen",thisPrint:"diesen Druck",thisItem:"dieses Element"},toast:{cancelled:"Warteschlangenelement abgebrochen",cancelFailed:"Element konnte nicht abgebrochen werden",removed:"Warteschlangenelement entfernt",removeFailed:"Element konnte nicht entfernt werden",stopped:"Druck gestoppt",stopFailed:"Druck konnte nicht gestoppt werden",released:"Druck in Warteschlange freigegeben",startFailed:"Druck konnte nicht gestartet werden",reorderFailed:"Warteschlange konnte nicht neu geordnet werden",historyCleared:"{{count}} Verlaufselement(e) gelöscht",clearHistoryFailed:"Verlauf konnte nicht gelöscht werden",updateFailed:"Elemente konnten nicht aktualisiert werden",bulkCancelled:"{{count}} Element(e) abgebrochen",bulkCancelFailed:"Elemente konnten nicht abgebrochen werden"},timeline:{listView:"Liste",timelineView:"Zeitstrahl",unassigned:"Nicht zugewiesen",noData:"Keine geplanten Drucke für diesen Tag",allDoneBy:"Alle Drucke voraussichtlich fertig um {{time}}",staged:"Bereitgestellt",filterAll:"Alle anzeigen",filterPrinting:"Druckend",filterQueued:"Warteschlange",time:{anyMoment:"jeden Moment",minutesLeft:"{{minutes}}m übrig",hoursLeft:"{{hours}}h übrig",hoursMinutesLeft:"{{hours}}h {{minutes}}m übrig"},day:{previous:"Vorheriger Tag",next:"Nächster Tag",today:"Heute"}},permissions:{noStopPrint:"Sie haben keine Berechtigung, Drucke zu stoppen",noStartPrint:"Sie haben keine Berechtigung, Drucke zu starten",noEdit:"Sie haben keine Berechtigung, dieses Warteschlangenelement zu bearbeiten",noCancel:"Sie haben keine Berechtigung, dieses Warteschlangenelement abzubrechen",noRequeue:"Sie haben keine Berechtigung, Elemente erneut einzureihen",noRemove:"Sie haben keine Berechtigung, dieses Warteschlangenelement zu entfernen",noClearHistory:"Sie haben keine Berechtigung, den gesamten Verlauf zu löschen",noEditItems:"Sie haben keine Berechtigung, Warteschlangenelemente zu bearbeiten",noCancelItems:"Sie haben keine Berechtigung, Warteschlangenelemente abzubrechen"}},backgroundDispatch:{unknownFile:"Unbekannte Datei",unknownPrinter:"Unbekannter Drucker",startingPrints:"Starte Drucke",progressSummary:"{{complete}}/{{total}} abgeschlossen • Geplant: {{dispatched}} • In Bearbeitung: {{processing}}",expandDetails:"Dispatch-Details ausklappen",collapseDetails:"Dispatch-Details einklappen",dismissToast:"Dispatch-Hinweis schließen",cancelDispatchJob:"Dispatch-Job abbrechen",cancel:"Abbrechen",cancelling:"Wird abgebrochen…",status:{dispatched:"Geplant",processing:"In Bearbeitung",completed:"Abgeschlossen",failed:"Fehlgeschlagen",cancelled:"Abgebrochen"},toast:{cancellingUpload:"Upload wird abgebrochen...",cancelled:"Dispatch abgebrochen",cancelFailed:"Dispatch konnte nicht abgebrochen werden",completeWithFailures:"Background Dispatch abgeschlossen: {{completed}} erfolgreich, {{failed}} fehlgeschlagen",completeSuccess:"Background Dispatch abgeschlossen: {{completed}} erfolgreich",printStartedRemaining:"{{completed}} Druck(e) gestartet, {{remaining}} weitere werden gesendet..."}},stats:{title:"Dashboard",subtitle:"Widgets zum Neuanordnen ziehen. Auf das Augensymbol klicken zum Ausblenden.",overview:"Übersicht",totalPrints:"Gesamtdrucke",successRate:"Erfolgsrate",totalPrintTime:"Gesamtdruckzeit",printTime:"Druckzeit",totalFilament:"Gesamtverbrauch Filament",filamentUsed:"Filamentverbrauch",filamentCost:"Filamentkosten",totalCost:"Gesamtkosten",energyUsed:"Energieverbrauch",energyCost:"Energiekosten",energyWarmingUpTooltip:"Die Energieerfassung sammelt noch stündliche Snapshots. Zeitraumwerte werden genau, sobald vor dem gewählten Bereich mindestens ein Snapshot vorliegt. Frühe Werte können zu niedrig sein.",averagePrintTime:"Durchschnittliche Druckzeit",printsPerDay:"Drucke pro Tag",byPrinter:"Nach Drucker",printsByPrinter:"Drucke nach Drucker",byMaterial:"Nach Material",byMonth:"Nach Monat",last7Days:"Letzte 7 Tage",last30Days:"Letzte 30 Tage",last90Days:"Letzte 90 Tage",allTime:"Gesamt",quickStats:"Schnellstatistiken",printActivity:"Druckaktivität",filamentTypes:"Filamenttypen",filamentTrends:"Filamenttrends",failureAnalysis:"Fehleranalyse",timeAccuracy:"Zeitgenauigkeit",successful:"Erfolgreich:",failed:"Fehlgeschlagen:",perfectEstimate:"100% = perfekte Schätzung",noTimeAccuracyData:"Noch keine Zeitgenauigkeitsdaten",noFilamentData:"Keine Filamentdaten verfügbar",noPrinterData:"Keine Druckerdaten verfügbar",noPrintData:"Keine Druckdaten verfügbar",noPrintDataLast30Days:"Keine Druckdaten in den letzten 30 Tagen",failureReasons:"Fehlerursachen",topFailureReasons:"Häufigste Fehlerursachen",failedPrintsCount:"{{failed}} / {{total}} Drucke fehlgeschlagen",lastWeekRate:"Letzte Woche: {{rate}}%",resetLayout:"Layout zurücksetzen",recalculateCosts:"Kosten neu berechnen",recalculateCostsHint:"Alle Archivkosten mit aktuellen Filamentpreisen neu berechnen",exportStats:"Statistiken exportieren",exportAsCsv:"Als CSV exportieren",exportAsExcel:"Als Excel exportieren",hiddenCount:"{{count}} ausgeblendet",exportDownloaded:"Export heruntergeladen",exportFailed:"Export fehlgeschlagen",layoutReset:"Layout zurückgesetzt",recalculatedCosts:"Kosten für {{count}} Archive neu berechnet",recalculateFailed:"Kosten konnten nicht neu berechnet werden",loadingStats:"Statistiken werden geladen...",noPermissionResetLayout:"Sie haben keine Berechtigung, das Layout zurückzusetzen",noPermissionRecalculate:"Sie haben keine Berechtigung, Kosten neu zu berechnen",noPrintDataInRange:"Keine Druckdaten im ausgewählten Zeitraum",periodFilament:"Filamentverbrauch",periodCost:"Kosten",avgPerPrint:"Durchschnitt pro Druck",usageOverTime:"Verbrauch im Zeitverlauf",filamentByWeight:"Gewicht",printDuration:"Druckdauer",printerUtilization:"Druckerauslastung",filamentSuccess:"Erfolg nach Material",printHabits:"Druckgewohnheiten",printTimeOfDay:"Druck-Tageszeit",colorDistribution:"Farbverteilung",noColorData:"Keine Farbdaten verfügbar",records:"Rekorde",longestPrint:"Längster Druck",heaviestPrint:"Schwerster Druck",mostExpensivePrint:"Teuerster Druck",busiestDay:"Aktivster Tag",successStreak:"Erfolgsserie",streakPrint:"aufeinanderfolgender Druck",streakPrints:"{{count}} aufeinanderfolgende Drucke",printerStats:"Druckerstatistiken",hours:"Stunden",avgPrints:"Ø Drucke",noArchiveData:"Keine Druckdaten verfügbar",filamentByTime:"Zeitverlauf",avgWeight:"Ø Gewicht",avgTime:"Ø Zeit",filamentByPrints:"Drucke",timeframe:{today:"Heute","this-week":"Diese Woche","this-month":"Dieser Monat","last-7":"Letzte 7 Tage","last-30":"Letzte 30 Tage","last-90":"Letzte 90 Tage","this-year":"Dieses Jahr","all-time":"Gesamt",custom:"Benutzerdefiniert",from:"Von",to:"Bis"},allUsers:"Alle Benutzer",noUser:"Kein Benutzer (System)",filterByUser:"Nach Benutzer filtern"},maintenance:{title:"Wartung",overview:"Übersicht",allOk:"Alle Wartungen aktuell",dueCount:"{{count}} Aufgabe fällig",dueCount_plural:"{{count}} Aufgaben fällig",warningCount:"{{count}} Warnung",warningCount_plural:"{{count}} Warnungen",totalPrintTime:"Gesamtdruckzeit",nextMaintenance:"Nächste Wartung",nothingDue:"Nichts fällig",tasks:"Aufgaben",lastPerformed:"Zuletzt durchgeführt",interval:"Intervall",hoursRemaining:"{{hours}}h verbleibend",hoursOverdue:"{{hours}}h überfällig",markDone:"Als erledigt markieren",performMaintenance:"Wartung durchführen",history:"Verlauf",noHistory:"Kein Wartungsverlauf",editPrintHours:"Druckstunden bearbeiten",currentHours:"Aktuelle Stunden",statusTab:"Status",settingsTab:"Einstellungen",overdueCount:"{{count}} überfällig",dueSoonCount:"{{count}} bald fällig",dueSoon:"Bald fällig",allGood:"Alles in Ordnung",overdueBy:"Überfällig um {{duration}}",dueIn:"Fällig in {{duration}}",timeLeft:"{{duration}} verbleibend",day:"1 Tag",days:"{{count}} Tage",week:"1 Woche",weeks:"{{count}} Wochen",month:"1 Monat",months:"{{count}} Monate",year:"1 Jahr",maintenanceTypes:"Wartungstypen",maintenanceTypesDescription:"Systemtypen und Ihre benutzerdefinierten Wartungsaufgaben",addCustomType:"Benutzerdefinierten Typ hinzufügen",restoreDefaults:"Standardaufgaben wiederherstellen",intervalType:"Intervalltyp",intervalValue:"Intervall ({{type}})",icon:"Symbol",documentationLink:"Dokumentationslink (optional)",assignToPrinters:"Druckern zuweisen",selectAtLeastOnePrinter:"Wählen Sie mindestens einen Drucker",addType:"Typ hinzufügen",custom:"Benutzerdefiniert",printHours:"Druckstunden",calendarDays:"Kalendertage",exampleName:"z.B. HEPA-Filter ersetzen",viewDocumentation:"Dokumentation anzeigen",timeBasedInterval:"Zeitbasiertes Intervall",intervalOverrides:"Intervall-Überschreibungen",intervalOverridesDescription:"Intervalle für bestimmte Drucker anpassen",assignedToPrinters:"Druckern zugewiesen:",noPrintersAssigned:"Keine Drucker zugewiesen",addPrinterShort:"Hinzufügen:",printersAssignedClick:"{{count}} Drucker zugewiesen - klicken zum Verwalten",removeFromPrinter:"Von diesem Drucker entfernen",types:{lubricateCarbonRods:"Karbonstäbe schmieren",lubricateRails:"Linearschienen schmieren",cleanNozzle:"Düse/Hotend reinigen",checkBelts:"Riemenspannung prüfen",cleanBuildPlate:"Druckbett reinigen",checkExtruder:"Extruderzahnräder prüfen",checkCooling:"Kühlungslüfter prüfen",generalInspection:"Allgemeine Inspektion",cleanCarbonRods:"Kohlenstoffstangen reinigen",lubricateSteelRods:"Stahlstangen schmieren",cleanSteelRods:"Stahlstangen reinigen",cleanLinearRails:"Linearschienen reinigen",checkPtfeTube:"PTFE-Schlauch prüfen",replaceHepaFilter:"HEPA-Filter ersetzen",replaceCarbonFilter:"Aktivkohlefilter ersetzen",lubricateLeftNozzleRail:"Linke Düsenschiene schmieren"},maintenanceComplete:"Wartung als abgeschlossen markiert",typeUpdated:"Wartungstyp aktualisiert",typeDeleted:"Wartungstyp gelöscht",defaultsRestored:"{{count}} Standardaufgabe(n) wiederhergestellt",printHoursUpdated:"Druckstunden aktualisiert",printerAssigned:"Drucker zugewiesen",printerRemoved:"Drucker entfernt",deleteTypeConfirm:'"{{name}}" löschen?',deleteSystemTypeTitle:"Standard-Wartungsaufgabe löschen?",deleteSystemTypeMessage:'Möchten Sie die Standard-Wartungsaufgabe "{{name}}" wirklich löschen?',noPermissionUpdate:"Sie haben keine Berechtigung, Wartungselemente zu aktualisieren",noPermissionPerform:"Sie haben keine Berechtigung, Wartungen durchzuführen",noPermissionEditTypes:"Sie haben keine Berechtigung, Wartungstypen zu bearbeiten",noPermissionDeleteTypes:"Sie haben keine Berechtigung, Wartungstypen zu löschen",noPermissionEditHours:"Sie haben keine Berechtigung, Druckstunden zu bearbeiten",noPermissionRemovePrinter:"Sie haben keine Berechtigung, Druckerzuweisungen zu entfernen",noPermissionAssignPrinter:"Sie haben keine Berechtigung, Drucker zuzuweisen",noPermissionEditIntervals:"Sie haben keine Berechtigung, Intervalle zu bearbeiten",configureSettings:"Wartungstypen und Intervalle konfigurieren"},settings:{title:"Einstellungen",general:"Allgemein",tabs:{general:"Allgemein",smartPlugs:"Smart Plugs",notifications:"Benachrichtigungen",queue:"Workflow",filament:"Filament",network:"Netzwerk",apiKeys:"API-Schlüssel",virtualPrinter:"Virtueller Drucker",spoolbuddy:"SpoolBuddy",failureDetection:"Fehlererkennung",users:"Authentifizierung",backup:"Sicherung",emailAuth:"E-Mail-Authentifizierung",ldap:"LDAP",twoFa:"Zwei-Faktor-Auth",oidc:"SSO / OIDC"},spoolbuddy:{infoTitle:"SpoolBuddy-Geräte",infoBody:"SpoolBuddy-Kioske registrieren sich automatisch per Heartbeat. Ein Gerät hier abmelden, wenn es nicht mehr verwendet wird oder wenn ein veralteter Eintrag nach einem Daemon-Absturz übrig geblieben ist.",duplicatesTitle:"{{count}} Geräte registriert",duplicatesBody:"Die Kiosk-Oberfläche verwendet nur das zuerst registrierte Gerät. Falls eines davon ein veralteter Doppeleintrag nach einem Absturz ist, kann es hier entfernt werden — ein laufendes Gerät registriert sich beim nächsten Heartbeat automatisch neu.",empty:"Noch keine SpoolBuddy-Geräte registriert.",online:"Online",offline:"Offline",unregister:"Abmelden",unregisterSuccess:"Gerät abgemeldet",unregisterError:"Gerät konnte nicht abgemeldet werden",confirmTitle:"SpoolBuddy-Gerät abmelden?",confirmBody:'Dies entfernt „{{hostname}}" ({{deviceId}}) aus der Datenbank. Ein laufendes Gerät registriert sich beim nächsten Heartbeat automatisch neu.',ipAddress:"IP-Adresse",firmware:"Firmware",lastSeen:"Zuletzt gesehen",daemonUptime:"Daemon-Laufzeit",systemUptime:"System-Laufzeit",never:"nie",nfc:"NFC",scale:"Waage",cpuTemp:"CPU-Temp.",memory:"Speicher",disk:"Festplatte",update:"Aktualisieren",updateConfirmTitle:"Spoolbuddy-Daemon aktualisieren?",updateConfirmBody:'Software-Update auf „{{hostname}}" auslösen? Der Daemon startet nach dem Update neu.',restartBrowser:"Browser neu starten",restartBrowserConfirmTitle:"Kiosk-Browser neu starten?",restartBrowserConfirmBody:'Kiosk-Browser auf „{{hostname}}" neu starten? Die Anzeige wird kurz schwarz.',restartDaemon:"Daemon neu starten",restartDaemonConfirmTitle:"Spoolbuddy-Daemon neu starten?",restartDaemonConfirmBody:'Spoolbuddy-Daemon auf „{{hostname}}" neu starten? Das Gerät ist für einige Sekunden offline.',reboot:"Neustart",rebootConfirmTitle:"Gerät neu starten?",rebootConfirmBody:'„{{hostname}}" neu starten? Das Gerät ist für etwa eine Minute offline.',shutdown:"Herunterfahren",shutdownConfirmTitle:"Gerät herunterfahren?",shutdownConfirmBody:'„{{hostname}}" herunterfahren? Physischer Zugriff ist nötig, um es wieder einzuschalten.',commandConfirm:"Bestätigen",commandQueued:"Befehl eingereiht",commandError:"Befehl konnte nicht gesendet werden"},ldap:{title:"LDAP-Authentifizierung",enabledDesc:"LDAP-Authentifizierung ist aktiviert",disabledDesc:"LDAP-Authentifizierung ist deaktiviert",disabledHint:"LDAP-Einstellungen unten konfigurieren und speichern, dann aktivieren.",enabled:"LDAP-Authentifizierung aktiviert",disabled:"LDAP-Authentifizierung deaktiviert",feature1:"Benutzer können sich mit LDAP-Anmeldedaten anmelden",feature2:"Lokales Admin-Konto bleibt als Fallback erhalten",feature3:"LDAP-Gruppen werden bei der Anmeldung BamBuddy-Gruppen zugeordnet",serverConfig:"LDAP-Server-Konfiguration",serverUrl:"Server-URL",serverUrlHint:"Verwenden Sie ldap:// für Standard oder ldaps:// für SSL-Verbindungen",security:"Sicherheit",securityHint:"StartTLS aktualisiert eine einfache Verbindung auf TLS. LDAPS verwendet TLS von Anfang an.",bindDn:"Bind-DN (Dienstkonto)",bindPassword:"Bind-Passwort",searchBase:"Such-Basis-DN",userFilter:"Benutzer-Suchfilter",userFilterHint:"{username} wird durch den Anmeldenamen ersetzt. Verwenden Sie (uid={username}) für OpenLDAP.",autoProvision:"Benutzer automatisch anlegen",autoProvisionHint:"Automatisch ein BamBuddy-Konto bei der ersten LDAP-Anmeldung erstellen",defaultGroup:"Standardgruppe",defaultGroupNone:"— Keine (kein Fallback) —",defaultGroupHint:"Fallback-Gruppe, die zugewiesen wird, wenn sich ein LDAP-Benutzer authentifiziert, aber in keiner zugeordneten LDAP-Gruppe enthalten ist. Leer lassen, um nicht zugeordnete Benutzer ohne Berechtigungen zu belassen.",groupMapping:"Gruppenzuordnung (JSON)",groupMappingHint:"LDAP-Gruppen-DNs BamBuddy-Gruppen zuordnen. Verfügbare Gruppen: ",testConnection:"Verbindung testen",settingsSaved:"LDAP-Einstellungen gespeichert",errors:{serverRequired:"LDAP-Server-URL ist erforderlich",searchBaseRequired:"Such-Basis-DN ist erforderlich",enableAuthFirst:"Authentifizierung zuerst aktivieren",configureLdapFirst:"LDAP-Einstellungen zuerst speichern"}},email:{smtpSettings:"SMTP-Konfiguration",smtpHost:"SMTP-Server",smtpPort:"SMTP-Port",security:"Sicherheit",authentication:"Authentifizierung",username:"Benutzername",password:"Passwort",fromEmail:"Absender-E-Mail",fromName:"Absendername",testConnection:"SMTP-Verbindung testen",testRecipient:"Test-Empfänger-E-Mail",sendTest:"Test-E-Mail senden",sending:"Wird gesendet...",save:"Einstellungen speichern",saving:"Wird gespeichert...",advancedAuth:"Erweiterte Authentifizierung",advancedAuthEnabled:"Erweiterte Authentifizierung ist aktiviert",advancedAuthEnabledDesc:"E-Mail-basierte Benutzerverwaltungsfunktionen sind aktiv. Neue Benutzer erhalten automatisch generierte Passwörter per E-Mail und können ihr Passwort über die Passwort vergessen Funktion zurücksetzen.",advancedAuthDisabled:"Erweiterte Authentifizierung ist deaktiviert",advancedAuthDisabledDesc:"Aktivieren Sie die erweiterte Authentifizierung, um E-Mail-basierte Funktionen für die Benutzerverwaltung zu aktivieren.",enable:"Aktivieren",disable:"Deaktivieren",feature1:"Passwörter werden automatisch generiert und an neue Benutzer gesendet",feature2:"Benutzer können sich mit Benutzername oder E-Mail anmelden",feature3:"Passwort vergessen Funktion ist verfügbar",feature4:"Administratoren können Benutzerpasswörter per E-Mail zurücksetzen",errors:{requiredFields:"Bitte füllen Sie alle Pflichtfelder aus",usernameRequired:"Benutzername ist erforderlich, wenn Authentifizierung aktiviert ist",enterTestEmail:"Bitte geben Sie eine Test-E-Mail-Adresse ein",smtpServerAndEmail:"Bitte füllen Sie SMTP-Server und Absender-E-Mail aus, bevor Sie testen",usernamePasswordRequired:"Benutzername und Passwort sind erforderlich, wenn Authentifizierung aktiviert ist",configureSmtpFirst:"Bitte konfigurieren und testen Sie zuerst die SMTP-Einstellungen",enableAuthFirst:"Bitte aktivieren Sie zuerst die Authentifizierung, um E-Mail-basierte Funktionen nutzen zu können."},success:{settingsSaved:"SMTP-Einstellungen erfolgreich gespeichert"},securityOptions:{starttls:"STARTTLS (Port 587)",ssl:"SSL/TLS (Port 465)",none:"Keine (Port 25)"},authOptions:{enabled:"Aktiviert",disabled:"Deaktiviert"}},appearance:"Erscheinungsbild",notifications:"Benachrichtigungen",smartPlugs:"Smart Plugs",spoolman:"Spoolman",updates:"Updates",language:"Sprache",languageDescription:"Wählen Sie Ihre bevorzugte Sprache",theme:"Design",themeLight:"Hell",themeDark:"Dunkel",themeSystem:"System",defaultView:"Standardansicht",defaultViewDescription:"Seite, die beim Öffnen der App angezeigt wird",checkForUpdates:"Nach Updates suchen",autoUpdate:"Automatische Updates",currentVersion:"Aktuelle Version",latestVersion:"Neueste Version",upToDate:"Sie sind auf dem neuesten Stand",updateAvailable:"Update verfügbar",notificationLanguage:"Benachrichtigungssprache",notificationLanguageDescription:"Sprache für Push-Benachrichtigungen",bedCooledThreshold:"Bett-Abkühlung Schwellenwert",bedCooledThresholdDescription:"Temperatur, unter der das Bett nach einem Druck als abgekühlt gilt",userNotificationsEnabled:"Benutzerbenachrichtigungen",userNotificationsEnabledDescription:"Aktiviert das Benutzerbenachrichtigungsmenü und E-Mail-Benachrichtigungen für Druckereignisse. Erfordert Erweiterte Authentifizierung.",userNotificationsDisabledHint:"Erweiterte Authentifizierung aktivieren, um Benutzerbenachrichtigungen zu verwenden.",notificationProviders:"Benachrichtigungsanbieter",addProvider:"Anbieter hinzufügen",editProvider:"Anbieter bearbeiten",providerType:"Anbietertyp",testNotification:"Testbenachrichtigung",testSuccess:"Testbenachrichtigung erfolgreich gesendet",testFailed:"Testbenachrichtigung konnte nicht gesendet werden",quietHours:"Ruhezeiten",quietHoursDescription:"Keine Störungen während dieser Zeiten",quietHoursStart:"Beginn",quietHoursEnd:"Ende",events:{title:"Benachrichtigungsereignisse",printStart:"Druck gestartet",printComplete:"Druck abgeschlossen",printFailed:"Druck fehlgeschlagen",printStopped:"Druck gestoppt",printProgress:"Fortschrittsmeldungen",printProgressDescription:"Bei 25%, 50%, 75% benachrichtigen",printerOffline:"Drucker offline",printerError:"Druckerfehler",filamentLow:"Filament niedrig",maintenanceDue:"Wartung fällig",maintenanceDueDescription:"Benachrichtigen, wenn Wartung erforderlich"},smartPlug:{title:"Smart Plugs",add:"Smart Plug hinzufügen",edit:"Smart Plug bearbeiten",name:"Name",ipAddress:"IP-Adresse",linkedPrinter:"Verknüpfter Drucker",autoOn:"Automatisch einschalten",autoOnDescription:"Einschalten beim Druckstart",autoOff:"Automatisch ausschalten",autoOffDescription:"Ausschalten nach Druckende",offDelay:"Ausschaltverzögerung",offDelayMinutes:"Minuten nach Druck",offDelayTemp:"Wenn Düse unter Temperatur",currentState:"Aktueller Status",turnOn:"Einschalten",turnOff:"Ausschalten"},filamentTracking:"Filament-Verfolgung",filamentTrackingDesc:"Wählen Sie, wie Sie Ihre Filamentspulen verfolgen möchten. Sie können das integrierte Inventar oder einen externen Spoolman-Server verwenden.",filamentChecks:"Filament-Prüfungen",disableFilamentWarnings:"Filament-Warnungen deaktivieren",disableFilamentWarningsDesc:"Keine Warnungen über unzureichendes Filament beim Drucken oder Einreihen anzeigen",preferLowestFilament:"Niedrigsten Filamentrest bevorzugen",preferLowestFilamentDesc:"Bei mehreren passenden Spulen die mit dem geringsten Restfilament verwenden",trackingModeBuiltIn:"Integriertes Inventar",trackingModeBuiltInDesc:"RFID-Erkennung und Verbrauchserfassung inklusive",trackingModeSpoolmanDesc:"Externer Filament-Management-Server",builtInFeatureRfid:"Erkennt automatisch Bambu Lab RFID-Spulen im AMS",builtInFeatureUsage:"Erfasst den Filamentverbrauch pro Druck",builtInFeatureCatalog:"Spulen, Farben und K-Faktor-Profile verwalten",builtInFeatureThirdParty:"Drittanbieter-Spulen können Inventarspulen zugewiesen werden",amsSyncButton:"Gewichte vom AMS synchronisieren",amsSyncTitle:"Spulengewichte vom AMS synchronisieren",amsSyncMessage:"Alle Inventar-Spulengewichte werden mit den aktuellen AMS-Restwerten der verbundenen Drucker überschrieben. Verwenden Sie dies zur Wiederherstellung beschädigter Gewichtsdaten. Drucker müssen online sein.",amsSyncing:"Synchronisiere...",amsSyncSuccess:"{{synced}} Spule(n) synchronisiert, {{skipped}} übersprungen",amsSyncError:"Synchronisierung der Gewichte vom AMS fehlgeschlagen",spoolmanUrl:"Spoolman URL",spoolmanUrlHint:"URL Ihres Spoolman-Servers (z.B. http://localhost:7912)",spoolmanConnected:"Verbunden",spoolmanDisconnected:"Nicht verbunden",status:"Status",connect:"Verbinden",disconnect:"Trennen",howSyncWorks:"So funktioniert die Synchronisierung",syncInfoRfidOnly:"Nur offizielle Bambu Lab Spulen mit RFID werden synchronisiert",syncInfoAutoCreate:"Neue Spulen werden bei der ersten Synchronisierung automatisch in Spoolman erstellt",syncInfoThirdPartySkipped:"Nicht-Bambu-Lab-Spulen (Drittanbieter, nachgefüllt) werden übersprungen",linkingExistingSpools:"Vorhandene Spulen verknüpfen",linkingExistingSpoolsDesc:'Um vorhandene Spoolman-Spulen mit Ihrem AMS zu verknüpfen, fahren Sie über einen AMS-Slot und klicken Sie auf "Mit Spoolman verknüpfen".',syncMode:"Synchronisierungsmodus",syncModeAuto:"Automatisch",syncModeManual:"Nur manuell",syncModeAutoDesc:"AMS-Daten werden automatisch synchronisiert, wenn Änderungen erkannt werden",syncModeManualDesc:"Nur bei manueller Auslösung synchronisieren",syncAmsData:"AMS-Daten synchronisieren",syncAmsDataDesc:"AMS-Daten des Druckers manuell mit Spoolman synchronisieren",allPrinters:"Alle Drucker",noDefaultPrinter:"Kein Standard (jedes Mal fragen)",sidebarOrder:"Seitenleisten-Reihenfolge",saveThumbnails:"Vorschaubilder speichern",captureFinishPhoto:"Abschlussfoto aufnehmen",noPrintersConfigured:"Keine Drucker konfiguriert",archiveMode:{always:"Immer Archiveintrag erstellen",never:"Nie Archiveintrag erstellen",ask:"Jedes Mal fragen"},checkForUpdatesLabel:"Nach Updates suchen",checkPrinterFirmware:"Drucker-Firmware prüfen",includeBetaUpdates:"Beta-Versionen einschließen",includeBetaUpdatesDesc:"Über Beta- und Vorabversionen bei der Updateprüfung benachrichtigen",enableRetry:"Wiederholung aktivieren",homeAssistantDescription:"Smart Plugs über Home Assistant steuern",environmentManagedLabel:"(Umgebungsvariable)",autoEnabledViaEnv:"Automatisch über Umgebungsvariablen aktiviert",urlFromEnvReadOnly:"Wert wird über HA_URL Umgebungsvariable gesetzt (schreibgeschützt)",tokenFromEnvReadOnly:"Wert wird über HA_TOKEN Umgebungsvariable gesetzt (schreibgeschützt)",mqttConnectedTo:"Verbunden mit",prometheusDescription:"Druckerdaten im Prometheus-Format bereitstellen",noSmartPlugsTitle:"Keine Smart Plugs konfiguriert",noSmartPlugsDescription:"Fügen Sie einen Tasmota-basierten Smart Plug hinzu, um den Energieverbrauch zu verfolgen und die Stromsteuerung zu automatisieren.",noProvidersTitle:"Keine Anbieter konfiguriert",noProvidersDescription:"Fügen Sie einen Anbieter hinzu, um Benachrichtigungen zu erhalten.",noTemplatesAvailable:"Keine Vorlagen verfügbar. Starten Sie das Backend neu, um Standardvorlagen zu laden.",apiPermissionView:"Druckerstatus und Warteschlange anzeigen",apiPermissionEdit:"Elemente zur Druckwarteschlange hinzufügen und entfernen",apiKeysEmptyTitle:"Keine API-Schlüssel",apiKeysEmptyDescription:"Erstellen Sie einen API-Schlüssel zur Integration mit externen Diensten.",noUsersFound:"Keine Benutzer gefunden",noGroupsFound:"Keine Gruppen gefunden",noGroupsAvailable:"Keine Gruppen verfügbar",passwordsDoNotMatch:"Passwörter stimmen nicht überein",systemGroupWarning:"System-Gruppennamen können nicht geändert werden",authDisabledTitle:"Authentifizierung ist deaktiviert",authDisabledFeature1:"Anmeldung zum Zugriff auf das System erforderlich",authDisabledFeature2:"Mehrere Benutzer mit gruppenbasierten Berechtigungen erstellen",authDisabledFeature3:"Zugriff mit über 50 granularen Berechtigungen steuern",userHasCreated:"Dieser Benutzer hat erstellt:",userItemsQuestion:"Was möchten Sie mit diesen Elementen tun?",deleteUserConfirm:"Möchten Sie diesen Benutzer wirklich löschen?",actionCannotBeUndone:"Diese Aktion kann nicht rückgängig gemacht werden.",addFirstSmartPlug:"Ersten Smart Plug hinzufügen",providers:"Anbieter",log:"Protokoll",testAll:"Alle testen",testResults:"Testergebnisse",testPassedCount:"{{count}} bestanden",testFailedCount:"{{count}} fehlgeschlagen",messageTemplates:"Nachrichtenvorlagen",messageTemplatesDescription:"Passen Sie Benachrichtigungen für jedes Ereignis an.",apiKeys:"API-Schlüssel",apiKeysDescription:"Erstellen Sie API-Schlüssel für externe Integrationen und Webhooks.",createKey:"Schlüssel erstellen",apiKeyCreated:"API-Schlüssel erfolgreich erstellt",apiKeyCopyWarning:"Kopieren Sie diesen Schlüssel jetzt - er wird nicht mehr angezeigt!",useInApiBrowser:"Im API-Browser verwenden",createNewApiKey:"Neuen API-Schlüssel erstellen",keyName:"Schlüsselname",keyNamePlaceholder:"z.B. Home Assistant, OctoPrint",readStatus:"Status lesen",readStatusDescription:"Druckerstatus und Warteschlange anzeigen",manageQueue:"Warteschlange verwalten",manageQueueDescription:"Elemente zur Druckwarteschlange hinzufügen und entfernen",controlPrinter:"Drucker steuern",controlPrinterDescription:"Drucke pausieren, fortsetzen und stoppen",unnamedKey:"Unbenannter Schlüssel",lastUsed:"Zuletzt verwendet",read:"Lesen",control:"Steuern",createFirstKey:"Ersten Schlüssel erstellen",webhookEndpoints:"Webhook-Endpunkte",webhookApiKeyHint:"Verwenden Sie Ihren API-Schlüssel im X-API-Key-Header.",webhook:{getAllStatus:"Alle Druckerstatus abrufen",getSpecificStatus:"Spezifischen Druckerstatus abrufen",addToQueue:"Zur Druckwarteschlange hinzufügen",pausePrint:"Druck pausieren",resumePrint:"Druck fortsetzen",stopPrint:"Druck stoppen"},apiBrowser:"API-Browser",apiBrowserDescription:"Erkunden und testen Sie alle verfügbaren API-Endpunkte.",apiKeyForTesting:"API-Schlüssel zum Testen",apiKeyPlaceholder:"Fügen Sie hier Ihren API-Schlüssel ein, um authentifizierte Endpunkte zu testen...",apiKeyHint:"Dieser Schlüssel wird als X-API-Key-Header mit Anfragen gesendet.",deleteApiKeyTitle:"API-Schlüssel löschen",deleteApiKeyMessage:"Möchten Sie diesen API-Schlüssel wirklich löschen? Alle Integrationen, die diesen Schlüssel verwenden, funktionieren nicht mehr.",deleteKey:"Schlüssel löschen",amsDisplayThresholds:"AMS-Anzeigeschwellenwerte",amsThresholdsDescription:"Konfigurieren Sie Farbschwellenwerte für AMS-Feuchtigkeits- und Temperaturanzeigen.",humidity:"Luftfeuchtigkeit",goodGreen:"Gut (grün)",fairOrange:"Mittel (orange)",aboveFairBad:"Über dem mittleren Schwellenwert wird rot angezeigt (schlecht)",fairAlsoDryingThreshold:"Dieser Schwellenwert wird auch für die automatische Trocknung verwendet",temperature:"Temperatur",goodBlue:"Gut (blau)",aboveFairHot:"Über dem mittleren Schwellenwert wird rot angezeigt (heiß)",historyRetention:"Verlaufsaufbewahrung",keepSensorHistory:"Sensorverlauf behalten für",historyRetentionDescription:"Ältere Feuchtigkeits- und Temperaturdaten werden automatisch gelöscht",defaultPrintOptions:"Standard-Druckoptionen",defaultPrintOptionsDescription:"Standardwerte für Druckoptionen bei neuen Drucken festlegen. Diese können im Druckdialog pro Druck überschrieben werden.",defaultBedLevelling:"Bett-Nivellierung",defaultBedLevellingDesc:"Bett vor dem Druck automatisch nivellieren",defaultFlowCali:"Fluss-Kalibrierung",defaultFlowCaliDesc:"Extrusionsfluss kalibrieren",defaultVibrationCali:"Vibrationskalibrierung",defaultVibrationCaliDesc:"Ringing-Artefakte reduzieren",defaultLayerInspect:"Erste-Schicht-Inspektion",defaultLayerInspectDesc:"KI-Inspektion der ersten Schicht",defaultTimelapse:"Zeitraffer",defaultTimelapseDesc:"Zeitraffervideo aufnehmen",staggeredStart:"Staggered Start",staggeredStartDescription:"Default group size and interval when staggering multi-printer batch starts. Can be overridden per batch in the print modal.",plateClear:"Druckplatte-Bestätigung",requirePlateClear:"Druckplatte-Bestätigung erforderlich",requirePlateClearDescription:'Wenn aktiviert, wartet der Scheduler auf eine Druckplatten-Bestätigung pro Drucker, bevor geplante Drucke auf Druckern mit abgeschlossenen Aufträgen gestartet werden. Wenn dies deaktiviert ist, werden auch das Druckplatten-Status-Badge und die Schaltfläche "Druckplatte als freigegeben markieren" auf den Druckerkarten ausgeblendet.',gcodeInjection:"G-code Injection",gcodeInjectionDescription:'Konfigurieren Sie benutzerdefinierten G-code, der am Anfang und/oder Ende von Drucken für Auto-Print-Systeme wie Farmloop, SwapMod, AutoClear und Printflow 3D eingefügt wird. Snippets werden pro Druckermodell konfiguriert und angewendet, wenn "G-code einfügen" bei einem Warteschlangen-Element aktiviert ist.',gcodeInjectionNoPrinters:"Keine Drucker gefunden. Fügen Sie Drucker hinzu, um G-code-Snippets zu konfigurieren.",gcodeStartLabel:"Start G-code",gcodeEndLabel:"End G-code",gcodeStartPlaceholder:"G-code, der vor dem Druckstart eingefügt wird...",gcodeEndPlaceholder:"G-code, der nach dem Druckende angefügt wird...",staggerGroupSize:"Group size",staggerGroupSizeHelp:"Printers to start simultaneously per group",staggerInterval:"Interval (minutes)",staggerIntervalHelp:"Delay between each group starting",queueDrying:"Automatische Trocknung",queueDryingDescription:"AMS-Filament automatisch trocknen, wenn der Drucker zwischen Warteschlangen-Drucken im Leerlauf ist. Verwendet den Feuchtigkeitsschwellenwert oben.",queueDryingEnabled:"Automatische Trocknung aktivieren",queueDryingEnabledDescription:"AMS-Trocknung automatisch starten, wenn der Drucker im Leerlauf ist und die Feuchtigkeit über dem Schwellenwert liegt",queueDryingBlock:"Auf Trocknung warten",queueDryingBlockDescription:"Druckwarteschlange blockieren, bis die Trocknung abgeschlossen ist. Wenn aus, haben Drucke Vorrang.",ambientDryingEnabled:"Umgebungstrocknung",ambientDryingEnabledDescription:"Filament auf inaktiven Druckern automatisch trocknen, wenn die Luftfeuchtigkeit den Schwellenwert überschreitet — auch ohne Warteschlange.",dryingPresets:"Trocknungsvoreinstellungen",dryingPresetsDescription:"Temperatur und Dauer pro Filamenttyp. AMS 2 Pro verwendet niedrigere Temperaturen, AMS-HT unterstützt höhere.",dryingFilament:"Filament",printModal:"Druckdialog",expandCustomMapping:"Benutzerdefinierte Zuordnung standardmäßig erweitern",expandCustomMappingDescription:"Bei Druck auf mehrere Drucker die AMS-Zuordnung pro Drucker erweitert anzeigen",authentication:"Authentifizierung",authEnabledDescription:"Ihre Instanz ist mit Benutzerauthentifizierung gesichert",authDisabledDescription:"Aktivieren Sie die Anmeldepflicht und verwalten Sie den Benutzerzugriff",authDisabledMessage:"Aktivieren Sie die Authentifizierung, um Benutzerkonten zu erstellen, Berechtigungen zu verwalten und Ihre Bambuddy-Instanz zu sichern.",enableAuthentication:"Authentifizierung aktivieren",currentUser:"Aktueller Benutzer",changePassword:"Passwort ändern",admin:"Admin",users:"Benutzer",addUser:"Benutzer hinzufügen",groups:"Gruppen",addGroup:"Gruppe hinzufügen",system:"System",noDescription:"Keine Beschreibung",userCount:"{{count}} Benutzer",permissionCount:"{{count}} Berechtigungen",createUser:"Benutzer erstellen",username:"Benutzername",enterUsername:"Benutzername eingeben",password:"Passwort",enterPassword:"Passwort eingeben (min. 6 Zeichen)",confirmPassword:"Passwort bestätigen",confirmPasswordPlaceholder:"Passwort bestätigen",viewReleaseOnGitHub:"Release auf GitHub anzeigen",turnAllPlugsOn:"Alle Stecker einschalten",turnAllPlugsOff:"Alle Stecker ausschalten",clearNotificationLogs:"Benachrichtigungsprotokolle löschen",clearLogsMessage:"Dadurch werden alle Benachrichtigungsprotokolle, die älter als 30 Tage sind, dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",clearLogs:"Protokolle löschen",resetUiPreferences:"UI-Einstellungen zurücksetzen",resetUiPreferencesMessage:"Dadurch werden alle UI-Einstellungen auf Standardwerte zurückgesetzt: Seitenleisten-Reihenfolge, Theme, Dashboard-Layout, Ansichtsmodi und Sortiereinstellungen. Ihre Drucker, Archive und Servereinstellungen werden NICHT beeinträchtigt. Die Seite wird nach dem Löschen neu geladen.",resetPreferences:"Einstellungen zurücksetzen",deleteGroupTitle:"Gruppe löschen",deleteGroupMessage:"Möchten Sie diese Gruppe wirklich löschen? Benutzer in dieser Gruppe verlieren diese Berechtigungen.",deleteGroup:"Gruppe löschen",disableAuthenticationTitle:"Authentifizierung deaktivieren",disableAuthenticationMessage:"Möchten Sie die Authentifizierung wirklich deaktivieren? Dadurch wird Ihre Bambuddy-Instanz ohne Anmeldung zugänglich. Alle Benutzer bleiben in der Datenbank, aber die Authentifizierung wird deaktiviert.",disableAuthentication:"Authentifizierung deaktivieren",configureBambuddy:"Bambuddy konfigurieren",systemDefault:"Systemstandard",archiveSettings:"Archiv-Einstellungen",newWindow:"Neues Fenster",embeddedOverlay:"Eingebettetes Overlay",preferredSlicer:"Bevorzugter Slicer",preferredSlicerDescription:"Wähle die Slicer-Anwendung zum Öffnen von Dateien",externalCameras:"Externe Kameras",costTracking:"Kostenverfolgung",printsOnly:"Nur Drucke",totalConsumption:"Gesamtverbrauch",dataManagement:"Datenverwaltung",storageUsage:"Speichernutzung",storageUsageDescription:"Aufschlüsselung der Datennutzung nach Kategorie",storageUsageTotal:"Gesamt",storageUsageErrors:"Fehler",storageUsageOtherBreakdown:"Sonstiges (enthält statische Assets, Skripte und Konfigurationsdateien)",storageUsageSystem:"System",storageUsageData:"Daten",storageUsageUnavailable:"Speichernutzungsinformationen nicht verfügbar",clearNotificationLogsDescription:"Benachrichtigungsprotokolle älter als 30 Tage löschen",resetUiPreferencesDescription:"Seitenleisten-Reihenfolge, Theme, Ansichtsmodi und Layout-Einstellungen zurücksetzen. Drucker, Archive und Einstellungen werden nicht beeinflusst.",enableHomeAssistant:"Home Assistant aktivieren",enableMqtt:"MQTT aktivieren",useTls:"TLS verwenden",enableMetricsEndpoint:"Metrik-Endpunkt aktivieren",availableMetrics:"Verfügbare Metriken",editUser:"Benutzer bearbeiten",deleteUserTitle:"Benutzer löschen",groupName:"Gruppenname",leaveEmptyForAnonymous:"Leer lassen für anonym",leaveEmptyForNoAuth:"Leer lassen für keine Authentifizierung",enterNewPassword:"Neues Passwort eingeben",confirmNewPassword:"Neues Passwort bestätigen",enterGroupName:"Gruppenname eingeben",enterDescriptionOptional:"Beschreibung eingeben (optional)",enterCurrentPassword:"Aktuelles Passwort eingeben",enterNewPasswordMin6:"Neues Passwort eingeben (min. 6 Zeichen)",toast:{keyCopied:"Schlüssel in Zwischenablage kopiert",copyFailed:"Schlüssel konnte nicht kopiert werden",keyAddedToBrowser:"Schlüssel zum API-Browser hinzugefügt",clearLogsFailed:"Protokolle konnten nicht gelöscht werden",uiPreferencesReset:"UI-Einstellungen zurückgesetzt. Wird neu geladen...",authDisabled:"Authentifizierung erfolgreich deaktiviert",authDisableFailed:"Authentifizierung konnte nicht deaktiviert werden",apiKeyCreated:"API-Schlüssel erstellt",apiKeyDeleted:"API-Schlüssel gelöscht",userCreated:"Benutzer erfolgreich erstellt",userUpdated:"Benutzer erfolgreich aktualisiert",userDeleted:"Benutzer erfolgreich gelöscht",groupCreated:"Gruppe erfolgreich erstellt",groupUpdated:"Gruppe erfolgreich aktualisiert",groupDeleted:"Gruppe erfolgreich gelöscht",fillRequiredFields:"Bitte füllen Sie alle erforderlichen Felder aus",passwordsDoNotMatch:"Passwörter stimmen nicht überein",passwordTooShort:"Passwort muss mindestens 6 Zeichen lang sein",enterGroupName:"Bitte geben Sie einen Gruppennamen ein",settingsSaved:"Einstellungen gespeichert",cameraSettingsSaved:"Kamera-Einstellungen gespeichert",enterCameraUrl:"Bitte geben Sie eine Kamera-URL ein",passwordChanged:"Passwort erfolgreich geändert",connectionFailed:"Verbindung fehlgeschlagen",testFailed:"Test fehlgeschlagen",cameraConnected:"Kamera verbunden{{resolution}}"},testConnection:"Verbindung testen",catalog:{spoolCatalog:"Spulenkatalog",spoolCatalogDescription:"Leerspulengewichte nach Marke/Typ. Wird für die automatische Gewichtssuche beim Hinzufügen von Spulen verwendet.",searchCatalog:"Katalog durchsuchen...",addNewEntry:"Neuen Eintrag hinzufügen",namePlaceholder:"Name (z.B. Bambu Lab - Plastik)",weight:"Gewicht",type:"Typ",default:"Standard",custom:"Benutzerdefiniert",noMatch:"Keine Einträge entsprechen Ihrer Suche",empty:"Keine Einträge im Katalog",deleteEntry:"Eintrag löschen",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen?',resetCatalog:"Katalog zurücksetzen",resetConfirm:"Katalog auf Standardwerte zurücksetzen? Alle benutzerdefinierten Einträge werden entfernt.",loadFailed:"Spulenkatalog konnte nicht geladen werden",nameWeightRequired:"Name und Gewicht sind erforderlich",entryAdded:"Eintrag hinzugefügt",addFailed:"Eintrag konnte nicht hinzugefügt werden",entryUpdated:"Eintrag aktualisiert",updateFailed:"Eintrag konnte nicht aktualisiert werden",entryDeleted:"Eintrag gelöscht",deleteFailed:"Eintrag konnte nicht gelöscht werden",resetSuccess:"Katalog auf Standardwerte zurückgesetzt",resetFailed:"Katalog konnte nicht zurückgesetzt werden",exported:"{{count}} Einträge exportiert",imported:"{{added}} Einträge importiert ({{skipped}} übersprungen)",importFailed:"Import fehlgeschlagen: ungültiges JSON-Format",exportTooltip:"Katalog als JSON exportieren",importTooltip:"Katalog aus JSON importieren",resetTooltip:"Auf Standardwerte zurücksetzen",selectedCount:"{{count}} ausgewählt",deleteSelected:"Ausgewählte löschen",bulkDeleteConfirm:"Möchten Sie {{count}} Einträge wirklich löschen?",bulkDeleted:"{{count}} Einträge gelöscht",bulkDeleteFailed:"Fehler beim Löschen der Einträge"},colorCatalog:{title:"Farbkatalog",description:"Filamentfarben nach Hersteller/Material. Wird für die automatische Farbsuche beim Hinzufügen von Spulen verwendet.",searchColors:"Farben durchsuchen...",allManufacturers:"Alle Hersteller",addNewColor:"Neue Farbe hinzufügen",manufacturer:"Hersteller",colorName:"Farbname",hex:"Hex",materialOptional:"Material (optional)",showing:"{{filtered}} von {{total}} Farben angezeigt",noMatch:"Keine Farben entsprechen Ihrer Suche",empty:"Keine Farben im Katalog",deleteColor:"Farbe löschen",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen?',resetCatalog:"Farbkatalog zurücksetzen",resetConfirm:"Katalog auf Standardwerte zurücksetzen? Alle benutzerdefinierten Farben werden entfernt.",sync:"Sync",starting:"Starten...",syncTooltip:"Von FilamentColors.xyz synchronisieren (2000+ Farben)",loadFailed:"Farbkatalog konnte nicht geladen werden",fieldsRequired:"Hersteller, Farbname und Hex-Farbe sind erforderlich",colorAdded:"Farbe hinzugefügt",addFailed:"Farbe konnte nicht hinzugefügt werden",colorUpdated:"Farbe aktualisiert",updateFailed:"Farbe konnte nicht aktualisiert werden",colorDeleted:"Farbe gelöscht",deleteFailed:"Farbe konnte nicht gelöscht werden",resetSuccess:"Farbkatalog auf Standardwerte zurückgesetzt",resetFailed:"Katalog konnte nicht zurückgesetzt werden",syncUpToDate:"Bereits aktuell ({{count}} Farben geprüft)",syncComplete:"{{added}} neue Farben hinzugefügt ({{skipped}} bereits vorhanden)",syncError:"Sync-Fehler",syncFailed:"Synchronisierung von FilamentColors.xyz fehlgeschlagen",exported:"{{count}} Farben exportiert",imported:"{{added}} Farben importiert ({{skipped}} übersprungen)",importFailed:"Import fehlgeschlagen: ungültiges JSON-Format",selectedCount:"{{count}} ausgewählt",deleteSelected:"Ausgewählte löschen",bulkDeleteConfirm:"Möchten Sie {{count}} Farben wirklich löschen?",bulkDeleted:"{{count}} Farben gelöscht",bulkDeleteFailed:"Fehler beim Löschen der Farben"},dateFormat:"Datumsformat",dateFormatUs:"US (MM/TT/JJJJ)",dateFormatEu:"EU (TT/MM/JJJJ)",dateFormatIso:"ISO (JJJJ-MM-TT)",timeFormat:"Zeitformat",timeFormat12:"12-Stunden (3:30 PM)",timeFormat24:"24-Stunden (15:30)",defaultPrinter:"Standarddrucker",defaultPrinterDescription:"Diesen Drucker für Uploads, Nachdrucke und andere Vorgänge vorauswählen.",slicerBambuStudio:"Bambu Studio",slicerOrcaSlicer:"OrcaSlicer",sidebarOrderDescription:"Elemente in der Seitenleiste per Drag & Drop neu anordnen. Hier auf Standardreihenfolge zurücksetzen.",setDefault:"Standard setzen",sidebarOrderSetDefaultHint:"Standard setzen übernimmt die aktuelle Menüreihenfolge für Benutzer, die ihre noch nicht angepasst haben.",sidebarDefaultSet:"Standard-Menüreihenfolge wurde festgelegt.",sidebarDefaultCleared:"Standard-Menüreihenfolge gelöscht.",sidebarDefaultFailed:"Festlegen der Standard-Menüreihenfolge fehlgeschlagen.",reset:"Zurücksetzen",darkMode:"Dunkelmodus",lightMode:"Hellmodus",active:"(aktiv)",background:"Hintergrund",accent:"Akzent",style:"Stil",bgNeutral:"Neutral",bgWarm:"Warm",bgCool:"Kühl",bgOled:"OLED Schwarz",bgSlate:"Schieferblau",bgForest:"Waldgrün",accentGreen:"Grün",accentTeal:"Türkis",accentBlue:"Blau",accentOrange:"Orange",accentPurple:"Lila",accentRed:"Rot",styleClassic:"Klassisch",styleGlow:"Leuchtend",styleVibrant:"Lebendig",themeToggleHint:"Zwischen Hell- und Dunkelmodus mit dem Sonnen-/Mondsymbol in der Seitenleiste wechseln.",autoArchivePrints:"Drucke automatisch archivieren",autoArchiveDescription:"3MF-Dateien automatisch speichern, wenn Drucke abgeschlossen sind",saveThumbnailsDescription:"Vorschaubilder aus 3MF-Dateien extrahieren und speichern",captureFinishPhotoDescription:"Foto von der Druckerkamera aufnehmen, wenn der Druck abgeschlossen ist",ffmpegNotInstalled:"ffmpeg nicht installiert",ffmpegRequired:"Kameraaufnahme benötigt ffmpeg. Installieren über brew install ffmpeg (macOS) oder apt install ffmpeg (Linux).",camera:"Kamera",cameraViewMode:"Kamera-Ansichtsmodus",cameraOverlayDescription:"Kamera öffnet sich als größenveränderbares Overlay auf dem Hauptbildschirm",cameraWindowDescription:"Kamera öffnet sich in einem separaten Browserfenster",externalCamerasDescription:"Externe Kameras konfigurieren, um die eingebaute Druckerkamera zu ersetzen. Unterstützt MJPEG-Streams, RTSP, HTTP-Snapshots und USB-Kameras (V4L2). Wenn aktiviert, wird die externe Kamera für Live-Ansicht und Abschlussfotos verwendet.",cameraPlaceholderUsb:"Gerätepfad (/dev/video0)",cameraPlaceholderUrl:"Kamera-URL (rtsp://... oder http://...)",cameraTypeMjpeg:"MJPEG-Stream",cameraTypeRtsp:"RTSP-Stream",cameraTypeSnapshot:"HTTP-Snapshot",cameraTypeUsb:"USB-Kamera (V4L2)",cameraRotation:"Drehung",test:"Testen",connected:"Verbunden",disconnected:"Getrennt",currency:"Währung",defaultFilamentCost:"Standard-Filamentkosten (pro kg)",electricityCost:"Stromkosten pro kWh",energyDisplayMode:"Energieanzeige-Modus",energyModePrintDescription:"Dashboard zeigt Summe der während Drucken verbrauchten Energie",energyModeTotalDescription:"Dashboard zeigt Gesamtenergie der Smart Plugs",fileManager:"Dateimanager",createArchiveEntry:"Archiveintrag beim Drucken erstellen",createArchiveEntryDescription:"Beim Drucken aus dem Dateimanager optional einen Archiveintrag erstellen",lowDiskSpaceWarning:"Warnung bei wenig Speicherplatz",lowDiskSpaceDescription:"Warnung anzeigen, wenn freier Speicherplatz unter diesen Schwellenwert fällt",printerFirmware:"Drucker-Firmware",checkFirmwareDescription:"Nach Firmware-Updates von Bambu Lab suchen",bambuddySoftware:"Bambuddy Software",autoCheckDescription:"Automatisch beim Start nach neuen Versionen suchen",checkNow:"Jetzt prüfen",updateAvailableVersion:"Update verfügbar: v{{version}}",releaseNotes:"Versionshinweise",updateViaDocker:"Update über Docker Compose:",installUpdate:"Update installieren",latestVersionRunning:"Sie verwenden die neueste Version",failedToCheckUpdates:"Update-Prüfung fehlgeschlagen: {{error}}",backupRestore:"Sicherung & Wiederherstellung",backupRestoreDescription:"Einstellungen exportieren/importieren und GitHub-Backup konfigurieren",goToBackup:"Zur Sicherung",externalUrl:"Externe URL",externalUrlDescription:"Die externe URL, unter der Bambuddy erreichbar ist. Wird für Benachrichtigungsbilder und externe Integrationen verwendet.",bambuddyUrl:"Bambuddy-URL",externalUrlHint:"Protokoll und Port angeben (z.B. http://192.168.1.100:8000)",ftpRetry:"FTP-Wiederholung",ftpRetryDescription:"FTP-Operationen bei unzuverlässigem Drucker-WLAN wiederholen. Gilt für 3MF-Downloads, Druck-Uploads, Zeitraffer-Downloads und Firmware-Updates.",autoRetryDescription:"Fehlgeschlagene FTP-Operationen automatisch wiederholen",retryAttempts:"Wiederholungsversuche",retryDelay:"Wiederholungsverzögerung",connectionTimeout:"Verbindungs-Timeout",time_one:"{{count}} Mal",time_other:"{{count}} Mal",second_one:"{{count}} Sekunde",second_other:"{{count}} Sekunden",nSeconds:"{{count}} Sekunden",increaseForWeakWifi:"Erhöhen für Drucker mit schwachem WLAN",homeAssistant:"Home Assistant",homeAssistantFullDescription:"Mit Home Assistant verbinden, um Smart Plugs über die HA REST-API zu steuern. Unterstützt Switch-, Light-, Input_Boolean- und Script-Entitäten.",homeAssistantUrl:"Home Assistant URL",longLivedAccessToken:"Langlebiges Zugriffstoken",haTokenHint:"Token in HA erstellen: Profil → Langlebige Zugriffstoken → Token erstellen",connectionSuccessful:"Verbindung erfolgreich",connectionFailed:"Verbindung fehlgeschlagen",haConnectionSuccess:"Erfolgreich mit Home Assistant verbunden.",haConnectionFailed:"Verbindung zu Home Assistant fehlgeschlagen.",mqttPublishing:"MQTT-Veröffentlichung",mqttDescription:"BamBuddy-Ereignisse an einen externen MQTT-Broker zur Integration mit Node-RED, Home Assistant und anderen Automatisierungssystemen veröffentlichen.",mqttEnableDescription:"Ereignisse an externen MQTT-Broker veröffentlichen",brokerHostname:"Broker-Hostname",port:"Port",usernameOptional:"Benutzername (optional)",passwordOptional:"Passwort (optional)",topicPrefix:"Topic-Präfix",topicPrefixHint:"Topics werden sein: {{prefix}}/printers//status, etc.",prometheusMetrics:"Prometheus-Metriken",prometheusEndpointDescription:"Druckermetriken unter /api/v1/metrics für Prometheus/Grafana-Überwachung bereitstellen.",bearerTokenOptional:"Bearer-Token (optional)",bearerTokenHint:"Wenn gesetzt, müssen Anfragen Authorization: Bearer enthalten",metricsConnectionStatus:"Verbindungsstatus",metricsPrinterState:"Druckerstatus (idle/printing/etc)",metricsPrintProgress:"Druckfortschritt 0-100%",metricsBedTemp:"Betttemperatur",metricsNozzleTemp:"Düsentemperatur",metricsPrintsTotal:"Gesamtdrucke nach Ergebnis",metricsMore:"...und mehr (Schichten, Lüfter, Warteschlange, Filamentverbrauch)",smartPlugsDescription:"Smart Plugs (Tasmota oder Home Assistant) verbinden, um Stromsteuerung zu automatisieren und Energieverbrauch für Ihre Drucker zu verfolgen.",allOn:"Alle Ein",allOff:"Alle Aus",addSmartPlug:"Smart Plug hinzufügen",energySummary:"Energieübersicht",currentPower:"Aktuelle Leistung",plugsOnline:"{{reachable}}/{{total}} Plugs online",today:"Heute",yesterday:"Gestern",total:"Gesamt",enablePlugsForSummary:"Plugs aktivieren, um Energieübersicht zu sehen",addNotificationProvider:"Hinzufügen",systemBadge:"(System)",creating:"Erstellen...",changing:"Ändern...",deleteUserAndItems:"Benutzer UND dessen Elemente löschen",deleteUserKeepItems:"Benutzer löschen, Elemente behalten (werden herrenlos)",ok:"OK",twoFa:{totpTitle:"Authenticator-App (TOTP)",totpDesc:"Verwende eine Authenticator-App wie Google Authenticator, Aegis oder Authy.",emailOtpTitle:"E-Mail OTP",emailOtpDesc:"Sende einen Einmalcode an {{email}} beim Einloggen.",emailOtpNoEmail:"Füge eine E-Mail-Adresse zu deinem Konto hinzu, um diese Methode zu aktivieren.",addEmailFirst:"Dein Konto hat keine E-Mail-Adresse. Bitte einen Administrator, eine hinzuzufügen.",setupTotp:"Authenticator-App einrichten",setupAuthApp:"Authenticator-App einrichten",setupInstructions:"Scanne den QR-Code mit deiner Authenticator-App und bestätige mit einem Code.",manualEntry:"Kein Scanner? Gib dieses Secret manuell ein:",scannedContinue:"Code gescannt — weiter",enterCodeToConfirm:"Gib den 6-stelligen Code aus deiner Authenticator-App ein, um die Einrichtung zu bestätigen.",activate:"Aktivieren",disableTotp:"Authenticator deaktivieren",disableConfirmHint:"Gib einen gültigen TOTP-Code oder einen Backup-Code ein, um den Authenticator zu deaktivieren.",totpDisabled:"Authenticator-App deaktiviert.",emailOtpEnabled:"E-Mail OTP aktiviert.",emailOtpDisabled:"E-Mail OTP deaktiviert.",smtpRequired:"Bitte konfigurieren und testen Sie zuerst die SMTP-Einstellungen.",invalidCode:"Ungültiger Code. Bitte erneut versuchen.",enableEmailOtp:"E-Mail OTP aktivieren",disableEmailOtp:"E-Mail OTP deaktivieren",emailSetupEnterCode:"Ein Bestätigungscode wurde an Ihre E-Mail-Adresse gesendet. Geben Sie ihn unten ein, um zu bestätigen, dass Ihnen dieses Postfach gehört.",verifyAndEnable:"Verifizieren & Aktivieren",emailDisablePasswordHint:"Geben Sie Ihr Kontopasswort ein, um die Deaktivierung des E-Mail OTP zu bestätigen.",passwordPlaceholder:"Passwort eingeben",backupCodesTitle:"Backup-Codes sichern",backupCodesWarning:"Speichere diese Codes sicher. Jeder Code kann nur einmal verwendet werden und wird nicht erneut angezeigt.",backupCodesRemaining:"{{count}} Backup-Codes verbleibend",savedCodes:"Codes gespeichert",regenBackup:"Backup-Codes neu generieren",regenBackupHint:"Gib deinen aktuellen TOTP-Code ein, um 10 neue Backup-Codes zu generieren. Alle bestehenden Codes werden ungültig.",newBackupCodes:"Neue Backup-Codes",linkedAccounts:"Verknüpfte SSO-Konten",linkedAccountsDesc:"Diese externen Identitätsanbieter sind mit deinem Konto verknüpft.",oidcUnlinked:"Konto getrennt."},oidc:{title:"SSO / OIDC-Anbieter",desc:"Konfiguriere OpenID Connect-Anbieter für Single Sign-On.",addProvider:"Anbieter hinzufügen",newProvider:"Neuer Anbieter",empty:"Noch keine OIDC-Anbieter konfiguriert.",created:"Anbieter erstellt.",updated:"Anbieter aktualisiert.",deleted:"Anbieter gelöscht.",deleteTitle:"Anbieter löschen",deleteMessage:'"{{name}}" löschen? Alle verknüpften Benutzerkonten werden getrennt.',form:{name:"Anzeigename",issuerUrl:"Aussteller-URL",clientId:"Client-ID",clientSecret:"Client-Secret",scopes:"Scopes",iconUrl:"Symbol-URL (optional)",enabled:"Aktiviert",autoCreate:"Benutzer automatisch anlegen",autoCreateDesc:"Erstellt beim ersten Login automatisch ein lokales Konto.",autoLink:"Bestehende Konten automatisch verknüpfen",autoLinkDesc:"Verknüpft beim ersten Login vorhandene lokale Konten anhand der E-Mail-Adresse.",secretHint:"leer lassen zum Beibehalten",secretPlaceholder:"neues Secret"}}},notification:{printStarted:{title:"Druck gestartet",body:"{{printer}}: {{filename}} wird gedruckt"},printCompleted:{title:"Druck abgeschlossen",body:"{{printer}}: {{filename}} erfolgreich abgeschlossen"},printFailed:{title:"Druck fehlgeschlagen",body:"{{printer}}: {{filename}} ist fehlgeschlagen"},printStopped:{title:"Druck gestoppt",body:"{{printer}}: {{filename}} wurde gestoppt"},printProgress:{title:"Druckfortschritt",body:"{{printer}}: {{filename}} ist zu {{percent}}% abgeschlossen"},printerOffline:{title:"Drucker offline",body:"{{printer}} ist offline"},printerError:{title:"Druckerfehler",body:"{{printer}}: {{error}}"},filamentLow:{title:"Filament niedrig",body:"{{printer}}: Filament geht zur Neige"},maintenanceDue:{title:"Wartung fällig",body:"{{printer}}: {{items}} benötigen Aufmerksamkeit"}},errors:{generic:"Etwas ist schiefgelaufen",networkError:"Netzwerkfehler. Bitte überprüfen Sie Ihre Verbindung.",notFound:"Nicht gefunden",unauthorized:"Nicht autorisiert",serverError:"Serverfehler",validationError:"Bitte überprüfen Sie Ihre Eingabe",printerConnectionFailed:"Verbindung zum Drucker fehlgeschlagen",saveFailed:"Speichern fehlgeschlagen",deleteFailed:"Löschen fehlgeschlagen",loadFailed:"Laden der Daten fehlgeschlagen"},hmsErrors:{title:"Fehler - {{name}}",noErrors:"Keine Fehler",viewOnWiki:"Im Bambu Lab Wiki ansehen",clearInstructions:"Löschen Sie die Fehler am Drucker, um sie hier zu entfernen.",clearErrors:"Fehler löschen",clearSuccess:"HMS-Fehler gelöscht",clearFailed:"HMS-Fehler konnten nicht gelöscht werden"},mqttDebug:{title:"MQTT-Debug-Protokoll",searchPlaceholder:"Topic oder Payload suchen...",noMessages:"Noch keine Nachrichten protokolliert",startLoggingHint:'Klicken Sie auf "Protokollierung starten", um MQTT-Nachrichten aufzuzeichnen',noMessagesMatch:"Keine Nachrichten entsprechen Ihrem Filter",adjustFilterHint:"Versuchen Sie, Ihre Such- oder Filterkriterien anzupassen",incoming:"Eingehend",outgoing:"Ausgehend",loggingStopped:"Protokollierung gestoppt",loggingActive:"Protokollierung aktiv - Nachrichten werden automatisch aktualisiert",startLogging:"Protokollierung starten",stopLogging:"Protokollierung stoppen",clearLog:"Protokoll löschen",topic:"Topic",timestamp:"Zeitstempel",direction:"Richtung",all:"Alle"},printerFiles:{title:"Dateimanager",storageUsed:"Belegt:",storageFree:"Frei:",filterPlaceholder:"Dateien filtern...",deleteButton:"Löschen",deleteFiles:"{{count}} Dateien löschen",deleteFileConfirm:'"{{name}}" löschen? Dies kann nicht rückgängig gemacht werden.',deleteFilesConfirm:"{{count}} ausgewählte Dateien löschen? Dies kann nicht rückgängig gemacht werden.",noFiles:"Keine Dateien auf dem Drucker",loadingFiles:"Dateien werden geladen...",failedToLoad:"Dateien konnten nicht geladen werden",toast:{filesDeleted:"{{count}} Datei(en) gelöscht",deleteFailed:"Löschen fehlgeschlagen: {{error}}"}},confirm:{delete:"Möchten Sie dies wirklich löschen?",unsavedChanges:"Sie haben ungespeicherte Änderungen. Möchten Sie wirklich verlassen?",clearQueue:"Möchten Sie die Warteschlange wirklich leeren?"},login:{title:"Bambuddy Anmeldung",subtitle:"Melden Sie sich bei Ihrem Konto an",username:"Benutzername",usernamePlaceholder:"Benutzername eingeben",usernameOrEmail:"Benutzername oder E-Mail",usernameOrEmailPlaceholder:"Benutzername oder @ E-Mail",password:"Passwort",passwordPlaceholder:"Passwort eingeben",signIn:"Anmelden",signingIn:"Anmeldung läuft...",forgotPassword:"Passwort vergessen?",loginSuccess:"Erfolgreich angemeldet",loginFailed:"Anmeldung fehlgeschlagen",enterCredentials:"Bitte Benutzername und Passwort eingeben",enterEmail:"Bitte geben Sie Ihre E-Mail-Adresse ein",oidcLoginFailed:"OIDC-Anmeldung fehlgeschlagen",oidcErrors:{providerError:"Der Identity-Provider hat einen Fehler zurückgegeben",missingParameters:"Dem OIDC-Callback fehlen erforderliche Parameter",invalidState:"OIDC-State ist ungültig oder wurde bereits verwendet",stateExpired:"OIDC-Sitzung abgelaufen — bitte erneut versuchen",providerNotFound:"OIDC-Provider nicht gefunden",discoveryFailed:"OIDC-Discovery-Dokument konnte nicht abgerufen werden",invalidDiscovery:"OIDC-Discovery-Dokument ist ungültig",networkError:"Netzwerkfehler beim OIDC-Token-Austausch",badResponse:"Unerwartete Antwort beim OIDC-Token-Austausch",noIdToken:"OIDC-Provider hat kein ID-Token zurückgegeben",validationFailed:"OIDC-Token-Validierung fehlgeschlagen",nonceMismatch:"OIDC-Nonce stimmt nicht überein — möglicher Replay-Angriff",missingSubClaim:"OIDC-Token enthält keinen Sub-Claim",noLinkedAccount:"Kein lokales Konto mit dieser OIDC-Identität verknüpft",accountInactive:"Ihr Konto ist inaktiv",userResolutionFailed:"Ihr Konto konnte nicht aufgelöst werden",internalError:"Interner Fehler beim OIDC-Login",tokenExchangeFailed:"OIDC-Token-Austausch fehlgeschlagen"},forgotPasswordTitle:"Passwort vergessen",forgotPasswordMessage:"Wenn Sie Ihr Passwort vergessen haben, wenden Sie sich bitte an Ihren Systemadministrator.",forgotPasswordEmailMessage:"Geben Sie Ihre E-Mail-Adresse ein und wir senden Ihnen ein neues Passwort.",emailAddress:"E-Mail-Adresse",emailPlaceholder:"ihre.email@beispiel.de",cancel:"Abbrechen",sending:"Wird gesendet...",sendResetEmail:"Zurücksetzungs-E-Mail senden",howToReset:"So setzen Sie Ihr Passwort zurück:",resetStep1:"Kontaktieren Sie Ihren Bambuddy-Administrator",resetStep2:"Bitten Sie ihn, Ihr Passwort in der Benutzerverwaltung zurückzusetzen",resetStep3:"Er kann ein neues temporäres Passwort für Sie festlegen",resetStep4:"Melden Sie sich mit dem neuen Passwort an und ändern Sie es in den Einstellungen",gotIt:"Verstanden",resetPassword:{title:"Neues Passwort festlegen",subtitle:"Geben Sie unten Ihr neues Passwort ein und bestätigen Sie es.",newPassword:"Neues Passwort",newPasswordPlaceholder:"Mindestens 8 Zeichen",confirmPassword:"Passwort bestätigen",confirmPasswordPlaceholder:"Neues Passwort wiederholen",saving:"Wird gespeichert…",submit:"Neues Passwort festlegen",backToLogin:"Zurück zur Anmeldung",passwordsDoNotMatch:"Passwörter stimmen nicht überein",passwordTooShort:"Passwort muss mindestens 8 Zeichen lang sein",resetFailed:"Passwort zurücksetzen fehlgeschlagen. Der Link ist möglicherweise abgelaufen."},twoFA:{title:"Zwei-Faktor-Authentifizierung",subtitle:"Ihr Konto ist mit 2FA geschützt. Geben Sie unten den Bestätigungscode ein.",methodAuthenticator:"Authenticator-App",methodEmail:"E-Mail-Code",methodBackup:"Wiederherstellungscode",instructionsTotp:"Öffnen Sie Ihre Authenticator-App und geben Sie den 6-stelligen Code für Bambuddy ein.",instructionsEmail:"Ein 6-stelliger Code wurde an Ihre E-Mail-Adresse gesendet. Er ist 10 Minuten gültig.",instructionsEmailNotSent:"Klicken Sie unten, um einen Bestätigungscode per E-Mail zu erhalten.",instructionsBackup:"Geben Sie einen Ihrer 8-stelligen Wiederherstellungscodes ein. Jeder Code kann nur einmal verwendet werden.",sendCodeButton:"Code per E-Mail senden",sendingCode:"Wird gesendet...",resendCode:"Code erneut senden",codeLabel:"Bestätigungscode",backupCodeLabel:"Wiederherstellungscode",codePlaceholder:"000000",backupCodePlaceholder:"XXXXXXXX",verifyButton:"Bestätigen",verifyingButton:"Wird überprüft...",backToLogin:"← Zurück zur Anmeldung",orContinueWith:"oder anmelden mit",signInWith:"Anmelden mit {{provider}}",enterCode:"Bitte geben Sie den Bestätigungscode ein",sendCodeFailed:"Bestätigungscode konnte nicht gesendet werden",invalidCode:"Ungültiger Code. Bitte erneut versuchen."}},setup:{title:"Bambuddy Einrichtung",subtitle:"Konfigurieren Sie die Authentifizierung für Ihre Bambuddy-Instanz",enableAuth:"Authentifizierung aktivieren",adminAccount:"Admin-Konto",adminAccountDesc:"Wenn bereits Admin-Benutzer existieren, wird die Authentifizierung mit den vorhandenen Admin-Konten aktiviert. Lassen Sie die Felder unten leer, um vorhandene Admins zu verwenden, oder geben Sie neue Anmeldedaten ein, um einen neuen Admin-Benutzer zu erstellen.",adminUsername:"Admin-Benutzername",adminPassword:"Admin-Passwort",optionalIfAdminExists:"(optional, wenn Admin-Benutzer existieren)",adminUsernamePlaceholder:"Admin-Benutzernamen eingeben (optional)",adminPasswordPlaceholder:"Admin-Passwort eingeben (optional)",confirmPassword:"Passwort bestätigen",confirmPasswordPlaceholder:"Admin-Passwort bestätigen",settingUp:"Einrichtung läuft...",completeSetup:"Einrichtung abschließen",toast:{authEnabledAdminCreated:"Authentifizierung aktiviert und Admin-Benutzer erstellt",authEnabledExistingAdmins:"Authentifizierung mit vorhandenen Admin-Benutzern aktiviert",setupCompleted:"Einrichtung abgeschlossen",enterBothCredentials:"Bitte geben Sie sowohl Admin-Benutzernamen als auch Passwort ein, oder lassen Sie beide leer, um vorhandene Admin-Benutzer zu verwenden",passwordsDoNotMatch:"Passwörter stimmen nicht überein",passwordTooShort:"Passwort muss mindestens 6 Zeichen lang sein"}},changePassword:{title:"Passwort ändern",currentPassword:"Aktuelles Passwort",currentPasswordPlaceholder:"Aktuelles Passwort eingeben",newPassword:"Neues Passwort",newPasswordPlaceholder:"Neues Passwort eingeben (min. 6 Zeichen)",confirmPassword:"Neues Passwort bestätigen",confirmPasswordPlaceholder:"Neues Passwort bestätigen",passwordsDoNotMatch:"Passwörter stimmen nicht überein",passwordTooShort:"Passwort muss mindestens 6 Zeichen lang sein",changing:"Wird geändert...",success:"Passwort erfolgreich geändert",failed:"Passwortänderung fehlgeschlagen"},plateAlert:{title:"Druck pausiert!",message:"Objekte auf dem Druckbett erkannt. Der Druck wurde automatisch pausiert. Bitte räumen Sie das Druckbett und setzen Sie den Druck fort.",understand:"Verstanden"},camera:{title:"Kameraansicht",invalidPrinterId:"Ungültige Drucker-ID",live:"Live",snapshot:"Schnappschuss",restartStream:"Stream neu starten",refreshSnapshot:"Schnappschuss aktualisieren",fullscreen:"Vollbild",exitFullscreen:"Vollbild beenden",connectingToCamera:"Verbinde mit Kamera...",capturingSnapshot:"Schnappschuss wird aufgenommen...",connectionLost:"Verbindung verloren",connectionFailed:"Kameraverbindung fehlgeschlagen",reconnecting:"Neuverbindung in {{countdown}}s... (Versuch {{attempt}}/{{max}})",reconnectNow:"Jetzt verbinden",cameraUnavailable:"Kamera nicht verfügbar",cameraUnavailableDesc:"Stellen Sie sicher, dass der Drucker eingeschaltet und verbunden ist.",noCamera:"Keine Kamera verfügbar",retry:"Erneut versuchen",cameraStream:"Kamera-Stream",zoomOut:"Verkleinern",zoomIn:"Vergrößern",resetZoom:"Zoom zurücksetzen",recording:"Aufnahme",startRecording:"Aufnahme starten",stopRecording:"Aufnahme stoppen",chamberLight:"Kammerbeleuchtung umschalten"},groups:{title:"Gruppenverwaltung",subtitle:"Berechtigungsgruppen für Zugriffskontrolle verwalten",backToSettings:"Zurück zu Einstellungen",createGroup:"Gruppe erstellen",noPermission:"Sie haben keine Berechtigung, auf diese Seite zuzugreifen.",system:"System",noDescription:"Keine Beschreibung",usersCount:"{{count}} Benutzer",permissionsCount:"{{count}} Berechtigungen",edit:"Bearbeiten",delete:"Löschen",toast:{created:"Gruppe erfolgreich erstellt",updated:"Gruppe erfolgreich aktualisiert",deleted:"Gruppe erfolgreich gelöscht",enterGroupName:"Bitte geben Sie einen Gruppennamen ein"},modal:{editGroup:"Gruppe bearbeiten",createGroup:"Gruppe erstellen",cancel:"Abbrechen",saving:"Speichern...",creating:"Erstellen...",saveChanges:"Änderungen speichern"},form:{groupName:"Gruppenname",groupNamePlaceholder:"Gruppennamen eingeben",systemGroupWarning:"Systemgruppennamen können nicht geändert werden",description:"Beschreibung",descriptionPlaceholder:"Beschreibung eingeben (optional)",permissions:"Berechtigungen ({{count}} ausgewählt)"},deleteModal:{title:"Gruppe löschen",message:"Sind Sie sicher, dass Sie diese Gruppe löschen möchten? Benutzer in dieser Gruppe verlieren diese Berechtigungen.",confirm:"Gruppe löschen"},editor:{title:"Gruppe bearbeiten",createTitle:"Gruppe erstellen",search:"Berechtigungen suchen...",selectAll:"Alle auswählen",clearAll:"Alle abwählen",permissionsSelected:"{{count}} ausgewählt",noResults:"Keine Berechtigungen entsprechen Ihrer Suche"}},users:{title:"Benutzerverwaltung",subtitle:"Benutzer und deren Zugriff auf Ihre Bambuddy-Instanz verwalten",backToSettings:"Zurück zu Einstellungen",createUser:"Benutzer erstellen",noPermission:"Sie haben keine Berechtigung, auf diese Seite zuzugreifen.",admin:"Admin",noGroups:"Keine Gruppen",active:"Aktiv",inactive:"Inaktiv",edit:"Bearbeiten",delete:"Löschen",system:"System",noGroupsAvailable:"Keine Gruppen verfügbar",table:{username:"Benutzername",groups:"Gruppen",status:"Status",actions:"Aktionen"},toast:{created:"Benutzer erfolgreich erstellt",updated:"Benutzer erfolgreich aktualisiert",deleted:"Benutzer erfolgreich gelöscht",fillRequired:"Bitte füllen Sie alle Pflichtfelder aus",passwordsDoNotMatch:"Passwörter stimmen nicht überein",passwordTooShort:"Passwort muss mindestens 6 Zeichen lang sein"},modal:{createUser:"Benutzer erstellen",editUser:"Benutzer bearbeiten",cancel:"Abbrechen",creating:"Erstellen...",saving:"Speichern...",saveChanges:"Änderungen speichern",advancedAuthSubtitle:"mit erweiterter Authentifizierung"},form:{username:"Benutzername",usernamePlaceholder:"Benutzernamen eingeben",email:"E-Mail",emailPlaceholder:"benutzer@beispiel.de",password:"Passwort",passwordPlaceholder:"Passwort eingeben",confirmPassword:"Passwort bestätigen",confirmPasswordPlaceholder:"Passwort bestätigen",newPasswordPlaceholder:"Neues Passwort eingeben",confirmNewPasswordPlaceholder:"Neues Passwort bestätigen",leaveBlankToKeep:"leer lassen, um das aktuelle zu behalten",groups:"Gruppen",optional:"optional",autoGeneratedPassword:"Ein sicheres Passwort wird automatisch generiert und per E-Mail an den Benutzer gesendet.",passwordManagedByAdvancedAuth:'Das Passwort wird durch erweiterte Authentifizierung verwaltet. Verwenden Sie "Passwort zurücksetzen", um ein neues Passwort per E-Mail an den Benutzer zu senden.',resetPassword:"Passwort zurücksetzen",resettingPassword:"Passwort wird zurückgesetzt..."},deleteModal:{title:"Benutzer löschen",message:"Sind Sie sicher, dass Sie diesen Benutzer löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",confirm:"Benutzer löschen"}},streamOverlay:{title:"Stream-Overlay",invalidPrinterId:"Ungültige Drucker-ID",cameraStream:"Kamera-Stream",progress:"Fortschritt",eta:"ETA",printerIdle:"Drucker ist inaktiv",printerOffline:"Drucker offline",status:{printing:"Druckt",paused:"Pausiert",finished:"Fertig",failed:"Fehlgeschlagen",idle:"Inaktiv",unknown:"Unbekannt"}},profiles:{title:"Profile",subtitle:"Verwalten Sie Ihre Slicer-Voreinstellungen und Druckvorschub-Kalibrierungen",tabs:{cloud:"Cloud-Profile",local:"Lokale Profile",kprofiles:"K-Profile"},localProfiles:{title:"Lokale Profile",subtitle:"Slicer-Voreinstellungen aus OrcaSlicer importieren und verwalten",import:"Profile importieren",importDesc:".bbscfg-, .bbsflmt-, .orca_filament-, .zip- oder .json-Dateien hier ablegen",importing:"Importiere...",search:"Lokale Voreinstellungen durchsuchen...",noPresets:"Noch keine lokalen Voreinstellungen",badge:"Lokal",edit:"Bearbeiten",delete:"Löschen",cancel:"Abbrechen",deleteConfirmTitle:"Voreinstellung löschen",deleteConfirm:"Möchten Sie diese Voreinstellung wirklich löschen? Dies kann nicht rückgängig gemacht werden.",source:"Quelle",inheritsFrom:"Erbt von",filamentType:"Typ",vendor:"Hersteller",compatiblePrinters:"Drucker",nozzleTemp:"Düsentemperatur",cost:"Kosten",density:"Dichte",pressureAdvance:"Druckvorschub",filament:"Filament",process:"Prozess",printer:"Drucker",toast:{importSuccess:"{{count}} Voreinstellung(en) importiert",importSkipped:"{{count}} Voreinstellung(en) übersprungen (Duplikate)",importError:"{{count}} Fehler beim Import",deleted:"Voreinstellung gelöscht",updated:"Voreinstellung aktualisiert"}},connectedAs:"Verbunden als",logout:"Abmelden",noLogoutPermission:"Sie haben keine Berechtigung zum Abmelden",failedToLoad:"Profile konnten nicht geladen werden",retry:"Erneut versuchen",time:{justNow:"Gerade eben",minsAgo:"vor {{count}}m",hoursAgo:"vor {{count}}h",daysAgo:"vor {{count}}d"},toast:{loggedOut:"Abgemeldet"},login:{title:"Mit Bambu Cloud verbinden",subtitle:"Synchronisieren Sie Ihre Slicer-Voreinstellungen geräteübergreifend",email:"E-Mail",password:"Passwort",region:"Region",regionGlobal:"Global",regionChina:"China",verificationCode:"Bestätigungscode",totpCode:"Authenticator-Code",checkEmail:"Prüfen Sie Ihre E-Mail ({{email}}) für einen 6-stelligen Code",enterTotpHint:"Geben Sie den 6-stelligen Code aus Ihrer Authenticator-App ein",accessToken:"Zugriffstoken",accessTokenHint:"Fügen Sie Ihr Bambu Lab Zugriffstoken ein (aus Bambu Studio)",back:"Zurück",loginButton:"Anmelden",verifyButton:"Bestätigen",setTokenButton:"Token setzen",useToken:"Stattdessen Zugriffstoken verwenden",useEmail:"Stattdessen mit E-Mail anmelden",toast:{loggedIn:"Erfolgreich angemeldet",codeSent:"Bestätigungscode an Ihre E-Mail gesendet",enterTotp:"Geben Sie den Code aus Ihrer Authenticator-App ein",tokenSet:"Token erfolgreich gesetzt"}},presets:{myPreset:"Mein Profil (bearbeitbar)",duplicate:"Duplizieren",editable:"Bearbeitbar",failedToLoadDetails:"Profil-Details konnten nicht geladen werden",deleteConfirm:"Dieses Profil löschen?",deleteWarning:'"{{name}}" wird dauerhaft aus Bambu Cloud gelöscht. Dies kann nicht rückgängig gemacht werden.',noDuplicatePermission:"Sie haben keine Berechtigung zum Duplizieren von Profilen",noEditPermission:"Sie haben keine Berechtigung zum Bearbeiten von Profilen",noDeletePermission:"Sie haben keine Berechtigung zum Löschen von Profilen",types:{filament:"Filament-Profil",printer:"Drucker-Profil",process:"Prozess-Profil"},toast:{deleted:"Profil gelöscht",created:"Profil erstellt",updated:"Profil aktualisiert",duplicated:"Profil dupliziert",fieldAdded:'Feld "{{key}}" hinzugefügt',exported:"Profil exportiert"},baseLabel:"Basis: {{name}}",currentLabel:"Aktuell: {{name}}",newPreset:"Neues Profil",editPreset:"Profil bearbeiten",duplicatePreset:"Profil duplizieren",createNewPreset:"Neues Profil erstellen",customizeSettings:"Passen Sie die Einstellungen für Ihr neues Profil an",compareWithBase:"Mit Basis-Profil vergleichen",compare:"Vergleichen",basePreset:"Basis-Profil",selectBasePreset:"Basis-Profil auswählen...",presetName:"Profilname",myCustomPreset:"Mein eigenes Profil",inheritsFrom:"Erbt von",dropJsonToImport:"JSON zum Importieren ablegen",tabs:{common:"Allgemein",allFields:"Alle Felder"},availableFields:"Verfügbare Felder",searchFieldsPlaceholder:"Felder suchen...",noMatchingFields:"Keine passenden Felder",allFieldsAdded:"Alle Felder hinzugefügt",addCustomField:"Eigenes Feld hinzufügen",yourOverrides:"Ihre Überschreibungen",noOverridesYet:"Noch keine Überschreibungen",clickFieldsToAdd:"Klicken Sie links auf Felder, um sie hinzuzufügen",saveAsTemplate:"Als Vorlage speichern",jsonTip:"Tipp: Ziehen Sie eine .json-Datei auf dieses Fenster, um Einstellungen zu importieren"},cloudView:{searchPlaceholder:"Profile suchen...",templates:"Vorlagen",refresh:"Aktualisieren",newPreset:"Neues Profil",clearFilters:"Filter zurücksetzen",compareMode:"Vergleichsmodus",selectAnotherPreset:"Wählen Sie ein weiteres {{type}}-Profil",clickTwoPresets:"Klicken Sie auf zwei Profile des gleichen Typs zum Vergleichen",selectFirst:"1. Erstes auswählen",selectSecond:"2. Zweites auswählen",compareNow:"Jetzt vergleichen",lastSynced:"Zuletzt synchronisiert:",showingCount:"{{showing}} von {{total}} Profilen",noPresetsFound:"Keine Profile gefunden",columns:{filament:"Filament",process:"Prozess",printer:"Drucker"},noFilamentPresets:"Keine Filament-Profile",noProcessPresets:"Keine Prozess-Profile",noPrinterPresets:"Keine Drucker-Profile",filters:{type:"Typ",owner:"Besitzer",printer:"Drucker",nozzle:"Düse",filament:"Filament",layer:"Schicht",all:"Alle",myPresets:"Meine Profile",builtIn:"Voreingestellt",process:"Prozess"},noTemplatesPermission:"Sie haben keine Berechtigung, Vorlagen zu verwalten",noRefreshPermission:"Sie haben keine Berechtigung, Profile zu aktualisieren",noCreatePermission:"Sie haben keine Berechtigung, Profile zu erstellen"},templates:{title:"Schnellvorlagen",noTemplates:"Noch keine Vorlagen",createFirst:"Erstellen Sie Vorlagen aus dem Preset-Editor",typeFilter:"Typ:",deleteTitle:"Vorlage löschen",deleteWarning:"Diese Aktion kann nicht rückgängig gemacht werden",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen?',namePlaceholder:"Vorlagenname",descriptionPlaceholder:"Beschreibung",settingsJson:"Einstellungen (JSON)",fieldsCount:"{{count}} Felder",shownInModals:"In Dialogen angezeigt",hiddenInModals:"In Dialogen ausgeblendet",apply:"Anwenden",toast:{deleted:"Vorlage gelöscht",updated:"Vorlage aktualisiert",created:"Vorlage erstellt",applied:"Vorlage angewendet"}}},support:{debugLoggingActive:"Debug-Protokollierung ist aktiv",manageLogs:"Verwalten",collectItem7:"Drucker-Verbindungsstatus und Firmware-Versionen",collectItem8:"Integrationsstatus (Spoolman, MQTT, HA)",collectItem9:"Netzwerkschnittstellen (nur Subnetze)",collectItem10:"Python-Paketversionen",collectItem11:"Datenbankzustandsprüfungen",collectItem12:"Docker-Umgebungsdetails"},fileManager:{title:"Dateimanager",subtitle:"Organisieren und verwalten Sie Ihre Druckdateien",uploadFiles:"Dateien hochladen",newFolder:"Neuer Ordner",folderName:"Ordnername",folderNamePlaceholder:"z.B. Funktionsteile",renameFile:"Datei umbenennen",renameFolder:"Ordner umbenennen",moveFiles:"{{count}} Datei(en) verschieben",rootNoFolder:"Stammverzeichnis (Kein Ordner)",current:"aktuell",linkFolder:"Ordner verknüpfen",linkFolderDescription:'"{{name}}" mit einem Projekt oder Archiv verknüpfen für schnellen Zugriff.',project:"Projekt",archive:"Archiv",noProjectsFound:"Keine Projekte gefunden",noArchivesFound:"Keine Archive gefunden",unlink:"Verknüpfung aufheben",link:"Verknüpfen",dragDropFiles:"Dateien hierher ziehen",dropFilesHere:"Dateien hier ablegen",orClickToBrowse:"oder klicken zum Durchsuchen",allFileTypesSupported:"Alle Dateitypen werden unterstützt. ZIP-Dateien werden extrahiert.",zipFilesDetected:"ZIP-Dateien erkannt",zipExtractOptions:"ZIP-Dateien werden extrahiert. Wählen Sie, wie die Ordnerstruktur behandelt werden soll:",preserveZipStructure:"Ordnerstruktur aus ZIP beibehalten",createFolderFromZip:"Ordner aus ZIP-Dateiname erstellen",stlThumbnailGeneration:"STL-Vorschaubildgenerierung",zipMayContainStl:"ZIP-Dateien können STL-Dateien enthalten. Vorschaubilder können während der Extraktion generiert werden.",thumbnailsCanBeGenerated:"Vorschaubilder können für STL-Dateien generiert werden. Große Modelle benötigen möglicherweise mehr Zeit.",generateThumbnailsForStl:"Vorschaubilder für STL-Dateien generieren",threemfDetected:"3MF-Dateien erkannt",threemfExtractionInfo:"Druckermodell, Material, Farbe und Druckeinstellungen werden automatisch aus 3MF-Dateien extrahiert.",willBeExtracted:"Wird extrahiert",filesExtracted:"{{count}} Dateien extrahiert",uploadComplete:"Upload abgeschlossen: {{succeeded}} erfolgreich",uploadFailed:"Hochladen fehlgeschlagen",zipFilesFailed:"{{count}} Dateien fehlgeschlagen",uploading:"Hochladen...",changeLink:"Verknüpfung ändern...",linkTo:"Verknüpfen mit...",linkToProjectOrArchive:"Mit Projekt oder Archiv verknüpfen",addToQueue:"Zur Warteschlange",schedulePrint:"Planen",generateThumbnail:"Vorschaubild generieren",generateThumbnails:"Vorschaubilder generieren",generateThumbnailsForMissing:"Vorschaubilder für STL-Dateien ohne Vorschau generieren",gridView:"Rasteransicht",listView:"Listenansicht",lowDiskSpaceWarning:"Warnung: Wenig Speicherplatz",lowDiskSpaceDetails:"Nur {{free}} frei von {{total}} gesamt. Schwellenwert ist auf {{threshold}} GB eingestellt.",files:"Dateien",folders:"Ordner",size:"Größe",free:"Frei",allFiles:"Alle Dateien",wrap:"Umbrechen",enableTextWrapping:"Textumbruch aktivieren",disableTextWrapping:"Textumbruch deaktivieren",collapse:"Einklappen",collapseFoldersByDefault:"Ordner standardmäßig einklappen",expandFoldersByDefault:"Ordner standardmäßig ausklappen",dragToResizeTooltip:"Ziehen zum Ändern der Größe, Doppelklick zum Zurücksetzen",searchFiles:"Dateien suchen...",allTypes:"Alle Typen",prints:"Drucke",ascending:"Aufsteigend",descending:"Absteigend",resultsCount:"{{showing}} von {{total}} Dateien",selectAll:"Alle auswählen",deselectAll:"Auswahl aufheben",selected:"{{count}} ausgewählt",adding:"Hinzufügen...",loadingFiles:"Dateien werden geladen...",folderIsEmpty:"Ordner ist leer",noFilesYet:"Noch keine Dateien",folderEmptyDescription:"Laden Sie Dateien hoch oder verschieben Sie Dateien in diesen Ordner.",noFilesDescription:"Laden Sie Dateien hoch, um Ihre Druckdateien zu organisieren.",noMatchingFiles:"Keine passenden Dateien",noMatchingFilesDescription:"Keine Dateien entsprechen Ihren aktuellen Such- oder Filterkriterien.",clearFilters:"Filter zurücksetzen",printedCount:"{{count}}x gedruckt",uploadedBy:"Hochgeladen von",deleteFolder:"Ordner löschen",deleteFile:"Datei löschen",deleteFilesCount:"{{count}} Dateien löschen",deleteFolderConfirm:"Möchten Sie diesen Ordner wirklich löschen? Alle Dateien darin werden ebenfalls gelöscht.",deleteFileConfirm:"Möchten Sie diese Datei wirklich löschen?",deleteFilesConfirm:"Möchten Sie {{count}} ausgewählte Dateien wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.",deleting:"Wird gelöscht...",noPermissionRenameFolder:"Sie haben keine Berechtigung, Ordner umzubenennen",noPermissionLinkFolder:"Sie haben keine Berechtigung, Ordner zu verknüpfen",noPermissionDeleteFolder:"Sie haben keine Berechtigung, Ordner zu löschen",noPermissionPrint:"Sie haben keine Berechtigung zum Drucken",noPermissionAddToQueue:"Sie haben keine Berechtigung, zur Warteschlange hinzuzufügen",noPermissionDownload:"Sie haben keine Berechtigung, Dateien herunterzuladen",noPermissionRenameFile:"Sie haben keine Berechtigung, diese Datei umzubenennen",noPermissionGenerateThumbnail:"Sie haben keine Berechtigung, Vorschaubilder zu generieren",noPermissionDeleteFile:"Sie haben keine Berechtigung, diese Datei zu löschen",noPermissionCreateFolder:"Sie haben keine Berechtigung, Ordner zu erstellen",noPermissionUpload:"Sie haben keine Berechtigung, Dateien hochzuladen",noPermissionMoveFiles:"Sie haben keine Berechtigung, Dateien zu verschieben",noPermissionDeleteFiles:"Sie haben keine Berechtigung, Dateien zu löschen",linkExternal:"Extern verknüpfen",linkExternalFolder:"Externen Ordner verknüpfen",linkExternalFolderDescription:"Ein Host-Verzeichnis (NAS, USB, Netzlaufwerk) in den Dateimanager einbinden. Dateien werden nicht kopiert — sie werden direkt vom Originalpfad gelesen.",externalFolderNamePlaceholder:"z.B. NAS-Drucke",externalPath:"Host-Pfad",externalPathHelp:"Absoluter Pfad zum Verzeichnis auf dem Docker-Host. Muss als Bind-Mount in den Container eingebunden sein.",readOnly:"Nur Lesen",readOnlyHelp:"verhindert Uploads und Löschungen",showHiddenFiles:"Versteckte Dateien anzeigen (Punkt-Dateien)",externalFolder:"Externer Ordner",scanFolder:"Scannen",toast:{folderCreated:"Ordner erstellt",folderDeleted:"Ordner gelöscht",fileDeleted:"Datei gelöscht",filesDeleted:"{{count}} Dateien gelöscht",filesMoved:"Dateien verschoben",folderLinked:"Ordner verknüpft",folderUnlinked:"Ordnerverknüpfung aufgehoben",externalFolderLinked:"Externer Ordner verknüpft und gescannt",folderScanned:"Scan abgeschlossen: {{added}} hinzugefügt, {{removed}} entfernt",addedToQueue:"{{count}} Datei(en) zur Warteschlange hinzugefügt",addedToQueuePartial:"{{added}} Datei(en) hinzugefügt, {{failed}} fehlgeschlagen",failedToAddToQueue:"Fehler beim Hinzufügen: {{error}}",fileRenamed:"Datei umbenannt",folderRenamed:"Ordner umbenannt",thumbnailsGenerated:"{{count}} Vorschaubild(er) generiert",thumbnailsGeneratedPartial:"{{succeeded}} Vorschaubild(er) generiert, {{failed}} fehlgeschlagen",noStlMissingThumbnails:"Keine STL-Dateien ohne Vorschaubild",failedToGenerateThumbnails:"Fehler beim Generieren der Vorschaubilder: {{error}}",thumbnailGenerated:"Vorschaubild generiert",failedToGenerateThumbnail:"Fehler beim Generieren des Vorschaubildes: {{error}}"}},projects:{title:"Projekte",subtitle:"Organisieren und verfolgen Sie Ihre 3D-Druckprojekte",newProject:"Neues Projekt",editProject:"Projekt bearbeiten",deleteProject:"Projekt löschen",projectName:"Projektname",description:"Beschreibung",noProjects:"Noch keine Projekte",noProjectsFiltered:"Keine {{status}} Projekte",noProjectsFilteredHelp:"Sie haben keine {{status}} Projekte. Projekte werden hier angezeigt, wenn sich ihr Status ändert.",createFirst:"Erstellen Sie Ihr erstes Projekt, um verwandte Drucke zu organisieren, den Fortschritt zu verfolgen und Ihre Builds zu verwalten.",createFirstButton:"Erstes Projekt erstellen",create:"Erstellen",files:"Dateien",prints:"Drucke",plates:"Platten",parts:"Teile",lastModified:"Zuletzt geändert",deleteConfirm:"Möchten Sie dieses Projekt wirklich löschen? Archive und Warteschlangenelemente werden getrennt, aber nicht gelöscht.",addFiles:"Dateien hinzufügen",removeFile:"Datei entfernen",viewDetails:"Details anzeigen",namePlaceholder:"z.B. Voron 2.4 Build",descriptionPlaceholder:"Optionale Beschreibung...",color:"Farbe",targetPlates:"Ziel-Platten",targetPlatesPlaceholder:"z.B. 25",targetPlatesHelp:"Anzahl der Druckaufträge",targetParts:"Ziel-Teile",targetPartsPlaceholder:"z.B. 150",targetPartsHelp:"Benötigte Objekte insgesamt",tagsLabel:"Tags (kommagetrennt)",tagsPlaceholder:"z.B. voron, funktional, geschenk",dueDate:"Fälligkeitsdatum",priority:"Priorität",priorityLow:"Niedrig",priorityNormal:"Normal",priorityHigh:"Hoch",priorityUrgent:"Dringend",statusActive:"Aktiv",statusCompleted:"Abgeschlossen",statusArchived:"Archiviert",done:"Fertig",completed:"abgeschlossen",failed:"fehlgeschlagen",inQueue:"in Warteschlange",noPrintsYet:"Noch keine Drucke",printJobs:"Druckaufträge (Platten)",partsPrinted:"Gedruckte Teile",failedParts:"Fehlgeschlagene Teile",import:"Importieren",export:"Exportieren",importProject:"Projekt importieren",exportAll:"Alle Projekte exportieren",loading:"Projekte werden geladen...",noEditPermission:"Sie haben keine Berechtigung, Projekte zu bearbeiten",noDeletePermission:"Sie haben keine Berechtigung, Projekte zu löschen",noCreatePermission:"Sie haben keine Berechtigung, Projekte zu erstellen",noImportPermission:"Sie haben keine Berechtigung, Projekte zu importieren",noExportPermission:"Sie haben keine Berechtigung, Projekte zu exportieren",toast:{created:"Projekt erstellt",updated:"Projekt aktualisiert",deleted:"Projekt gelöscht",imported:"Projekt importiert",multipleImported:"{{count}} Projekte importiert",importFailed:"Import fehlgeschlagen",exported:"Projekte exportiert (nur Metadaten)"}},projectDetail:{notFound:"Projekt nicht gefunden",backToProjects:"Zurück zu Projekten",export:"Exportieren",exportProject:"Projekt exportieren",noExportPermission:"Sie haben keine Berechtigung, Projekte zu exportieren",noEditPermission:"Sie haben keine Berechtigung, Projekte zu bearbeiten",partOf:"Teil von:",priorityLabel:"Priorität:",noPrints:"Noch keine Drucke in diesem Projekt",status:{active:"Aktiv",completed:"Abgeschlossen",archived:"Archiviert"},priority:{low:"Niedrig",normal:"Normal",high:"Hoch",urgent:"Dringend"},dueDate:{overdue:"Überfällig",today:"Heute fällig",daysLeft:"{{count}} Tage übrig"},progress:{platesProgress:"Platten-Fortschritt",partsProgress:"Teile-Fortschritt",printJobs:"Druckaufträge",parts:"Teile",percentComplete:"{{percent}}% abgeschlossen",remaining:"{{count}} verbleibend"},stats:{printJobs:"Druckaufträge",total:"gesamt",failed:"{{count}} fehlgeschlagen",partsPrinted:"{{count}} Teile gedruckt",printTime:"Druckzeit",filamentUsed:"Filament verbraucht"},cost:{title:"Kostenverfolgung",filamentCost:"Filamentkosten",energy:"Energie",totalCost:"Gesamtkosten",total:"Gesamt",includesBom:"inkl. Stückliste",budget:"Budget",remaining:"Verbleibend"},subProjects:{title:"Unterprojekte ({{count}})"},notes:{title:"Notizen",noEditPermission:"Sie haben keine Berechtigung, Notizen zu bearbeiten",placeholder:"Notizen zu diesem Projekt hinzufügen...",empty:"Noch keine Notizen. Klicken Sie auf Bearbeiten, um Notizen hinzuzufügen."},files:{title:"Dateien",linkFolders:"Ordner aus dem Dateimanager verknüpfen",forQuickAccess:"für schnellen Zugriff auf dieses Projekt.",fileCount:"{{count}} Datei(en)",empty:"Keine Ordner verknüpft. Gehen Sie zum Dateimanager und verknüpfen Sie einen Ordner mit diesem Projekt.",noFiles:"Keine Dateien in diesem Ordner.",print:"Jetzt drucken",addToQueue:"Zur Warteschlange"},bom:{title:"Stückliste",acquired:"{{completed}}/{{total}} beschafft",showAll:"Alle anzeigen",hideDone:"Erledigte ausblenden",addPart:"Teil hinzufügen",noAddPermission:"Sie haben keine Berechtigung, Teile hinzuzufügen",partNamePlaceholder:"Teilename (z.B. M3x8 Schrauben)",partName:"Teilename",qty:"Menge",price:"Preis ({{currency}})",sourcingUrlPlaceholder:"Bezugsquelle-URL (optional)",remarksPlaceholder:"Bemerkungen (optional)",deletePart:"Teil löschen",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen?',noUpdatePermission:"Sie haben keine Berechtigung, Teile zu aktualisieren",noEditPermission:"Sie haben keine Berechtigung, Teile zu bearbeiten",noDeletePermission:"Sie haben keine Berechtigung, Teile zu löschen",totalCost:"Gesamtkosten:",empty:"Keine Teile in der Stückliste. Fügen Sie Hardware, Elektronik oder andere Komponenten hinzu, um zu verfolgen, was beschafft werden muss."},timeline:{title:"Aktivitätsverlauf",empty:"Noch keine Aktivität."},template:{saveAsTemplate:"Als Vorlage speichern",noCreatePermission:"Sie haben keine Berechtigung, Vorlagen zu erstellen"},queue:{title:"Warteschlange",viewAll:"Alle anzeigen",printing:"{{count}} druckend",queued:"{{count}} in Warteschlange"},prints:{title:"Drucke ({{count}})"},toast:{projectUpdated:"Projekt aktualisiert",partAdded:"Teil hinzugefügt",partRemoved:"Teil entfernt",exportFailed:"Export fehlgeschlagen",projectExported:"Projekt exportiert",templateCreated:"Vorlage erstellt"}},system:{title:"Systeminformationen",version:"Version",uptime:"Laufzeit",cpuUsage:"CPU-Auslastung",memoryUsage:"Speicherauslastung",diskUsage:"Festplattenauslastung",networkInfo:"Netzwerkinformationen",logs:"Protokolle",debugMode:"Debug-Modus",enableDebug:"Debug-Protokollierung aktivieren",disableDebug:"Debug-Protokollierung deaktivieren",downloadLogs:"Protokolle herunterladen",clearLogs:"Protokolle löschen",dockerInfo:"Docker-Info",containerName:"Container-Name",imageName:"Image-Name",platform:"Plattform",architecture:"Architektur"},library:{title:"Filament-Bibliothek",addFilament:"Filament hinzufügen",editFilament:"Filament bearbeiten",deleteFilament:"Filament löschen",vendor:"Hersteller",material:"Material",color:"Farbe",kFactor:"K-Faktor",temperature:"Temperatur",noFilaments:"Keine Filamente in der Bibliothek",deleteConfirm:"Möchten Sie dieses Filament wirklich löschen?",importFromPrinter:"Vom Drucker importieren",exportToFile:"In Datei exportieren"},spoolman:{title:"Spoolman-Integration",enabled:"Spoolman aktiviert",url:"Spoolman URL",connected:"Verbunden",disconnected:"Nicht verbunden",testConnection:"Verbindung testen",sync:"Synchronisieren",syncing:"Synchronisiert...",lastSync:"Letzte Synchronisierung",linkToSpoolman:"Mit Spoolman verknüpfen",openInSpoolman:"In Spoolman öffnen",unlinkSpool:"Spule trennen",unlinkConfirmTitle:"Spule entkoppeln?",unlinkConfirmMessage:"Dadurch wird die Spule von Spoolman getrennt. Die Spulendaten in Spoolman bleiben unverändert.",selectSpool:"Spule auswählen",noUnlinkedSpools:"Keine nicht verknüpften Spulen verfügbar",linkSuccess:"Spule erfolgreich mit Spoolman verknüpft",linkFailed:"Verknüpfung mit Spoolman fehlgeschlagen",unlinkSuccess:"Spule erfolgreich von Spoolman getrennt",unlinkFailed:"Trennen der Spule von Spoolman fehlgeschlagen",spoolId:"Spulen-ID",fillSourceLabel:"(Spoolman)",weight:"Gewicht",remaining:"Verbleibend",disableWeightSync:"AMS-Gewichtsschätzung deaktivieren",disableWeightSyncDesc:"Verbleibende Kapazität nicht aus AMS-Schätzungen aktualisieren. Verwenden Sie dies, wenn Sie die Verbrauchserfassung von Spoolman gegenüber den prozentualen AMS-Schätzungen bevorzugen. Neue Spulen verwenden weiterhin die AMS-Schätzung als Anfangsgewicht.",reportPartialUsage:"Teilverbrauch bei fehlgeschlagenen Drucken melden",reportPartialUsageDesc:"Wenn ein Druck fehlschlägt oder abgebrochen wird, den geschätzten Filamentverbrauch bis zu diesem Zeitpunkt basierend auf dem Schichtfortschritt melden."},inventory:{title:"Spulen-Inventar",addSpool:"Spule hinzufügen",editSpool:"Spule bearbeiten",material:"Material",selectMaterial:"Material auswählen...",subtype:"Untertyp",brand:"Marke",searchBrand:"Marke suchen...",useCustomBrand:'"{{brand}}" verwenden',useCustomMaterial:"Benutzerdefiniertes Material verwenden: {{material}}",colorName:"Farbname",colorNamePlaceholder:"Jade White, Fire Red...",color:"Farbe",hexColor:"Hex-Farbe",pickColor:"Benutzerdefinierte Farbe wählen",labelWeight:"Nenngewicht",coreWeight:"Leergewicht der Spule",searchSpoolWeight:"Spulengewicht suchen...",weightUsed:"Verbraucht",currentWeight:"Restgewicht",measuredWeight:"Gemessenes Gewicht",spoolName:"Spule",costPerKg:"Kosten pro kg",measuredWeightError:"Das gemessene Gewicht muss zwischen {{min}}g und {{max}}g liegen.",slicerFilament:"Slicer-Filament",slicerFilamentName:"Slicer-Preset-Name",slicerPreset:"Slicer-Preset",searchPresets:"Filament-Presets suchen...",selectedPreset:"Ausgewählt",noPresetsFound:"Keine Presets gefunden",tempOverrides:"Temperatur-Überschreibungen",note:"Notiz",notePlaceholder:"Zusätzliche Notizen zu dieser Spule...",archive:"Archivieren",restore:"Wiederherstellen",noSpools:"Noch keine Spulen. Fügen Sie Ihre erste Spule hinzu.",noManualSpools:"Keine manuell hinzugefügten Spulen verfügbar. Fügen Sie zuerst eine Spule zum Inventar hinzu.",kProfiles:"K-Profile",addKProfile:"K-Profil hinzufügen",assignSpool:"Spule zuweisen",unassignSpool:"Zuweisung aufheben",assignSuccess:"Spule zugewiesen und AMS-Slot konfiguriert",assignFailed:"Spulenzuweisung fehlgeschlagen",selectSpool:"Wählen Sie eine Spule für diesen Slot",assigned:"Zugewiesen",assigning:"Wird zugewiesen...",searchSpools:"Spulen suchen...",showAllSpools:"Alle Spulen anzeigen",allMaterials:"Alle Materialien",filterByBrand:"Nach Marke filtern...",showArchived:"Archivierte anzeigen",quickAdd:"Schnellerfassung (Lager)",quantity:"Menge",stock:"Lager",configured:"Konfiguriert",spoolsCreated:"{{count}} Spulen erstellt",spoolCreated:"Spule erstellt",spoolUpdated:"Spule aktualisiert",spoolDeleted:"Spule gelöscht",spoolArchived:"Spule archiviert",spoolRestored:"Spule wiederhergestellt",deleteConfirm:"Möchten Sie diese Spule wirklich löschen? Dies kann nicht rückgängig gemacht werden.",archiveConfirm:"Möchten Sie diese Spule wirklich archivieren?",advancedSettings:"Erweiterte Einstellungen",filamentInfoTab:"Filament-Info",paProfileTab:"PA-Profil",filamentInfo:"Filament",additional:"Zusätzlich",loadingPresets:"Cloud-Presets werden geladen...",cloudConnected:"Cloud verbunden",cloudNotConnected:"Cloud nicht verbunden (Standardwerte)",recentColors:"Zuletzt",searchColors:"Farben suchen...",searchResults:"Suchergebnisse",allColors:"Alle Farben",commonColors:"Häufige Farben",showLess:"Weniger",showAll:"Alle",noColorsFound:"Keine Farben gefunden",noResults:"Keine Ergebnisse",selectMaterialFirst:"Bitte zuerst ein Material im Filament-Info Tab auswählen.",noPrintersConfigured:"Keine Drucker konfiguriert. Fügen Sie Drucker hinzu.",matchingFilter:"Filter",anyBrand:"Jede Marke",anyVariant:"Jede Variante",autoSelect:"Auto-Auswahl",matches:"Treffer",match:"Treffer",noMatches:"Keine Treffer",connected:"Verbunden",offline:"Offline",printerOffline:"Drucker ist offline. Verbinden Sie ihn, um Kalibrierungsprofile anzuzeigen.",noKProfilesMatch:"Keine K-Profile stimmen mit dem gewählten Filament überein.",leftNozzle:"Linke Düse",rightNozzle:"Rechte Düse",profilesSelected:"Kalibrierungsprofil(e) ausgewählt",totalInventory:"Gesamtbestand",totalConsumed:"Gesamtverbrauch",byMaterial:"Nach Material",inPrinter:"Im Drucker",lowStock:"Niedriger Bestand",sinceTracking:"Seit Beginn der Erfassung",loadedInAms:"Im AMS/Ext geladen",remaining:"Verbleibend",weightCheck:"Gewichtskontrolle",lastWeighed:"Zuletzt gewogen",neverWeighed:"Nie gewogen",search:"Spulen suchen...",showing:"Zeige",to:"bis",of:"von",show:"Zeige",spools:"Spulen",spool:"Spule",page:"Seite",noSpoolsMatch:"Keine Ergebnisse",noSpoolsMatchDesc:"Versuchen Sie, Ihre Suche oder Filter anzupassen.",active:"Aktiv",archived:"Archiviert",all:"Alle",used:"Verwendet",new:"Neu",clearFilters:"Filter löschen",table:"Tabelle",cards:"Karten",net:"Netto",groupSimilar:"Gruppieren",groupedSpools:"{{count}} identische Spulen",groupedRows:"Zeilen",columns:"Spalten",configureColumns:"Spalten konfigurieren",configureColumnsDesc:"Ziehen zum Neuordnen oder Pfeile verwenden. Sichtbarkeit mit dem Augensymbol umschalten.",visible:"sichtbar",reset:"Zurücksetzen",cancel:"Abbrechen",applyChanges:"Änderungen anwenden",moveUp:"Nach oben",moveDown:"Nach unten",hideColumn:"Spalte ausblenden",showColumn:"Spalte einblenden",linkToSpool:"Mit Spule verknüpfen",tagLinked:"Tag mit Spule verknüpft",tagLinkFailed:"Tag-Verknüpfung fehlgeschlagen",tagAlreadyLinked:"Tag bereits mit anderer Spule verknüpft",unknownTag:"Unbekannter RFID-Tag erkannt",usageHistory:"Verbrauchshistorie",noUsageHistory:"Noch kein Verbrauch erfasst",printName:"Druckname",weightConsumed:"Verbrauchtes Gewicht",clearHistory:"Löschen",historyCleared:"Verbrauchshistorie gelöscht",fillSourceLabel:"(Inv)",lowStockThresholdError:"Der Schwellenwert muss zwischen 0.1 und 99.9 liegen",assignMismatchTitle:"Material stimmt nicht überein",assignMismatchMessage:'Das ausgewählte Spulenmaterial "{{spoolMaterial}}" stimmt nicht mit dem Tray-Material "{{trayMaterial}}" für {{location}} überein. Trotzdem zuweisen?',assignMismatchConfirm:"Trotzdem zuweisen",assignPartialMismatchMessage:'Das Spulenmaterial "{{spoolMaterial}}" ist ähnlich, stimmt aber nicht genau mit "{{trayMaterial}}" in {{location}} überein. Möchten Sie fortfahren?',assignProfileMismatchMessage:'Das Spulenprofil "{{spoolProfile}}" stimmt nicht mit dem Fachprofil "{{trayProfile}}" in {{location}} überein. Möchten Sie fortfahren?'},timelapse:{title:"Zeitraffer",create:"Zeitraffer erstellen",download:"Herunterladen",delete:"Löschen",preview:"Vorschau",frameRate:"Bildrate",quality:"Qualität",processing:"Wird verarbeitet...",noTimelapses:"Keine Zeitraffer verfügbar"},ams:{title:"AMS",slot:"Slot",empty:"Leer",emptySlot:"Leerer Slot",unknown:"Unbekannt",humidity:"Luftfeuchtigkeit",temperature:"Temperatur",filamentType:"Filamenttyp",filamentColor:"Farbe",remaining:"Verbleibend",history:"AMS-Verlauf",noHistory:"Kein Verlauf verfügbar",configureSlot:"Slot konfigurieren",externalSpool:"Externe Spule",profile:"Profil",kFactor:"K-Faktor",fill:"Füllstand",configure:"Konfigurieren",used:"verwendet",remainingUnit:"verbleibend"},printModal:{title:"Druck starten",selectPrinter:"Drucker auswählen",selectPlate:"Platte auswählen",filamentMapping:"Filamentzuordnung",totalCost:"Gesamtkosten:",slotRemainingShort:" - {{grams}}g übrig",printSettings:"Druckeinstellungen",bedLeveling:"Bett-Nivellierung",flowCalibration:"Fluss-Kalibrierung",vibrationCalibration:"Vibrations-Kalibrierung",layerInspection:"Erste-Schicht-Prüfung",timelapse:"Zeitraffer",startPrint:"Druck starten",addToQueue:"Zur Warteschlange hinzufügen",cancel:"Abbrechen",noPrintersAvailable:"Keine Drucker verfügbar",printerBusy:"Drucker ist beschäftigt",printerOffline:"Drucker ist offline",sameTypeDifferentColor:"Gleicher Typ, andere Farbe",filamentTypeNotLoaded:"Filamenttyp nicht geladen",openCalendar:"Kalender öffnen",leftNozzle:"L",rightNozzle:"R",leftNozzleTooltip:"Linke Düse",rightNozzleTooltip:"Rechte Düse",filamentOverride:"Filament-Überschreibung",filamentOverrideHint:"Filamente für modellbasierte Zuweisung optional überschreiben. Der Planer wird gegen die ausgewählten Filamente statt der ursprünglichen 3MF-Werte abgleichen.",originalFilament:"Original",overrideWith:"Ersetzen mit",resetToOriginal:"Auf Original zurücksetzen",insufficientFilamentTitle:"Nicht genug Filament",insufficientFilamentMessage:"Einige zugewiesene Spulen haben weniger Filament als dieser Druck benötigt:",insufficientFilamentLine:"{{printer}} - {{slot}}: benötigt {{required}}g, verbleibend {{remaining}}g",printAnyway:"Trotzdem drucken",forceColorMatch:"Farbe erzwingen",staggerPrinterStarts:"Stagger printer starts",staggerGroupSize:"Group size",staggerInterval:"Interval (min)",staggerPreview:"{{printers}} printers → {{groups}} groups of {{size}}, starting every {{interval}} min",staggerLastGroup:"last group: {{count}}",staggerTotal:"total: {{minutes}} min",staggerToPrinters:"Gestaffelt an {{count}} Drucker senden",gcodeInjection:"Auto-Print G-code einfügen"},backup:{title:"Sichern & Wiederherstellen",createBackup:"Sicherung erstellen",restoreBackup:"Sicherung wiederherstellen",restoreDescription:"Alle Daten aus einer Sicherungsdatei ersetzen",downloadBackup:"Sicherung herunterladen",uploadBackup:"Sicherung hochladen",lastBackup:"Letzte Sicherung",autoBackup:"Automatische Sicherung",backupNow:"Jetzt sichern",restoreWarning:"Warnung: Das Wiederherstellen einer Sicherung überschreibt alle aktuellen Daten.",includeArchives:"Archive einschließen",includeSettings:"Einstellungen einschließen",includeProfiles:"Profile einschließen",backupSuccess:"Sicherung erfolgreich erstellt",restoreSuccess:"Sicherung erfolgreich wiederhergestellt",backupFailed:"Sicherung fehlgeschlagen",restoreFailed:"Wiederherstellung fehlgeschlagen",restoreNote:"Virtueller Drucker wird während der Wiederherstellung gestoppt",githubBackup:"GitHub Backup",enabled:"Aktiviert",cloudLoginRequired:"Bambu Cloud Login erforderlich. Melden Sie sich unter Profile → Cloud-Profile an, um GitHub-Backup zu aktivieren.",cloudLoginRequiredShort:"Cloud-Login erforderlich",githubDescription:"Synchronisieren Sie Ihre Profile automatisch mit einem privaten GitHub-Repository für Backup und Versionsverlauf.",repositoryUrl:"Repository-URL",personalAccessToken:"Persönlicher Zugriffstoken",tokenSaved:"(gespeichert)",enterNewToken:"Neuen Token eingeben zum Aktualisieren",tokenHint:"Feingranularer Token mit Lese-/Schreibberechtigung für Inhalte",branch:"Branch",manualOnly:"Nur manuell",hourly:"Stündlich",daily:"Täglich",weekly:"Wöchentlich",includeInBackup:"In Sicherung einschließen",kProfiles:"K-Profile",kProfilesDescription:"Druckvorschub-Kalibrierung von verbundenen Druckern",noPrintersConnected:"Keine Drucker verbunden",printersConnected:"{{connected}}/{{total}} verbunden",cloudProfiles:"Cloud-Profile",cloudProfilesDescription:"Filament-, Drucker- und Prozessprofile aus der Bambu Cloud",appSettings:"App-Einstellungen",appSettingsDescription:"Bambuddy-Konfiguration (komplette Datenbank)",spoolInventory:"Spulenbestand",spoolInventoryDescription:"Filamentspulen, Nutzungsverlauf und Kostenverfolgung",printArchives:"Druckarchive",printArchivesDescription:"Druckverlauf-Metadaten (keine GCode/3MF-Dateien)",lastBackupAt:"Letzte Sicherung:",noBackupsYet:"Noch keine Sicherungen",next:"Nächste:",startingBackup:"Sicherung wird gestartet...",test:"Test",enableBackup:"Sicherung aktivieren",testConnection:"Verbindung testen",enterRepoUrl:"Repository-URL eingeben",enterRepoAndToken:"Repository-URL und Zugriffstoken eingeben",repoRequired:"Repository-URL ist erforderlich",tokenRequired:"Zugriffstoken ist erforderlich",githubBackupEnabled:"GitHub-Backup aktiviert",tokenUpdated:"Token aktualisiert",settingsSaved:"Einstellungen gespeichert",failedToSave:"Speichern fehlgeschlagen: {{message}}",backupCompleteFiles:"Sicherung abgeschlossen - {{count}} Dateien aktualisiert",backupSkippedNoChanges:"Sicherung übersprungen - keine Änderungen",backupFailed2:"Sicherung fehlgeschlagen: {{message}}",clearedLogs:"{{count}} Protokolle gelöscht",failedToClearLogs:"Protokolle löschen fehlgeschlagen: {{message}}",history:"Verlauf",clear:"Löschen",date:"Datum",status:"Status",commit:"Commit",localBackup:"Lokale Sicherung",localBackupDescription:"Erstellen Sie eine vollständige Sicherung Ihrer Bambuddy-Daten einschließlich Datenbank, Archive, Uploads und aller Dateien.",downloadBackupLabel:"Sicherung herunterladen",completeBackupZip:"Vollständige Sicherung: Datenbank + alle Dateien (ZIP)",download:"Herunterladen",preparingBackup:"Sicherung wird vorbereitet...",creatingArchive:"Sicherungsarchiv wird erstellt... Dies kann bei großen Archiven eine Weile dauern.",downloadingFile:"Sicherungsdatei wird heruntergeladen...",backupDownloaded:"Sicherung erfolgreich heruntergeladen",failedToCreateBackup:"Sicherung erstellen fehlgeschlagen: {{message}}",restore:"Wiederherstellen",restoreReplacesAll:"Wiederherstellung ersetzt alle Daten.",restoreReplacesAllDetail:"Ihre aktuelle Datenbank und Dateien werden vollständig ersetzt. Nach der Wiederherstellung ist ein Neustart erforderlich.",restoreConfirmTitle:"Sicherung wiederherstellen",restoreConfirmMessage:'Sind Sie sicher, dass Sie von "{{filename}}" wiederherstellen möchten? Dies ersetzt Ihre aktuelle Datenbank und alle Dateien vollständig. Die Anwendung muss nach der Wiederherstellung neu gestartet werden.',restoreConfirmButton:"Sicherung wiederherstellen",uploadingFile:"Sicherungsdatei wird hochgeladen...",backupRestoredRestart:"Sicherung wiederhergestellt. Bitte starten Sie Bambuddy neu.",failedToRestore:"Sicherung wiederherstellen fehlgeschlagen. Bitte überprüfen Sie das Dateiformat.",reloadNow:"Jetzt neu laden",creatingBackup:"Sicherung erstellen",restoringBackup:"Sicherung wiederherstellen",preparing:"Vorbereiten...",processing:"Verarbeiten...",doNotClosePage:"Bitte schließen Sie diese Seite nicht und navigieren Sie nicht weg. Dieser Vorgang kann bei großen Sicherungen mehrere Minuten dauern.",restoring:"Wiederherstellen...",restoreComplete:"Wiederherstellung abgeschlossen",restoreFailed2:"Wiederherstellung fehlgeschlagen",importSettings:"Einstellungen aus einer Sicherungsdatei importieren",pleaseWaitRestoring:"Bitte warten Sie, während Ihre Daten wiederhergestellt werden",selectBackupFile:"Klicken Sie, um eine Sicherungsdatei auszuwählen (.json oder .zip)",duplicateHandling:"So funktioniert die Duplikatbehandlung:",matchPrinters:"Drucker",matchPrintersBy:"abgeglichen nach Seriennummer",matchSmartPlugs:"Smart Plugs",matchSmartPlugsBy:"abgeglichen nach IP-Adresse",matchNotificationProviders:"Benachrichtigungsanbieter",matchNotificationProvidersBy:"abgeglichen nach Name",matchFilaments:"Filamente",matchFilamentsBy:"abgeglichen nach Name + Typ + Marke",matchArchives:"Archive",matchArchivesBy:"abgeglichen nach Inhaltshash (immer übersprungen)",matchPendingUploads:"Ausstehende Uploads",matchPendingUploadsBy:"abgeglichen nach Dateiname",matchSettingsTemplates:"Einstellungen & Vorlagen",matchSettingsTemplatesBy:"immer überschrieben",replaceExisting:"Vorhandene Daten ersetzen",keepExisting:"Vorhandene Daten behalten",overwriteDescription:"Bereits vorhandene Elemente mit Sicherungsdaten überschreiben",keepDescription:"Nur Elemente wiederherstellen, die noch nicht vorhanden sind",overwriteCaution:"Achtung:",overwriteWarning:"Das Überschreiben ersetzt Ihre aktuellen Konfigurationen durch Daten aus der Sicherung. Drucker-Zugangscodes werden aus Sicherheitsgründen nie überschrieben.",cancel:"Abbrechen",processingBackup:"Sicherungsdatei wird verarbeitet...",itemsRestored:"Wiederhergestellt",itemsSkipped:"Übersprungen",restored:"Wiederhergestellt",skippedAlreadyExist:"Übersprungen (bereits vorhanden)",filesCategory:"Dateien (3MF, Thumbnails, etc.)",andMore:"...und {{count}} weitere",newApiKeysGenerated:"Neue API-Schlüssel generiert",keysShownOnce:"Diese Schlüssel werden nur einmal angezeigt. Kopieren Sie sie jetzt!",copy:"Kopieren",noDataFound:"In der Sicherungsdatei wurden keine Daten zur Wiederherstellung gefunden.",close:"Schließen",scheduledBackup:"Scheduled Backups",scheduledBackupDescription:"Automatically create backup snapshots on a schedule. Output directory can be mounted to a NAS or external storage.",frequency:"Frequency",backupTime:"Time",retention:"Retention",retentionDescription:"Number of backups to keep",outputPath:"Output Path",outputPathPlaceholder:"Default: {{path}}",outputPathDescription:"Leave empty for default location",runNow:"Run Now",backupFiles:"Backup Files",noScheduledBackups:"No backups yet",deleteBackup:"Delete",deleteBackupConfirm:"Delete this backup file?",backupRunning:"Backup in progress...",scheduledBackupComplete:"Backup completed successfully",scheduledBackupFailed:"Backup failed",nextBackup:"Next backup",backupSize:"Size",utc:"UTC",defaultPathLabel:"Default:",categories:{settings:"Einstellungen",notification_providers:"Benachrichtigungsanbieter",notification_templates:"Benachrichtigungsvorlagen",smart_plugs:"Smart Plugs",printers:"Drucker",filaments:"Filamente",maintenance_types:"Wartungstypen",archives:"Archive",projects:"Projekte",pending_uploads:"Ausstehende Uploads",external_links:"Externe Links",api_keys:"API-Schlüssel"}},tags:{title:"Tags",addTag:"Tag hinzufügen",editTag:"Tag bearbeiten",deleteTag:"Tag löschen",tagName:"Tag-Name",tagColor:"Tag-Farbe",noTags:"Keine Tags",deleteConfirm:"Möchten Sie diesen Tag wirklich löschen?",manageTags:"Tags verwalten"},uploadModal:{title:"3MF-Dateien hochladen",dragDrop:"3MF-Dateien hierher ziehen",or:"oder",browseFiles:"Dateien durchsuchen",extractionInfo:"Das Druckermodell wird automatisch aus den 3MF-Datei-Metadaten extrahiert.",uploaded:"hochgeladen",failed:"fehlgeschlagen",uploading:"Wird hochgeladen...",upload:"Hochladen",uploadFailed:"Hochladen fehlgeschlagen"},editArchive:{title:"Archiv bearbeiten",name:"Name",namePlaceholder:"Druckname",printer:"Drucker",noPrinter:"Kein Drucker",project:"Projekt",noProject:"Kein Projekt",itemsPrinted:"Gedruckte Teile",itemsPrintedHelp:"Anzahl der in diesem Druckauftrag produzierten Teile",notes:"Notizen",notesPlaceholder:"Notizen zu diesem Druck hinzufügen...",externalLink:"Externer Link",externalLinkPlaceholder:"https://printables.com/model/...",externalLinkHelp:"Link zu Printables, Thingiverse oder anderer Quelle",tags:"Tags",tagsPlaceholder:"Tags hinzufügen...",addMoreTags:"Weitere Tags hinzufügen...",matchingTags:'Übereinstimmend mit "{{query}}"',existingTags:"Vorhandene Tags",clickToAdd:"(zum Hinzufügen klicken)",status:"Status",failureReason:"Fehlergrund",selectReason:"Grund auswählen...",photos:"Fotos des Druckergebnisses",photosHelp:"Klicken Sie auf + um Fotos Ihres Druckergebnisses hinzuzufügen",printResult:"Druckergebnis",saving:"Wird gespeichert...",failureReasons:{adhesionFailure:"Haftungsfehler",spaghettiDetached:"Spaghetti / Abgelöst",layerShift:"Schichtversatz",cloggedNozzle:"Verstopfte Düse",filamentRunout:"Filament aufgebraucht",warping:"Verformung",stringing:"Fadenziehen",underExtrusion:"Unterextrusion",powerFailure:"Stromausfall",userCancelled:"Vom Benutzer abgebrochen",other:"Sonstiges"},statuses:{completed:"Abgeschlossen",failed:"Fehlgeschlagen",aborted:"Abgebrochen",printing:"Druckt"}},kProfiles:{title:"K-Profile",noPrintersConfigured:"Keine Drucker konfiguriert",addPrinterInSettings:"Fügen Sie einen Drucker in den Einstellungen hinzu, um K-Profile zu verwalten",noActivePrinters:"Keine aktiven Drucker",enablePrinterConnection:"Aktivieren Sie eine Druckerverbindung, um K-Profile anzuzeigen",loadingProfiles:"Lade K-Profile...",printerOffline:"Drucker offline",printerOfflineDesc:"Der ausgewählte Drucker ist nicht verbunden. Schalten Sie ihn ein, um K-Profile anzuzeigen.",noMatchingProfiles:"Keine passenden Profile",noMatchingProfilesDesc:"Keine Profile entsprechen Ihren Suchkriterien",noKProfiles:"Keine K-Profile",noKProfilesDesc:"Keine Druckvorschub-Profile für {{diameter}}mm Düse gefunden",createFirstProfile:"Erstes Profil erstellen",printer:"Drucker",nozzle:"Düse",refresh:"Aktualisieren",addProfile:"Profil hinzufügen",export:"Exportieren",import:"Importieren",select:"Auswählen",selectAll:"Alle auswählen",delete:"Löschen",searchPlaceholder:"Nach Name oder Filament suchen...",allExtruders:"Alle Extruder",leftOnly:"Nur links",rightOnly:"Nur rechts",allFlow:"Alle Flusstypen",hfOnly:"Nur HF",sOnly:"Nur S",sortName:"Sortieren: Name",sortKValue:"Sortieren: K-Wert",sortFilament:"Sortieren: Filament",leftExtruder:"Linker Extruder",rightExtruder:"Rechter Extruder",modal:{addTitle:"K-Profil hinzufügen",editTitle:"K-Profil bearbeiten",profileName:"Profilname",profileNamePlaceholder:"Mein PLA-Profil",kValue:"K-Wert",kValuePlaceholder:"0,020",kValueHelp:"Typischer Bereich: 0,01 - 0,06 für PLA, 0,02 - 0,10 für PETG",filament:"Filament",selectFilament:"Filament auswählen...",noFilamentsHelp:"Keine Filamente gefunden. Erstellen Sie zuerst ein K-Profil in Bambu Studio.",flowType:"Flusstyp",highFlow:"High Flow",standard:"Standard",nozzleSize:"Düsengröße",extruder:"Extruder",extruders:"Extruder",left:"Links",right:"Rechts",notes:"Notizen (lokal gespeichert)",notesPlaceholder:"Notizen zu diesem Profil hinzufügen...",notesHelp:"Notizen werden in Bambuddy gespeichert, nicht auf dem Drucker",syncing:"Synchronisiert mit Drucker...",savingExtruder:"Speichern auf Extruder {{current}}/{{total}}...",pleaseWait:"Bitte warten"},deleteConfirm:{title:"Profil löschen",cannotUndo:"Dies kann nicht rückgängig gemacht werden",message:'Möchten Sie "{{name}}" wirklich vom Drucker löschen?'},bulkDelete:{title:"Profile löschen",cannotUndo:"Dies kann nicht rückgängig gemacht werden",message:"Möchten Sie wirklich {{count}} ausgewählte Profile vom Drucker löschen?"},toast:{profileSaved:"K-Profil gespeichert",profilesSaved:"K-Profil auf {{count}} Extrudern gespeichert",selectAtLeastOneExtruder:"Bitte wählen Sie mindestens einen Extruder aus",profileDeleted:"K-Profil gelöscht",profilesDeleted:"{{count}} Profile gelöscht",exportedProfiles:"{{count}} Profile exportiert",importedProfiles:"{{count}} von {{total}} Profilen importiert",noProfilesToExport:"Keine Profile zum Exportieren",invalidFileFormat:"Ungültiges Dateiformat",failedToParseImport:"Import-Datei konnte nicht gelesen werden",failedToSaveBatch:"K-Profile konnten nicht gespeichert werden",noteSaved:"Notiz gespeichert",failedToSaveNote:"Notiz konnte nicht gespeichert werden"},permission:{noRead:"Sie haben keine Berechtigung, Profile zu aktualisieren",noCreate:"Sie haben keine Berechtigung, Profile hinzuzufügen",noUpdate:"Sie haben keine Berechtigung, K-Profile zu aktualisieren",noDelete:"Sie haben keine Berechtigung, K-Profile zu löschen",noExport:"Sie haben keine Berechtigung, Profile zu exportieren",noImport:"Sie haben keine Berechtigung, Profile zu importieren"}},virtualPrinter:{title:"Virtueller Drucker",running:"Läuft",stopped:"Gestoppt",description:{default:"Aktiviere einen virtuellen Drucker, der in Bambu Studio und OrcaSlicer erscheint. Dateien, die an diesen Drucker gesendet werden, werden direkt archiviert ohne zu drucken.",proxy:"Aktiviere einen Proxy, der Slicer-Datenverkehr an einen echten Drucker weiterleitet, um Ferndruck über jedes Netzwerk zu ermöglichen."},enable:{title:"Virtuellen Drucker aktivieren",visibleInSlicer:'Sichtbar als "Bambuddy" in der Slicer-Erkennung',proxyingTo:"Proxy zu {{name}}",notActive:"Nicht aktiv"},model:{title:"Druckermodell",description:"Wähle welches Druckermodell emuliert werden soll.",restartWarning:"Das Ändern des Modells startet den virtuellen Drucker neu"},accessCode:{title:"Zugangscode",isSet:"Zugangscode ist gesetzt",notSet:"Kein Zugangscode gesetzt - erforderlich zum Aktivieren",placeholder:"8-Zeichen-Code eingeben",placeholderChange:"Neuen Code eingeben zum Ändern",hint:"Muss genau 8 Zeichen lang sein. Wird von Slicern zur Authentifizierung verwendet.",charCount:"({{count}}/8)"},targetPrinter:{title:"Zieldrucker",configured:"Proxy-Ziel konfiguriert",notConfigured:"Kein Zieldrucker ausgewählt - erforderlich für Proxy-Modus",placeholder:"Drucker auswählen...",hint:"Wähle den Drucker aus, an den der Slicer-Datenverkehr weitergeleitet werden soll. Der Drucker muss im LAN-Modus sein.",noPrinters:"Keine Drucker konfiguriert. Füge zuerst einen Drucker hinzu, um den Proxy-Modus zu verwenden."},remoteInterface:{title:"Netzwerkschnittstelle überschreiben",configured:"Schnittstellenüberschreibung aktiv",optional:"Optional - verwenden wenn die automatisch erkannte IP falsch ist (z.B. mehrere NICs, Docker, VPN)",placeholder:"Automatisch erkennen (Standard)...",hint:"Überschreibt die per SSDP beworbene und im TLS-Zertifikat verwendete IP-Adresse. Nützlich wenn Bambuddy mehrere Netzwerkschnittstellen hat."},mode:{title:"Modus",archive:"Archivieren",archiveDesc:"Dateien sofort archivieren",review:"Überprüfen",reviewDesc:"Vor dem Archivieren überprüfen",queue:"Warteschlange",queueDesc:"Archivieren und zur Warteschlange hinzufügen",proxy:"Proxy",proxyDesc:"An echten Drucker weiterleiten"},autoDispatch:{title:"Automatisch starten",description:"Drucke automatisch starten, wenn sie zur Warteschlange hinzugefügt werden. Wenn deaktiviert, warten Drucke auf manuellen Start."},setupRequired:{title:"Einrichtung erforderlich",description:"Die virtuelle Druckerfunktion erfordert zusätzliche Systemkonfiguration, bevor sie funktioniert. Dies beinhaltet Portweiterleitung, Firewall-Regeln und plattformspezifische Einstellungen.",readGuide:"Lese die Einrichtungsanleitung vor dem Aktivieren"},howItWorks:{title:"So funktioniert es",step1:"Im selben LAN erscheinen virtuelle Drucker automatisch in deinem Slicer (Bambu Studio / OrcaSlicer). Aus anderen Netzwerken füge sie manuell per IP-Adresse und Zugangscode hinzu.",step2:'Im Archiv-, Überprüfungs- und Warteschlangen-Modus verwende die "Senden"-Funktion im Slicer, um 3MF-Dateien an Bambuddy zu senden. Der Slicer zeigt "Druck erfolgreich" — die Datei wird gespeichert, nicht gedruckt.',step3:"Im Proxy-Modus leitet der virtuelle Drucker den gesamten Datenverkehr an einen echten Drucker weiter — Drucke starten sofort wie bei einer direkten Verbindung."},status:{title:"Status-Details",printerName:"Druckername",model:"Modell",serialNumber:"Seriennummer",mode:"Modus",pendingFiles:"Ausstehende Dateien",targetPrinter:"Zieldrucker",ftpPort:"FTP-Port",mqttPort:"MQTT-Port",ftpConnections:"FTP-Verbindungen",mqttConnections:"MQTT-Verbindungen"},toast:{updated:"Virtuelle Druckereinstellungen aktualisiert",failedToUpdate:"Einstellungen konnten nicht aktualisiert werden",accessCodeRequired:"Bitte zuerst einen Zugangscode setzen",targetPrinterRequired:"Bitte zuerst einen Zieldrucker auswählen",bindIpRequired:"Bitte zuerst eine Bind-IP setzen",accessCodeEmpty:"Zugangscode darf nicht leer sein",accessCodeLength:"Zugangscode muss genau 8 Zeichen lang sein",created:"Virtueller Drucker erstellt",failedToCreate:"Virtueller Drucker konnte nicht erstellt werden",deleted:"Virtueller Drucker gelöscht",failedToDelete:"Virtueller Drucker konnte nicht gelöscht werden"},list:{title:"Virtuelle Drucker",add:"Hinzufügen",addFirst:"Virtuellen Drucker hinzufügen",empty:"Keine virtuellen Drucker konfiguriert. Fügen Sie einen hinzu, um zu beginnen."},bindIp:{title:"Bind-Interface",placeholder:"Interface auswählen...",hint:"Netzwerkinterface, an das dieser virtuelle Drucker gebunden wird. Muss pro Drucker eindeutig sein."},proxy:{accessCodeHint:"Im Proxy-Modus den Zugangscode des Zieldruckers im Slicer verwenden. Die Verbindung wird transparent zum echten Drucker weitergeleitet."},addDialog:{title:"Virtuellen Drucker hinzufügen",name:"Name",hint:"Sie können Zugangscode, Zieldrucker und andere Einstellungen nach dem Erstellen konfigurieren.",create:"Erstellen"},deleteConfirm:{title:"Virtuellen Drucker löschen",message:'Möchten Sie "{{name}}" wirklich löschen? Dies stoppt alle Dienste für diesen Drucker.'}},modelViewer:{openInSlicer:"Im Slicer öffnen",tabs:{model:"3D-Modell",gcode:"G-Code Vorschau"},notAvailable:"nicht verfügbar",notSliced:"nicht geslicet",plates:"Platten",allPlates:"Alle Platten",plateNumber:"Platte {{number}}",plateCount:"{{count}} Platte",plateCount_other:"{{count}} Platten",objectCount:"{{count}} Objekt",objectCount_other:"{{count}} Objekte",filamentCount:"{{count}} Filament",filamentCount_other:"{{count}} Filamente",eta:"ETA {{minutes}} Min",noPreview:"Keine Vorschau für diese Datei verfügbar",pagination:{pageOf:"Seite {{current}} von {{total}}",prev:"Zurück",next:"Weiter"},errors:{failedToLoad:"Datei konnte nicht geladen werden",noMeshes:"Keine Meshes in 3MF-Datei gefunden",unsupportedFormat:"Nicht unterstütztes Dateiformat"}},maintenanceDescriptions:{lubricateCarbonRods:"Schmiermittel auf Karbonstäbe für sanfte Bewegung auftragen",lubricateRails:"Schmiermittel auf Linearschienen für sanfte Bewegung auftragen",cleanNozzle:"Hotend und Düse reinigen, um Verstopfungen zu verhindern",checkBelts:"Riemenspannung für präzise Drucke überprüfen",cleanBuildPlate:"Druckplatte für bessere Haftung reinigen",checkExtruder:"Extruderzahnräder auf Verschleiß prüfen",checkCooling:"Sicherstellen, dass Lüfter ordnungsgemäß funktionieren",generalInspection:"Allgemeine Druckerinspektion",cleanCarbonRods:"Karbonstäbe reinigen, um Reibung zu reduzieren",lubricateSteelRods:"Schmiermittel auf Stahlstangen für sanfte Bewegung auftragen",cleanSteelRods:"Stahlstangen reinigen, um Reibung zu reduzieren",cleanLinearRails:"Linearschienen abwischen, um Staub und Schmutz zu entfernen",checkPtfeTube:"PTFE-Schlauch auf Verschleiß oder Beschädigung prüfen",replaceHepaFilter:"HEPA-Filter für Luftqualität ersetzen",replaceCarbonFilter:"Aktivkohlefilter ersetzen",lubricateLeftNozzleRail:"Linke Düsenschiene schmieren (H2-Serie)"},smartPlugs:{offline:"Offline",admin:"Admin",openPlugAdminPage:"Plug-Admin-Seite öffnen",deleteSmartPlug:"Smart Plug löschen",turnOnSmartPlug:"Smart Plug einschalten",turnOffSmartPlug:"Smart Plug ausschalten",turnOn:"Einschalten",turnOff:"Ausschalten",addSmartPlug:{scanningNetwork:"Netzwerk wird durchsucht...",chooseEntity:"Entität auswählen...",connectionFailed:"Verbindung fehlgeschlagen",searchEntities:"Entitäten suchen...",searchPowerSensors:"Leistungssensoren suchen...",searchEnergySensors:"Energiesensoren suchen...",placeholders:{plugName:"Wohnzimmer Steckdose",mqttStateOnValue:"ON, true, 1",mqttSameAsPower:"Gleich wie Leistungs-Topic oder anders"}},linkedTo:"Verbunden mit:",monitorOnly:"Nur Überwachung",alerts:"Alarme",scheduleOn:"Ein {{time}}",scheduleOff:"Aus {{time}}",on:"Ein",off:"Aus",power:"Leistung",kwhToday:"kWh Heute",settings:"Einstellungen",automationSettings:"Automatisierungseinstellungen",showInSwitchbar:"In Schaltleiste anzeigen",quickAccessSidebar:"Schnellzugriff über Seitenleiste",enabled:"Aktiviert",enableAutomation:"Automatisierung für diesen Stecker aktivieren",autoOn:"Auto Ein",autoOnDescription:"Einschalten wenn Druck startet",autoOff:"Auto Aus",autoOffDescription:"Ausschalten wenn Druck abgeschlossen (einmalig)",autoOffPersistent:"Aktiviert lassen",autoOffPersistentDescription:"Zwischen Drucken aktiviert bleiben statt einmalig",turnOffDelayMode:"Ausschaltverzögerungsmodus",time:"Zeit",temp:"Temp",delayMinutes:"Verzögerung (Minuten)",tempThreshold:"Temperaturschwelle (°C)",tempThresholdDescription:"Schaltet aus wenn die Düse unter diese Temperatur abkühlt",edit:"Bearbeiten",deleteConfirm:'Möchten Sie "{{name}}" wirklich löschen? Dies kann nicht rückgängig gemacht werden.',turnOnConfirm:'Möchten Sie "{{name}}" wirklich einschalten?',turnOffConfirm:'Möchten Sie "{{name}}" wirklich ausschalten? Dies unterbricht die Stromversorgung des angeschlossenen Geräts.',failedToTurn:'{{name}}" konnte nicht {{action}} werden',unknown:"Unbekannt",addTitle:"Smart Plug hinzufügen",editTitle:"Smart Plug bearbeiten",stopScanning:"Suche beenden",discoverTasmota:"Tasmota Geräte suchen",foundDevices:"{{count}} Gerät(e) gefunden - zum Auswählen klicken:",noDevicesFound:"Keine Tasmota Geräte in Ihrem Netzwerk gefunden",haNotConfigured:"Home Assistant ist nicht konfiguriert. Einrichtung unter",haSettingsPath:"Einstellungen → Netzwerk → Home Assistant",selectEntity:"Entität auswählen *",ipAddress:"IP-Adresse *",nameLabel:"Name *",username:"Benutzername",password:"Passwort",authHint:"Leer lassen, wenn Ihr Tasmota-Gerät keine Authentifizierung benötigt",linkToPrinter:"Mit Drucker verbinden",noPrinter:"Kein Drucker (nur manuelle Steuerung)",linkingDescription:"Verknüpfung ermöglicht automatisches Ein-/Ausschalten bei Druckstart/-ende",powerAlerts:"Leistungsalarme",alertAbove:"Alarm wenn über (W)",alertBelow:"Alarm wenn unter (W)",alertDescription:"Benachrichtigung wenn der Stromverbrauch diese Schwellenwerte überschreitet. Leer lassen um diese Richtung zu deaktivieren.",dailySchedule:"Tagesplan",turnOnAt:"Einschalten um",turnOffAt:"Ausschalten um",scheduleDescription:"Den Stecker automatisch täglich zu diesen Zeiten ein-/ausschalten. Leer lassen um diese Aktion zu überspringen.",showOnPrinterCard:"Auf Druckerkarte anzeigen",displayOnPrinterCard:"Schaltfläche auf Druckerkarte anzeigen",connectedResult:"Verbunden!",deviceLabel:"Gerät: {{name}} - ",stateLabel:"Status: {{state}}",test:"Test",delete:"Löschen",save:"Speichern",add:"Hinzufügen",cancel:"Abbrechen",failedToStartScan:"Suche konnte nicht gestartet werden",nameRequired:"Name ist erforderlich",entityRequired:"Entität ist für Home Assistant Stecker erforderlich",mqttTopicRequired:"Mindestens ein MQTT-Topic muss für Leistung, Energie oder Statusüberwachung konfiguriert sein",loadingEntities:"Entitäten werden geladen...",loading:"Laden...",failedToLoadEntities:"Entitäten konnten nicht geladen werden: {{error}}",noEntitiesMatching:'Keine Entitäten gefunden die "{{search}}" entsprechen',noEntitiesAvailable:"Keine Entitäten verfügbar",searchingEntities:"Alle Entitäten durchsuchen ({{count}} gefunden)",showingEntities:"Zeige switch, light, input_boolean ({{count}} verfügbar)",energyMonitoringOptional:"Energieüberwachung (Optional)",energyMonitoringHint:"Sensoren suchen und auswählen, die Leistungs-/Energiedaten liefern.",powerSensorW:"Leistungssensor (W)",energyTodayKwh:"Energie Heute (kWh)",totalEnergyKwh:"Gesamtenergie (kWh)",noMatchingSensors:"Keine passenden Sensoren",none:"Keine",mqttNotConfigured:"MQTT-Broker nicht konfiguriert. Broker-Adresse einstellen unter",mqttSettingsPath:"Einstellungen → Netzwerk → MQTT-Veröffentlichung",mqttNotConfiguredSuffix:"(Sie müssen die Veröffentlichung nicht aktivieren, nur die Broker-Details ausfüllen).",mqttMonitorOnlyDescription:"MQTT-Stecker empfangen Leistungs-/Energiedaten über MQTT-Abonnement. Ein-/Ausschalten ist nicht verfügbar - verwenden Sie Ihren MQTT-Broker oder Ihr Home-Automation-System.",powerMonitoring:"Leistungsüberwachung",energyMonitoring:"Energieüberwachung",stateMonitoring:"Statusüberwachung",optional:"optional",topic:"Topic",jsonPath:"JSON-Pfad",multiplier:"Multiplikator",onValue:"EIN-Wert",mqttPowerHint:`JSON-Pfad extrahiert Wert aus JSON-Payload (z.B. "power_l1"). Leer lassen wenn Topic rohe numerische Werte sendet. @@ -32,7 +32,7 @@ ON值:表示"ON"的确切字符串。留空以自动检测(ON、true、1) 乘數:Wh→kWh使用0.001,MWh→kWh使用1000。`,mqttStateHint:`JSON路徑從JSON負載中提取值。原始值請留空。 ON值:表示"ON"的確切字串。留空以自動檢測(ON、true、1)。`,restControl:"控制",restOnUrl:"開啟 URL",restOffUrl:"關閉 URL",restOnBody:"開啟請求內容",restOffBody:"關閉請求內容",restMethod:"HTTP 方法",restHeaders:"自訂標頭(JSON)",restStatusUrl:"狀態 URL",restStatusPath:"狀態 JSON 路徑",restStatusOnValue:"ON 值",restPowerUrl:"功率URL",restPowerPath:"功率 JSON 路徑",restPowerMultiplier:"功率乘數",restEnergyUrl:"能耗URL",restEnergyPath:"能耗 JSON 路徑",restEnergyMultiplier:"能耗乘數",restUrlRequired:"REST 插座至少需要一個 URL(ON 或 OFF)",restHeadersHint:'例如:{"Authorization": "Bearer your-token"}',restBodyHint:'例如:ON、{"state": "on"}',restStatusHint:"用於輪詢目前狀態的 URL",restPathHint:"例如:state 或 data.power.status",restPowerUrlHint:"功率資料的獨立URL(留空則使用狀態URL)",restEnergyUrlHint:"能耗資料的獨立URL(留空則使用狀態URL)",restEnergyHint:"每個值可以使用獨立的URL,或回退到狀態 URL。使用乘數進行單位轉換(例如:0.001 將 Wh 轉換為 kWh)。",testConnection:"測試連線",connectionSuccess:"連線成功",noSwitchesInSwitchbar:"開關欄中沒有開關",enableSwitchbarHint:'在設定 > 智慧插座中啟用"在開關欄顯示"'},notifications:{providerTypes:{callmebot:"CallMeBot/WhatsApp",ntfy:"ntfy",pushover:"Pushover",telegram:"Telegram",email:"電子郵件",discord:"Discord",webhook:"Webhook",homeassistant:"Home Assistant"},providerDescriptions:{email:"SMTP 電子郵件通知",telegram:"透過 Telegram 機器人傳送通知",discord:"透過 Webhook 傳送到 Discord 頻道",ntfy:"免費、可自託管的推送通知",pushover:"簡單、可靠的推送通知",callmebot:"透過 CallMeBot 免費傳送 WhatsApp 通知",webhook:"通用 HTTP POST 到任意 URL",homeassistant:"Home Assistant 儀表板中的持久通知"},lastSuccess:"上次:{{date}}",error:"錯誤",printer:"印表機:",allPrinters:"所有印表機",sendTestNotification:"傳送測試通知",eventSettings:"事件設定",enabled:"已啟用",sendFromProvider:"從此提供者傳送通知",printEvents:"列印事件",printerStatus:"印表機狀態",amsAlarms:"AMS 警報",amsHtAlarms:"AMS-HT 警報",printQueue:"列印佇列",start:"開始",plateCheck:"熱床檢測",complete:"完成",failed:"失敗",stopped:"已停止",progress:"進度",offline:"離線",lowFilament:"耗材不足",maintenance:"維護",amsHumidity:"AMS 濕度",amsTemp:"AMS 溫度",amsHtHumidity:"AMS-HT 濕度",amsHtTemp:"AMS-HT 溫度",bedCooled:"熱床已冷卻",firstLayer:"首層完成",quiet:"免打擾",digest:"摘要 {{time}}",printStarted:"列印已開始",plateNotEmpty:"熱床非空",plateNotEmptyDescription:"列印前偵測到物體",printCompleted:"列印已完成",bedCooledLabel:"熱床已冷卻",bedCooledDescription:"列印後熱床溫度降至閾值以下",firstLayerCompleteLabel:"首層列印完成",firstLayerCompleteDescription:"首層完成時傳送帶照片的通知",missingSpoolAssignmentLabel:"缺少料卷分配",missingSpoolAssignmentDescription:"當列印開始且所需料盤沒有分配料卷時傳送通知",printFailed:"列印失敗",printStopped:"列印已停止",progressMilestones:"進度里程碑",progressMilestonesDescription:"在 25%、50%、75% 時通知",printerOffline:"印表機離線",printerError:"印表機錯誤",lowFilamentLabel:"耗材不足",maintenanceDue:"需要維護",maintenanceDueDescription:"需要維護時通知",amsHumidityHigh:"AMS 濕度過高",amsHumidityHighDescription:"普通 AMS 濕度超過閾值",amsTemperatureHigh:"AMS 溫度過高",amsTemperatureHighDescription:"普通 AMS 溫度超過閾值",amsHtHumidityHigh:"AMS-HT 濕度過高",amsHtHumidityHighDescription:"AMS-HT 濕度超過閾值",amsHtTemperatureHigh:"AMS-HT 溫度過高",amsHtTemperatureHighDescription:"AMS-HT 溫度超過閾值",jobAdded:"任務已新增",jobAddedDescription:"任務已新增到佇列",jobAssigned:"任務已分配",jobAssignedDescription:"基於模型的任務已分配給印表機",jobStarted:"任務已開始",jobStartedDescription:"佇列任務已開始列印",jobWaiting:"任務等待中",jobWaitingDescription:"任務正在等待耗材或印表機",jobSkipped:"任務已跳過",jobSkippedDescription:"任務已跳過(上一個失敗)",jobFailed:"任務失敗",jobFailedDescription:"任務啟動失敗",queueComplete:"佇列已完成",queueCompleteDescription:"所有佇列任務已完成",quietHours:"免打擾時段",noNotificationsDuring:"在此時段內不傳送通知",editProviderToChangeQuietHours:"編輯提供者以更改免打擾時段",dailyDigest:"每日摘要",batchNotifications:"將通知彙總為每日摘要",sendAt:"傳送於 {{time}}",editProviderToChangeDigestTime:"編輯提供者以更改摘要時間",edit:"編輯",deleteProvider:"刪除通知提供者",deleteConfirm:'確定要刪除"{{name}}"嗎?此操作無法復原。',delete:"刪除",addTitle:"新增通知提供者",editTitle:"編輯通知提供者",nameLabel:"名稱 *",namePlaceholder:"我的通知",providerTypeLabel:"提供者類型 *",configuration:"設定",testConfiguration:"測試設定",printerFilter:"印表機篩選",onlyFromPrinter:"僅傳送來自此印表機的事件通知",quietHoursDnd:"免打擾時段",quietStart:"開始",quietEnd:"結束",dailyDigestLabel:"每日摘要",sendDigestAt:"傳送摘要於",digestCollected:"事件將被收集並在此時間作為單條摘要傳送",notificationEvents:"通知事件",progressPercent:"(25%、50%、75%)",bedCooledAfterPrint:"(列印完成後)",cancel:"取消",save:"儲存",add:"新增",nameRequired:"名稱為必填項",fieldRequired:"{{field}}為必填項",phoneNumber:"電話號碼",apiKey:"API 金鑰",serverUrl:"伺服器 URL",topic:"主題",authToken:"認證權杖",userKey:"使用者金鑰",appToken:"應用程式權杖",priority:"優先順序",botToken:"機器人權杖",chatId:"聊天 ID",smtpServer:"SMTP 伺服器",smtpPort:"SMTP 連接埠",security:"安全",authentication:"認證",username:"使用者名稱",password:"密碼",fromEmail:"寄件人信箱",toEmail:"收件人信箱",webhookUrl:"Webhook URL",payloadFormat:"負載格式",authorization:"授權",titleFieldName:"標題欄位名",messageFieldName:"訊息欄位名",editTemplate:"編輯範本:{{name}}",titleLabel:"標題",bodyLabel:"正文",titlePlaceholder:"通知標題...",bodyPlaceholder:"通知正文...",availableVariables:"可用變數",clickToInsert:"點選插入到正文游標位置",livePreview:"即時預覽",hide:"隱藏",show:"顯示",loadingPreview:"載入預覽中...",enterTemplateContent:"輸入範本內容以檢視預覽",titlePreview:"標題:",bodyPreview:"正文:",resetToDefault:"恢復預設",titleRequired:"標題為必填項",bodyRequired:"正文為必填項",notificationLog:"通知日誌",showFailedOnly:"僅顯示失敗",last24Hours:"最近 24 小時",last7Days:"最近 7 天",last30Days:"最近 30 天",last90Days:"最近 90 天",justNow:"剛剛",noFailedNotifications:"沒有失敗的通知",noNotificationsLogged:"沒有通知紀錄",unknownProvider:"未知提供者",logTitle:"標題",logMessage:"訊息",logError:"錯誤",logProvider:"提供者:{{type}}",logTime:"時間:{{time}}",refresh:"重新整理",clearOld:"清除舊紀錄",statsSummary:"最近 {{days}} 天:",statsNotifications:"條通知",statsSent:"{{count}} 條已傳送",statsFailed:"{{count}} 條失敗",eventTypes:{print_start:"列印已開始",print_complete:"列印完成",print_failed:"列印失敗",print_stopped:"列印已停止",print_progress:"進度",printer_offline:"印表機離線",printer_error:"印表機錯誤",filament_low:"耗材不足",maintenance_due:"需要維護",test:"測試"},userEmail:{title:"通知",emailNotifications:"郵件通知",emailNotificationsDesc:"接收您自己列印任務的郵件通知。郵件將透過進階身份驗證中設定的 SMTP 設定傳送。",sendingTo:"通知將傳送至",noEmailWarning:"您的帳戶沒有郵件地址。請聯絡管理員新增。",printJobNotifications:"列印任務通知",printJobNotificationsDesc:"選擇哪些事件會觸發您提交的列印任務的郵件通知。",printJobStarts:"列印任務開始",printJobStartsDesc:"當您的列印任務開始時收到通知。",printJobFinishes:"列印任務完成",printJobFinishesDesc:"當您的列印任務成功完成時收到通知。",printErrors:"列印錯誤",printErrorsDesc:"當您的列印任務失敗或遇到錯誤時收到通知。",printJobStops:"列印任務停止",printJobStopsDesc:"當您的列印任務被取消或停止時收到通知。",saveSuccess:"通知偏好設定已儲存。",saveError:"儲存通知偏好設定失敗。"}},richTextEditor:{bold:"粗體",italic:"斜體",underline:"底線",bulletList:"無序列表",numberedList:"有序列表",alignLeft:"左對齊",alignCenter:"居中對齊",alignRight:"右對齊",addLink:"新增連結",removeLink:"移除連結"},externalLinks:{noLinksConfigured:"未設定外部連結",deleteLink:"刪除連結",removeCustomIcon:"移除自訂圖示",openInNewTab:"在新標籤頁中開啟",placeholders:{linkName:"我的連結"}},keyboardShortcuts:{title:"鍵盤快捷鍵",navigation:"導航",archivesSection:"歸檔",kProfilesSection:"K 值設定",generalSection:"通用",shortcuts:{goToPrinters:"前往印表機",goToArchives:"前往歸檔",goToQueue:"前往佇列",goToStats:"前往統計",goToProfiles:"前往雲端設定",goToSettings:"前往設定",focusSearch:"聚焦搜尋",openUploadModal:"開啟上傳對話方塊",clearSelection:"清除選擇 / 取消焦點",contextMenu:"卡片右鍵選單",refreshProfiles:"重新整理設定",newProfile:"新增設定",exitSelectionMode:"結束選擇模式",showHelp:"顯示此協助"},footer:"按 Esc 或點選外部關閉"},notificationLog:{title:"通知日誌",events:{printStarted:"列印開始",printComplete:"列印完成",printFailed:"列印失敗",printStopped:"列印停止",progress:"進度",printerOffline:"印表機離線",printerError:"印表機錯誤",lowFilament:"耗材不足",maintenanceDue:"維護到期",test:"測試"},timeAgo:{justNow:"剛剛",minutesAgo:"{{minutes}} 分鐘前",hoursAgo:"{{hours}} 小時前"}},restoreBackup:{title:"恢復備份",restoring:"恢復中...",restoreComplete:"恢復完成",restoreFailed:"恢復失敗",importSettings:"從備份檔案匯入設定",pleaseWait:"請稍候,正在恢復您的資料",clickToSelect:"點選選擇備份檔案(.json 或 .zip)",howDuplicateHandling:"重複處理方式:",categories:{printers:"印表機",smartPlugs:"智慧插座",notificationProviders:"通知提供者",filaments:"耗材",archives:"歸檔",pendingUploads:"待處理上傳",settingsTemplates:"設定和範本"},matchingInfo:{printers:"按序列號匹配",smartPlugs:"按 IP 位址匹配",notificationProviders:"按名稱匹配",filaments:"按名稱 + 類型 + 品牌匹配",archives:"按內容雜湊匹配",pendingUploads:"按檔名匹配",settingsTemplates:"始終覆蓋"},replaceExisting:"替換現有資料",keepExisting:"保留現有資料",replaceDescription:"用備份資料覆蓋已存在的項目",keepDescription:"僅恢復不存在的項目",caution:"注意:",cautionText:"覆蓋將用備份資料替換您目前的設定。出於安全考慮,印表機存取碼永遠不會被覆蓋。",itemsRestored:"已恢復項目",itemsSkipped:"已跳過項目",restored:"已恢復",skipped:"已跳過(已存在)",filesLabel:"檔案(3MF、縮圖等)",newApiKeysGenerated:"已產生新 API 金鑰",newApiKeysWarning:"這些金鑰僅顯示一次。請立即複製!",processingBackup:"處理備份檔案中...",noDataFound:"備份檔案中未找到可恢復的資料。",failedToRestore:"恢復備份失敗。請檢查檔案格式。"},backupExport:{title:"匯出備份",selectData:"選擇要包含的資料",selectAll:"全選",selectNone:"全不選",categoryDescriptions:{settings:"語言、主題、更新偏好",notifications:"ntfy、Pushover、Discord 等",templates:"自訂訊息範本",smartPlugs:"Tasmota 插座設定",externalLinks:"側邊欄外部服務連結",printers:"印表機資訊(不含存取碼)",plateDetection:"空列印板參考影像",filaments:"耗材類型和成本",maintenance:"自訂維護計畫",archives:"所有列印資料 + 檔案(3MF、縮圖、照片)",projects:"專案、材料清單和附件",pendingUploads:"虛擬印表機待審核的上傳",apiKeys:"Webhook API 金鑰(匯入時產生新金鑰)"},requiresPrinters:"需要選擇印表機",zipFileWarning:"將建立 ZIP 檔案。",zipFileDescription:"包括所有 3MF 檔案、縮圖、縮時攝影和照片。這可能需要一些時間並產生較大的檔案。",includeAccessCodes:"包含存取碼",includeAccessCodesDescription:"用於轉移到另一臺機器",includeAccessCodesWarning:"存取碼將以明文形式包含。請妥善保管此備份檔案!",categoriesSelected:"已選擇 {{selectedCount}} 個類別"},pendingUploads:{placeholders:{notes:"新增關於此列印的備註..."},discardUpload:"丟棄上傳",archiveAllUploads:"歸檔所有上傳",discardAllUploads:"丟棄所有上傳",archive:"歸檔",timeAgo:{justNow:"剛剛",minutesAgo:"{{minutes}} 分鐘前",hoursAgo:"{{hours}} 小時前",daysAgo:"{{days}} 天前"}},apiBrowser:{placeholders:{requestBody:"JSON 請求體...",searchEndpoints:"搜尋端點..."}},configureAmsSlot:{title:"設定 AMS 槽位",slotConfigured:"槽位已設定!",configuringSlot:"正在設定槽位:",slotLabel:"{{ams}} 槽位 {{slot}}",searchPresets:"搜尋預設...",colorPlaceholder:"顏色名稱或十六進位(例如:棕色、FF8800)",clearCustomColor:"清除自訂顏色",noCloudPresets:"無雲端預設。登入拓竹雲以同步。",noPresetsAvailable:"無可用預設。登入拓竹雲或匯入本機設定。",noMatchingPresets:"未找到匹配的預設。",custom:"自訂",builtin:"內建",settingsSentToPrinter:"設定已傳送到印表機",filamentProfile:"耗材設定",kProfileLabel:"K 值設定(壓力推進)",filteringFor:"篩選:{{material}}",noKProfile:"無 K 值設定(使用預設值 0.020)",noMatchingKProfiles:"未找到匹配的 K 值設定。將使用預設 K=0.020。",selectFilamentFirst:"請先選擇耗材設定",kFromCalibration:"K={{value}}(來自印表機校準)",customColorLabel:"自訂顏色(可選)",presetColors:"{{name}} 顏色:",showLessColors:"顯示更少顏色",showMoreColors:"顯示更多顏色",clear:"清除",hexLabel:"十六進位:#{{hex}}",resetting:"重設中...",resetSlot:"重設槽位",cancel:"取消",configuring:"設定中...",configureSlot:"設定槽位"},githubBackup:{title:"GitHub 備份",history:"歷史",downloadBackup:"下載備份",restoreBackup:"恢復備份",noBackupsYet:"尚無備份"},emailSettings:{placeholders:{fromName:"BamBuddy"}},tagManagement:{searchTags:"搜尋標籤...",renameTag:"重新命名標籤",deleteTag:"刪除標籤"},notificationTemplates:{placeholders:{title:"通知標題...",body:"通知正文..."}},batchTag:{placeholders:{newTag:"輸入新標籤..."}},photoGallery:{deletePhoto:"刪除照片"},filamentHoverCard:{copySpoolUuid:"複製耗材 UUID"},kProfilesView:{hasNote:"有備註",copyProfile:"複製設定"},layout:{openMenu:"開啟選單",noPermissionSystemInfo:"您沒有檢視系統資訊的權限"},dashboard:{dragToReorder:"拖曳以重新排列",hideWidget:"隱藏小工具"},notificationProviderCard:{deleteNotificationProvider:"刪除通知提供者"},fileManagerModal:{closeFileManager:"關閉檔案管理器",sortFiles:"排序檔案",goToParentFolder:"返回上級資料夾",threeView:"3D 檢視"},embeddedCameraViewer:{refreshStream:"重新整理流",close:"關閉",zoomOut:"縮小",resetZoom:"重設縮放",zoomIn:"放大",dragToResize:"拖曳調整大小"},timelapseViewer:{skipBack5s:"後退 5 秒",skipForward5s:"前進 5 秒"},notificationProviders:{descriptions:{email:"SMTP 郵件通知",telegram:"透過 Telegram 機器人通知",discord:"透過 Webhook 傳送到 Discord 頻道",ntfy:"免費、可自託管的推送通知",pushover:"簡單、可靠的推送通知",callmebot:"透過 CallMeBot 的免費 WhatsApp 通知",webhook:"通用 HTTP POST 到任意 URL"}},logViewer:{searchPlaceholder:"搜尋訊息或日誌名稱...",noLogEntries:"未找到日誌條目"},switchbarPopover:{noSwitchesInSwitchbar:"切換欄中沒有開關"},projectPageModal:{placeholders:{title:"標題",designer:"設計師",license:"許可證",description:"輸入描述...",profileTitle:"設定標題",profileDescription:"設定描述..."}},spoolmanSettings:{},time:{unknown:"-",waiting:"等待中",justNow:"剛剛",now:"現在",minsAgo:"{{count}} 分鐘前",inMins:"{{count}} 分鐘後",hoursAgo:"{{count}} 小時前",inHours:"{{count}} 小時後",daysAgo:"{{count}} 天前",inDays:"{{count}} 天後"},spoolbuddy:{nav:{dashboard:"儀表板",ams:"AMS",inventory:"庫存",writeTag:"寫入",settings:"設定"},status:{nfcReady:"NFC 就緒",nfcOff:"NFC 關閉",offline:"離線",online:"線上",noPrinters:"無印表機",deviceOffline:"裝置離線",waitingConnection:"等待裝置連線...",systemReady:"系統就緒",status:"狀態"},dashboard:{readyToScan:"準備掃描",idleMessage:"將耗材放在磅秤上以識別",nfcHint:"NFC 標籤將自動讀取",device:"裝置",syncWeight:"同步重量",weightSynced:"已同步!",unknownTag:"未知標籤",newTag:"偵測到新標籤",onScale:"在磅秤上",linkSpool:"連結到耗材",linkTagTitle:"將標籤連結到耗材",linkTag:"連結標籤",selectSpool:"選擇要連結此標籤的耗材:",noUntagged:"未找到沒有標籤的耗材",tagDetected:"偵測到標籤",noTag:"無標籤",tagId:"標籤",grossWeight:"毛重",spoolSize:"耗材盤尺寸",close:"關閉",currentSpool:"目前耗材"},modal:{spoolDetected:"偵測到耗材",assignToAms:"分配到 AMS",syncWeight:"同步重量",weightSynced:"已同步!",syncing:"同步中...",newTagDetected:"偵測到新標籤",addToInventory:"新增到庫存",assignToAmsTitle:"分配到 AMS",selectSlot:"選擇槽位",assign:"分配",assigning:"分配中...",assignSuccess:"已分配!",assignError:"分配耗材失敗。請重試。",noPrinterSelected:"選擇印表機...",noAmsDetected:"此印表機未偵測到 AMS",slot:"槽位"},weight:{noReading:"無讀數",stable:"穩定",measuring:"測量中...",tare:"去皮",calibrate:"校準"},spool:{remaining:"剩餘",material:"材料",brand:"品牌",color:"顏色",coreWeight:"軸心重",labelWeight:"標籤重",scaleWeight:"磅秤重",netWeight:"淨重",lastUsed:"上次使用"},ams:{noData:"未偵測到 AMS",connectAms:"連線 AMS 以檢視耗材槽位",noPrinter:"未選擇印表機",selectPrinter:"從頂部欄選擇印表機",printerDisconnected:"印表機已斷開",humidity:"濕度",level:"餘量",active:"活躍",slot:"槽位",empty:"空"},inventory:{search:"搜尋耗材...",empty:"庫存中沒有耗材",noResults:"沒有匹配的耗材",spools:"個耗材",addSpool:"新增耗材"},settings:{tabDevice:"裝置",tabDisplay:"顯示",tabScale:"磅秤",tabUpdates:"更新",nfcReader:"NFC 讀卡器",type:"類型",connection:"連線",notConnected:"不適用",deviceInfo:"裝置資訊",hostname:"主機",uptime:"執行時間",systemConfig:"後端與認證",backendUrl:"Bambuddy 後端 URL",apiToken:"API 權杖",apiTokenPlaceholder:"輸入 API 權杖",saveConfig:"儲存設定",systemQueued:"設定已加入佇列。",nfcDiagnostic:"NFC 診斷",scaleDiagnostic:"磅秤診斷",readTagDiagnostic:"讀取標籤診斷",testNfc:"測試讀卡器",testScale:"測試精度",testReadTag:"讀取標籤",systemFieldsRequired:"後端 URL 為必填項。",brightness:"亮度",saved:"已儲存",noBacklight:"未偵測到 DSI 背光。亮度控制需要 DSI 螢幕。",screenBlank:"螢幕熄滅超時",screenBlankDesc:"不活動後螢幕關閉。觸控喚醒。",displayNote:"亮度作為軟體濾鏡套用。",scaleCalibration:"磅秤校準",currentWeight:"目前重量",tareOffset:"去皮",calFactor:"係數",knownWeight:"已知重量",calStep1:"移除磅秤上所有物品並按設定零點。",calStep2:"將已知重量放在磅秤上。",setZero:"設定零點",calibrateNow:"校準",calibrated:"已校準",tareSet:"去皮命令已傳送。等待裝置回應...",tareFailed:"傳送去皮命令失敗",zeroSet:"零點已設定。將已知重量放在磅秤上。",calibrationDone:"校準完成!",calibrationFailed:"校準失敗",lastCalibrated:"上次校準",stable:"穩定",settling:"穩定中...",firmware:"韌體",scale:"磅秤",noDevice:"未找到 SpoolBuddy 裝置",daemonVersion:"守護程式版本",currentVersion:"目前",versionPending:"等待守護程式...",checking:"檢查中...",checkUpdates:"檢查更新",updateAvailable:"有可用更新",updateInstructions:"透過 SSH 更新:執行 SpoolBuddy 安裝腳本進行升級。",upToDate:"已是最新",includeBeta:"包含測試版本"},writeTag:{tabExisting:"現有耗材",tabNew:"新耗材",tabReplace:"替換標籤",searchPlaceholder:"按材料、顏色、品牌搜尋...",noUntaggedSpools:"沒有無標籤的耗材",noTaggedSpools:"沒有有標籤的耗材",selectSpool:"選擇一個耗材,然後將空白 NTAG 放在讀卡器上",placeTag:"將 NTAG 放在讀卡器上",tagReady:"偵測到標籤 — 準備寫入",writeTag:"寫入標籤",replaceTag:"替換標籤",writing:"寫入標籤中...",waiting:"等待 SpoolBuddy...",writeSuccess:"標籤寫入成功!",writeFailed:"寫入失敗",queueFailed:"佇列寫入命令失敗",tryAgain:"重試",cancel:"取消",replaceWarning:"舊標籤將被取消連結。新標籤將替換它。",deviceOffline:"SpoolBuddy 離線",material:"材料",colorName:"顏色名稱",color:"顏色",brand:"品牌",weight:"重量 (g)",createSpool:"建立耗材",creating:"建立中...",spoolCreated:"耗材已建立!準備寫入。",createFailed:"建立耗材失敗"},quickMenu:{printerPower:"印表機電源",systemControls:"系統",restartDaemon:"重新啟動守護程式",restartBrowser:"重新啟動瀏覽器",reboot:"重新開機",shutdown:"關機",swipeToClose:"向下滑動關閉",confirmTitle:"確認",confirmShutdown:"確定要關閉 SpoolBuddy 嗎?您需要實體存取才能重新開啟。",confirmReboot:"確定要重新開機 SpoolBuddy 嗎?",confirmRestartDaemon:"重新啟動 SpoolBuddy 守護程式?NFC 和磅秤將暫時不可用。",confirmRestartBrowser:"重新啟動kiosk瀏覽器?螢幕將短暫變黑。",confirm:"確認",confirmPlugOn:"開啟 {{name}}?",confirmPlugOff:"關閉 {{name}}?",turnOn:"開啟",turnOff:"關閉"}},bugReport:{title:"報告錯誤",description:"描述",descriptionPlaceholder:"出了什麼問題?請描述問題...",email:"信箱(可選)",emailPlaceholder:"your@email.com",emailPrivacy:"如果提供,您的信箱將包含在GitHub Issue的摺疊部分中,以便維護者後續跟進。",screenshot:"截圖",uploadOrPaste:"上傳、貼上或拖曳圖片",dataCollectedSummary:"報告中包含哪些資料?",dataIncluded:"包含:",dataIncludedList:"應用程式版本、作業系統、架構、Python版本、資料庫統計(僅計數)、印表機型號、噴嘴數量、韌體版本、連線狀態、整合狀態(Spoolman、MQTT、HA)、非敏感設定、網路介面數量、Docker詳情、依賴版本。",dataNeverIncluded:"絕不包含:",dataNeverIncludedList:"印表機名稱、序列號、存取碼、密碼、IP 位址、信箱地址、API金鑰、權杖、Webhook URL、主機名稱或使用者名稱。",submit:"提交",startLogging:"開始偵錯日誌",stepEnableLogging:"偵錯日誌已啟用",stepReproduce:"請現在重現問題",stepStopLogging:"停止並提交報告",stopAndSubmit:"停止並提交",maxDuration:"{{minutes}} 分鐘後自動停止",stoppingLogs:"正在收集日誌並提交...",submitting:"正在提交錯誤報告...",submitSuccess:"錯誤報告提交成功!",submitFailed:"提交錯誤報告失敗",thankYou:"謝謝!",submitted:"您的錯誤報告已提交。",viewIssue:"檢視 Issue",unexpectedError:"發生了意外錯誤"},failureDetection:{title:"AI 故障檢測",description:"透過自託管的 Obico ML API 監控列印,並對偵測到的故障自動採取行動。",mlUrl:"Obico ML API 地址",mlUrlHint:"您自託管的 Obico ml_api 容器的基礎 URL(例如 http://192.168.1.10:3333)。",test:"測試",testSuccess:"ML API 可存取且正常。",testFailed:"無法存取 ML API。",sensitivity:"靈敏度",sensitivityLow:"低(減少誤報)",sensitivityMedium:"中(平衡)",sensitivityHigh:"高(更早檢測,更多誤報)",sensitivityHint:"調整觸發警告和故障的置信度閾值。",action:"偵測到故障時的操作",actionNotify:"僅通知",actionPause:"暫停列印",actionPauseOff:"暫停並切斷電源",pollInterval:"檢查間隔(秒)",pollIntervalHint:"列印過程中每臺印表機的檢查頻率。最小 5 秒,最大 120 秒。",externalUrlMissing:"尚未設定外部 URL。",externalUrlHint:"ML API 透過 URL 擷取攝影機快照。請在一般設定中設定外部 URL,讓 ML API 容器可以連線到 Bambuddy。",perPrinterTitle:"監控的印表機",perPrinterHint:"選擇檢測服務要監視哪些印表機。",monitorAll:"監控所有已連線的印表機",statusTitle:"狀態",serviceRunning:"服務執行中",thresholds:"低 / 高閾值",activePrinters:"活動列印",noActivePrints:"目前沒有正在進行的列印。",historyTitle:"最近檢測",noHistory:"尚無檢測紀錄。"}},Zue={en:{translation:$ue},de:{translation:Vue},fr:{translation:Gue},ja:{translation:Wue},it:{translation:Kue},"pt-BR":{translation:Xue},"zh-CN":{translation:Yue},"zh-TW":{translation:Que}};xo.use(YY).use(Sue).init({resources:Zue,fallbackLng:"en",supportedLngs:["en","de","fr","ja","it","pt-BR","zh-CN","zh-TW"],detection:{order:["localStorage","navigator","htmlTag"],lookupLocalStorage:"bambutrack_language",caches:["localStorage"]},interpolation:{escapeValue:!1},react:{useSuspense:!1}});const iH=[{code:"en",name:"English",nativeName:"English"},{code:"de",name:"German",nativeName:"Deutsch"},{code:"fr",name:"French",nativeName:"Français"},{code:"ja",name:"Japanese",nativeName:"日本語"},{code:"it",name:"Italian",nativeName:"Italiano"},{code:"pt-BR",name:"Portuguese (Brazil)",nativeName:"Português (Brasil)"},{code:"zh-CN",name:"Chinese (Simplified)",nativeName:"简体中文"},{code:"zh-TW",name:"Chinese (Traditional)",nativeName:"繁體中文"}];var sH="popstate";function Jue(t={}){function e(r,i){let{pathname:s,search:o,hash:l}=r.location;return H3("",{pathname:s,search:o,hash:l},i.state&&i.state.usr||null,i.state&&i.state.key||"default")}function n(r,i){return typeof i=="string"?i:Q0(i)}return tme(e,n,null,t)}function Aa(t,e){if(t===!1||t===null||typeof t>"u")throw new Error(e)}function lc(t,e){if(!t){typeof console<"u"&&console.warn(e);try{throw new Error(e)}catch{}}}function eme(){return Math.random().toString(36).substring(2,10)}function oH(t,e){return{usr:t.state,key:t.key,idx:e}}function H3(t,e,n=null,r){return{pathname:typeof t=="string"?t:t.pathname,search:"",hash:"",...typeof e=="string"?by(e):e,state:n,key:e&&e.key||r||eme()}}function Q0({pathname:t="/",search:e="",hash:n=""}){return e&&e!=="?"&&(t+=e.charAt(0)==="?"?e:"?"+e),n&&n!=="#"&&(t+=n.charAt(0)==="#"?n:"#"+n),t}function by(t){let e={};if(t){let n=t.indexOf("#");n>=0&&(e.hash=t.substring(n),t=t.substring(0,n));let r=t.indexOf("?");r>=0&&(e.search=t.substring(r),t=t.substring(0,r)),t&&(e.pathname=t)}return e}function tme(t,e,n,r={}){let{window:i=document.defaultView,v5Compat:s=!1}=r,o=i.history,l="POP",c=null,d=u();d==null&&(d=0,o.replaceState({...o.state,idx:d},""));function u(){return(o.state||{idx:null}).idx}function m(){l="POP";let b=u(),g=b==null?null:b-d;d=b,c&&c({action:l,location:v.location,delta:g})}function p(b,g){l="PUSH";let _=H3(v.location,b,g);d=u()+1;let C=oH(_,d),P=v.createHref(_);try{o.pushState(C,"",P)}catch(N){if(N instanceof DOMException&&N.name==="DataCloneError")throw N;i.location.assign(P)}s&&c&&c({action:l,location:v.location,delta:1})}function f(b,g){l="REPLACE";let _=H3(v.location,b,g);d=u();let C=oH(_,d),P=v.createHref(_);o.replaceState(C,"",P),s&&c&&c({action:l,location:v.location,delta:0})}function x(b){return nme(b)}let v={get action(){return l},get location(){return t(i,o)},listen(b){if(c)throw new Error("A history only accepts one active listener");return i.addEventListener(sH,m),c=b,()=>{i.removeEventListener(sH,m),c=null}},createHref(b){return e(i,b)},createURL:x,encodeLocation(b){let g=x(b);return{pathname:g.pathname,search:g.search,hash:g.hash}},push:p,replace:f,go(b){return o.go(b)}};return v}function nme(t,e=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),Aa(n,"No window.location.(origin|href) available to create URL");let r=typeof t=="string"?t:Q0(t);return r=r.replace(/ $/,"%20"),!e&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function QY(t,e,n="/"){return rme(t,e,n,!1)}function rme(t,e,n,r){let i=typeof e=="string"?by(e):e,s=pm(i.pathname||"/",n);if(s==null)return null;let o=ZY(t);ame(o);let l=null;for(let c=0;l==null&&c{let u={relativePath:d===void 0?o.path||"":d,caseSensitive:o.caseSensitive===!0,childrenIndex:l,route:o};if(u.relativePath.startsWith("/")){if(!u.relativePath.startsWith(r)&&c)return;Aa(u.relativePath.startsWith(r),`Absolute route path "${u.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),u.relativePath=u.relativePath.slice(r.length)}let m=am([r,u.relativePath]),p=n.concat(u);o.children&&o.children.length>0&&(Aa(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${m}".`),ZY(o.children,e,p,m,c)),!(o.path==null&&!o.index)&&e.push({path:m,score:ume(m,o.index),routesMeta:p})};return t.forEach((o,l)=>{if(o.path===""||!o.path?.includes("?"))s(o,l);else for(let c of JY(o.path))s(o,l,!0,c)}),e}function JY(t){let e=t.split("/");if(e.length===0)return[];let[n,...r]=e,i=n.endsWith("?"),s=n.replace(/\?$/,"");if(r.length===0)return i?[s,""]:[s];let o=JY(r.join("/")),l=[];return l.push(...o.map(c=>c===""?s:[s,c].join("/"))),i&&l.push(...o),l.map(c=>t.startsWith("/")&&c===""?"/":c)}function ame(t){t.sort((e,n)=>e.score!==n.score?n.score-e.score:mme(e.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var ime=/^:[\w-]+$/,sme=3,ome=2,lme=1,cme=10,dme=-2,lH=t=>t==="*";function ume(t,e){let n=t.split("/"),r=n.length;return n.some(lH)&&(r+=dme),e&&(r+=ome),n.filter(i=>!lH(i)).reduce((i,s)=>i+(ime.test(s)?sme:s===""?lme:cme),r)}function mme(t,e){return t.length===e.length&&t.slice(0,-1).every((r,i)=>r===e[i])?t[t.length-1]-e[e.length-1]:0}function hme(t,e,n=!1){let{routesMeta:r}=t,i={},s="/",o=[];for(let l=0;l{if(u==="*"){let x=l[p]||"";o=s.slice(0,s.length-x.length).replace(/(.)\/+$/,"$1")}const f=l[p];return m&&!f?d[u]=void 0:d[u]=(f||"").replace(/%2F/g,"/"),d},{}),pathname:s,pathnameBase:o,pattern:t}}function pme(t,e=!1,n=!0){lc(t==="*"||!t.endsWith("*")||t.endsWith("/*"),`Route path "${t}" will be treated as if it were "${t.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${t.replace(/\*$/,"/*")}".`);let r=[],i="^"+t.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(o,l,c)=>(r.push({paramName:l,isOptional:c!=null}),c?"/?([^\\/]+)?":"/([^\\/]+)")).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return t.endsWith("*")?(r.push({paramName:"*"}),i+=t==="*"||t==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?i+="\\/*$":t!==""&&t!=="/"&&(i+="(?:(?=\\/|$))"),[new RegExp(i,e?void 0:"i"),r]}function fme(t){try{return t.split("/").map(e=>decodeURIComponent(e).replace(/\//g,"%2F")).join("/")}catch(e){return lc(!1,`The URL path "${t}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${e}).`),t}}function pm(t,e){if(e==="/")return t;if(!t.toLowerCase().startsWith(e.toLowerCase()))return null;let n=e.endsWith("/")?e.length-1:e.length,r=t.charAt(n);return r&&r!=="/"?null:t.slice(n)||"/"}var gme=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function bme(t,e="/"){let{pathname:n,search:r="",hash:i=""}=typeof t=="string"?by(t):t,s;return n?(n=n.replace(/\/\/+/g,"/"),n.startsWith("/")?s=cH(n.substring(1),"/"):s=cH(n,e)):s=e,{pathname:s,search:vme(r),hash:wme(i)}}function cH(t,e){let n=e.replace(/\/+$/,"").split("/");return t.split("/").forEach(i=>{i===".."?n.length>1&&n.pop():i!=="."&&n.push(i)}),n.length>1?n.join("/"):"/"}function SM(t,e,n,r){return`Cannot include a '${t}' character in a manually specified \`to.${e}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function xme(t){return t.filter((e,n)=>n===0||e.route.path&&e.route.path.length>0)}function dO(t){let e=xme(t);return e.map((n,r)=>r===e.length-1?n.pathname:n.pathnameBase)}function uO(t,e,n,r=!1){let i;typeof t=="string"?i=by(t):(i={...t},Aa(!i.pathname||!i.pathname.includes("?"),SM("?","pathname","search",i)),Aa(!i.pathname||!i.pathname.includes("#"),SM("#","pathname","hash",i)),Aa(!i.search||!i.search.includes("#"),SM("#","search","hash",i)));let s=t===""||i.pathname==="",o=s?"/":i.pathname,l;if(o==null)l=n;else{let m=e.length-1;if(!r&&o.startsWith("..")){let p=o.split("/");for(;p[0]==="..";)p.shift(),m-=1;i.pathname=p.join("/")}l=m>=0?e[m]:"/"}let c=bme(i,l),d=o&&o!=="/"&&o.endsWith("/"),u=(s||o===".")&&n.endsWith("/");return!c.pathname.endsWith("/")&&(d||u)&&(c.pathname+="/"),c}var am=t=>t.join("/").replace(/\/\/+/g,"/"),yme=t=>t.replace(/\/+$/,"").replace(/^\/*/,"/"),vme=t=>!t||t==="?"?"":t.startsWith("?")?t:"?"+t,wme=t=>!t||t==="#"?"":t.startsWith("#")?t:"#"+t,Sme=class{constructor(t,e,n,r=!1){this.status=t,this.statusText=e||"",this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function _me(t){return t!=null&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.internal=="boolean"&&"data"in t}function kme(t){return t.map(e=>e.route.path).filter(Boolean).join("/").replace(/\/\/*/g,"/")||"/"}var eQ=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function tQ(t,e){let n=t;if(typeof n!="string"||!gme.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,i=!1;if(eQ)try{let s=new URL(window.location.href),o=n.startsWith("//")?new URL(s.protocol+n):new URL(n),l=pm(o.pathname,e);o.origin===s.origin&&l!=null?n=l+o.search+o.hash:i=!0}catch{lc(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:i,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var nQ=["POST","PUT","PATCH","DELETE"];new Set(nQ);var Nme=["GET",...nQ];new Set(Nme);var xy=w.createContext(null);xy.displayName="DataRouter";var OP=w.createContext(null);OP.displayName="DataRouterState";var Cme=w.createContext(!1),rQ=w.createContext({isTransitioning:!1});rQ.displayName="ViewTransition";var Pme=w.createContext(new Map);Pme.displayName="Fetchers";var Tme=w.createContext(null);Tme.displayName="Await";var Sl=w.createContext(null);Sl.displayName="Navigation";var Vw=w.createContext(null);Vw.displayName="Location";var xc=w.createContext({outlet:null,matches:[],isDataRoute:!1});xc.displayName="Route";var mO=w.createContext(null);mO.displayName="RouteError";var aQ="REACT_ROUTER_ERROR",Ame="REDIRECT",jme="ROUTE_ERROR_RESPONSE";function Mme(t){if(t.startsWith(`${aQ}:${Ame}:{`))try{let e=JSON.parse(t.slice(28));if(typeof e=="object"&&e&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.location=="string"&&typeof e.reloadDocument=="boolean"&&typeof e.replace=="boolean")return e}catch{}}function Eme(t){if(t.startsWith(`${aQ}:${jme}:{`))try{let e=JSON.parse(t.slice(40));if(typeof e=="object"&&e&&typeof e.status=="number"&&typeof e.statusText=="string")return new Sme(e.status,e.statusText,e.data)}catch{}}function Dme(t,{relative:e}={}){Aa(yy(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:r}=w.useContext(Sl),{hash:i,pathname:s,search:o}=Ww(t,{relative:e}),l=s;return n!=="/"&&(l=s==="/"?n:am([n,s])),r.createHref({pathname:l,search:o,hash:i})}function yy(){return w.useContext(Vw)!=null}function ed(){return Aa(yy(),"useLocation() may be used only in the context of a component."),w.useContext(Vw).location}var iQ="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function sQ(t){w.useContext(Sl).static||w.useLayoutEffect(t)}function Uo(){let{isDataRoute:t}=w.useContext(xc);return t?Wme():Fme()}function Fme(){Aa(yy(),"useNavigate() may be used only in the context of a component.");let t=w.useContext(xy),{basename:e,navigator:n}=w.useContext(Sl),{matches:r}=w.useContext(xc),{pathname:i}=ed(),s=JSON.stringify(dO(r)),o=w.useRef(!1);return sQ(()=>{o.current=!0}),w.useCallback((c,d={})=>{if(lc(o.current,iQ),!o.current)return;if(typeof c=="number"){n.go(c);return}let u=uO(c,JSON.parse(s),i,d.relative==="path");t==null&&e!=="/"&&(u.pathname=u.pathname==="/"?e:am([e,u.pathname])),(d.replace?n.replace:n.push)(u,d.state,d)},[e,n,s,i,t])}var oQ=w.createContext(null);function vy(){return w.useContext(oQ)}function Rme(t){let e=w.useContext(xc).outlet;return w.useMemo(()=>e&&w.createElement(oQ.Provider,{value:t},e),[e,t])}function Gw(){let{matches:t}=w.useContext(xc),e=t[t.length-1];return e?e.params:{}}function Ww(t,{relative:e}={}){let{matches:n}=w.useContext(xc),{pathname:r}=ed(),i=JSON.stringify(dO(n));return w.useMemo(()=>uO(t,JSON.parse(i),r,e==="path"),[t,i,r,e])}function Lme(t,e){return lQ(t,e)}function lQ(t,e,n,r,i){Aa(yy(),"useRoutes() may be used only in the context of a component.");let{navigator:s}=w.useContext(Sl),{matches:o}=w.useContext(xc),l=o[o.length-1],c=l?l.params:{},d=l?l.pathname:"/",u=l?l.pathnameBase:"/",m=l&&l.route;{let _=m&&m.path||"";dQ(d,!m||_.endsWith("*")||_.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${d}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. -Please change the parent to .`)}let p=ed(),f;if(e){let _=typeof e=="string"?by(e):e;Aa(u==="/"||_.pathname?.startsWith(u),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${u}" but pathname "${_.pathname}" was given in the \`location\` prop.`),f=_}else f=p;let x=f.pathname||"/",v=x;if(u!=="/"){let _=u.replace(/^\//,"").split("/");v="/"+x.replace(/^\//,"").split("/").slice(_.length).join("/")}let b=QY(t,{pathname:v});lc(m||b!=null,`No routes matched location "${f.pathname}${f.search}${f.hash}" `),lc(b==null||b[b.length-1].route.element!==void 0||b[b.length-1].route.Component!==void 0||b[b.length-1].route.lazy!==void 0,`Matched leaf route at location "${f.pathname}${f.search}${f.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let g=Bme(b&&b.map(_=>Object.assign({},_,{params:Object.assign({},c,_.params),pathname:am([u,s.encodeLocation?s.encodeLocation(_.pathname.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:_.pathname]),pathnameBase:_.pathnameBase==="/"?u:am([u,s.encodeLocation?s.encodeLocation(_.pathnameBase.replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:_.pathnameBase])})),o,n,r,i);return e&&g?w.createElement(Vw.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...f},navigationType:"POP"}},g):g}function Ome(){let t=Gme(),e=_me(t)?`${t.status} ${t.statusText}`:t instanceof Error?t.message:JSON.stringify(t),n=t instanceof Error?t.stack:null,r="rgba(200,200,200, 0.5)",i={padding:"0.5rem",backgroundColor:r},s={padding:"2px 4px",backgroundColor:r},o=null;return console.error("Error handled by React Router default ErrorBoundary:",t),o=w.createElement(w.Fragment,null,w.createElement("p",null,"💿 Hey developer 👋"),w.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",w.createElement("code",{style:s},"ErrorBoundary")," or"," ",w.createElement("code",{style:s},"errorElement")," prop on your route.")),w.createElement(w.Fragment,null,w.createElement("h2",null,"Unexpected Application Error!"),w.createElement("h3",{style:{fontStyle:"italic"}},e),n?w.createElement("pre",{style:i},n):null,o)}var Ime=w.createElement(Ome,null),cQ=class extends w.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,e){return e.location!==t.location||e.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:e.error,location:e.location,revalidation:t.revalidation||e.revalidation}}componentDidCatch(t,e){this.props.onError?this.props.onError(t,e):console.error("React Router caught the following error during render",t)}render(){let t=this.state.error;if(this.context&&typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){const n=Eme(t.digest);n&&(t=n)}let e=t!==void 0?w.createElement(xc.Provider,{value:this.props.routeContext},w.createElement(mO.Provider,{value:t,children:this.props.component})):this.props.children;return this.context?w.createElement(zme,{error:t},e):e}};cQ.contextType=Cme;var _M=new WeakMap;function zme({children:t,error:e}){let{basename:n}=w.useContext(Sl);if(typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){let r=Mme(e.digest);if(r){let i=_M.get(e);if(i)throw i;let s=tQ(r.location,n);if(eQ&&!_M.get(e))if(s.isExternal||r.reloadDocument)window.location.href=s.absoluteURL||s.to;else{const o=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(s.to,{replace:r.replace}));throw _M.set(e,o),o}return w.createElement("meta",{httpEquiv:"refresh",content:`0;url=${s.absoluteURL||s.to}`})}}return t}function Ume({routeContext:t,match:e,children:n}){let r=w.useContext(xy);return r&&r.static&&r.staticContext&&(e.route.errorElement||e.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=e.route.id),w.createElement(xc.Provider,{value:t},n)}function Bme(t,e=[],n=null,r=null,i=null){if(t==null){if(!n)return null;if(n.errors)t=n.matches;else if(e.length===0&&!n.initialized&&n.matches.length>0)t=n.matches;else return null}let s=t,o=n?.errors;if(o!=null){let u=s.findIndex(m=>m.route.id&&o?.[m.route.id]!==void 0);Aa(u>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),s=s.slice(0,Math.min(s.length,u+1))}let l=!1,c=-1;if(n)for(let u=0;u=0?s=s.slice(0,c+1):s=[s[0]];break}}}let d=n&&r?(u,m)=>{r(u,{location:n.location,params:n.matches?.[0]?.params??{},unstable_pattern:kme(n.matches),errorInfo:m})}:void 0;return s.reduceRight((u,m,p)=>{let f,x=!1,v=null,b=null;n&&(f=o&&m.route.id?o[m.route.id]:void 0,v=m.route.errorElement||Ime,l&&(c<0&&p===0?(dQ("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),x=!0,b=null):c===p&&(x=!0,b=m.route.hydrateFallbackElement||null)));let g=e.concat(s.slice(0,p+1)),_=()=>{let C;return f?C=v:x?C=b:m.route.Component?C=w.createElement(m.route.Component,null):m.route.element?C=m.route.element:C=u,w.createElement(Ume,{match:m,routeContext:{outlet:u,matches:g,isDataRoute:n!=null},children:C})};return n&&(m.route.ErrorBoundary||m.route.errorElement||p===0)?w.createElement(cQ,{location:n.location,revalidation:n.revalidation,component:v,error:f,children:_(),routeContext:{outlet:null,matches:g,isDataRoute:!0},onError:d}):_()},null)}function hO(t){return`${t} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Hme(t){let e=w.useContext(xy);return Aa(e,hO(t)),e}function qme(t){let e=w.useContext(OP);return Aa(e,hO(t)),e}function $me(t){let e=w.useContext(xc);return Aa(e,hO(t)),e}function pO(t){let e=$me(t),n=e.matches[e.matches.length-1];return Aa(n.route.id,`${t} can only be used on routes that contain a unique "id"`),n.route.id}function Vme(){return pO("useRouteId")}function Gme(){let t=w.useContext(mO),e=qme("useRouteError"),n=pO("useRouteError");return t!==void 0?t:e.errors?.[n]}function Wme(){let{router:t}=Hme("useNavigate"),e=pO("useNavigate"),n=w.useRef(!1);return sQ(()=>{n.current=!0}),w.useCallback(async(i,s={})=>{lc(n.current,iQ),n.current&&(typeof i=="number"?await t.navigate(i):await t.navigate(i,{fromRouteId:e,...s}))},[t,e])}var dH={};function dQ(t,e,n){!e&&!dH[t]&&(dH[t]=!0,lc(!1,n))}w.memo(Kme);function Kme({routes:t,future:e,state:n,onError:r}){return lQ(t,void 0,n,r,e)}function Bx({to:t,replace:e,state:n,relative:r}){Aa(yy()," may be used only in the context of a component.");let{static:i}=w.useContext(Sl);lc(!i," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:s}=w.useContext(xc),{pathname:o}=ed(),l=Uo(),c=uO(t,dO(s),o,r==="path"),d=JSON.stringify(c);return w.useEffect(()=>{l(JSON.parse(d),{replace:e,state:n,relative:r})},[l,d,r,e,n]),null}function uQ(t){return Rme(t.context)}function Rr(t){Aa(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function Xme({basename:t="/",children:e=null,location:n,navigationType:r="POP",navigator:i,static:s=!1,unstable_useTransitions:o}){Aa(!yy(),"You cannot render a inside another . You should never have more than one in your app.");let l=t.replace(/^\/*/,"/"),c=w.useMemo(()=>({basename:l,navigator:i,static:s,unstable_useTransitions:o,future:{}}),[l,i,s,o]);typeof n=="string"&&(n=by(n));let{pathname:d="/",search:u="",hash:m="",state:p=null,key:f="default"}=n,x=w.useMemo(()=>{let v=pm(d,l);return v==null?null:{location:{pathname:v,search:u,hash:m,state:p,key:f},navigationType:r}},[l,d,u,m,p,f,r]);return lc(x!=null,` is not able to match the URL "${d}${u}${m}" because it does not start with the basename, so the won't render anything.`),x==null?null:w.createElement(Sl.Provider,{value:c},w.createElement(Vw.Provider,{children:e,value:x}))}function Yme({children:t,location:e}){return Lme(q3(t),e)}function q3(t,e=[]){let n=[];return w.Children.forEach(t,(r,i)=>{if(!w.isValidElement(r))return;let s=[...e,i];if(r.type===w.Fragment){n.push.apply(n,q3(r.props.children,s));return}Aa(r.type===Rr,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),Aa(!r.props.index||!r.props.children,"An index route cannot have child routes.");let o={id:r.props.id||s.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(o.children=q3(r.props.children,s)),n.push(o)}),n}var Rk="get",Lk="application/x-www-form-urlencoded";function IP(t){return typeof HTMLElement<"u"&&t instanceof HTMLElement}function Qme(t){return IP(t)&&t.tagName.toLowerCase()==="button"}function Zme(t){return IP(t)&&t.tagName.toLowerCase()==="form"}function Jme(t){return IP(t)&&t.tagName.toLowerCase()==="input"}function ehe(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function the(t,e){return t.button===0&&(!e||e==="_self")&&!ehe(t)}function $3(t=""){return new URLSearchParams(typeof t=="string"||Array.isArray(t)||t instanceof URLSearchParams?t:Object.keys(t).reduce((e,n)=>{let r=t[n];return e.concat(Array.isArray(r)?r.map(i=>[n,i]):[[n,r]])},[]))}function nhe(t,e){let n=$3(t);return e&&e.forEach((r,i)=>{n.has(i)||e.getAll(i).forEach(s=>{n.append(i,s)})}),n}var G_=null;function rhe(){if(G_===null)try{new FormData(document.createElement("form"),0),G_=!1}catch{G_=!0}return G_}var ahe=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function kM(t){return t!=null&&!ahe.has(t)?(lc(!1,`"${t}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Lk}"`),null):t}function ihe(t,e){let n,r,i,s,o;if(Zme(t)){let l=t.getAttribute("action");r=l?pm(l,e):null,n=t.getAttribute("method")||Rk,i=kM(t.getAttribute("enctype"))||Lk,s=new FormData(t)}else if(Qme(t)||Jme(t)&&(t.type==="submit"||t.type==="image")){let l=t.form;if(l==null)throw new Error('Cannot submit a