@openloaf/openspeech-frontend 0.2.34 → 0.2.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/App-1l8JJIXu.css +1 -0
- package/dist/assets/App-CwCuun8F.js +20 -0
- package/dist/assets/main-D8OyAS3R.js +583 -0
- package/dist/assets/promo-0JSYHRTQ.js +5 -0
- package/dist/index.html +3 -6
- package/dist/promo.html +4 -6
- package/package.json +6 -4
- package/dist/assets/App-BN09Ng5O.css +0 -1
- package/dist/assets/App-Bq4YFGdc.js +0 -4
- package/dist/assets/index-CpFdKgxj.js +0 -14
- package/dist/assets/landing-COMdmQW2.js +0 -43
- package/dist/assets/landing-yoH7kvwQ.css +0 -1
- package/dist/assets/lenis-BmCCtsAn.js +0 -1
- package/dist/assets/main-Ccp2r9X-.js +0 -564
- package/dist/assets/promo-aMad1HB1.js +0 -5
- package/dist/assets/proxy-C8trGop7.js +0 -17
- package/dist/landing.html +0 -22
- /package/dist/assets/{lenis-BNWJ7Zcm.css → promo-BNWJ7Zcm.css} +0 -0
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{d as Z,j as $}from"./proxy-C8trGop7.js";const p=o=>typeof o=="string",B=()=>{let o,e;const t=new Promise((i,n)=>{o=i,e=n});return t.resolve=o,t.reject=e,t},pe=o=>o==null?"":String(o),_s=(o,e,t)=>{o.forEach(i=>{e[i]&&(t[i]=e[i])})},us=/###/g,he=o=>o&&o.includes("###")?o.replace(us,"."):o,fe=o=>!o||p(o),W=(o,e,t)=>{const i=p(e)?e.split("."):e;let n=0;for(;n<i.length-1;){if(fe(o))return{};const a=he(i[n]);!o[a]&&t&&(o[a]=new t),Object.prototype.hasOwnProperty.call(o,a)?o=o[a]:o={},++n}return fe(o)?{}:{obj:o,k:he(i[n])}},ge=(o,e,t)=>{const{obj:i,k:n}=W(o,e,Object);if(i!==void 0||e.length===1){i[n]=t;return}let a=e[e.length-1],s=e.slice(0,e.length-1),r=W(o,s,Object);for(;r.obj===void 0&&s.length;)a=`${s[s.length-1]}.${a}`,s=s.slice(0,s.length-1),r=W(o,s,Object),r?.obj&&typeof r.obj[`${r.k}.${a}`]<"u"&&(r.obj=void 0);r.obj[`${r.k}.${a}`]=t},ps=(o,e,t,i)=>{const{obj:n,k:a}=W(o,e,Object);n[a]=n[a]||[],n[a].push(t)},J=(o,e)=>{const{obj:t,k:i}=W(o,e);if(t&&Object.prototype.hasOwnProperty.call(t,i))return t[i]},hs=(o,e,t)=>{const i=J(o,t);return i!==void 0?i:J(e,t)},Ce=(o,e,t)=>{for(const i in e)i!=="__proto__"&&i!=="constructor"&&(i in o?p(o[i])||o[i]instanceof String||p(e[i])||e[i]instanceof String?t&&(o[i]=e[i]):Ce(o[i],e[i],t):o[i]=e[i]);return o},C=o=>o.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),fs={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},gs=o=>p(o)?o.replace(/[&<>"'\/]/g,e=>fs[e]):o;class ms{constructor(e){this.capacity=e,this.regExpMap=new Map,this.regExpQueue=[]}getRegExp(e){const t=this.regExpMap.get(e);if(t!==void 0)return t;const i=new RegExp(e);return this.regExpQueue.length===this.capacity&&this.regExpMap.delete(this.regExpQueue.shift()),this.regExpMap.set(e,i),this.regExpQueue.push(e),i}}const ys=[" ",",","?","!",";"],bs=new ms(20),vs=(o,e,t)=>{e=e||"",t=t||"";const i=ys.filter(s=>!e.includes(s)&&!t.includes(s));if(i.length===0)return!0;const n=bs.getRegExp(`(${i.map(s=>s==="?"?"\\?":s).join("|")})`);let a=!n.test(o);if(!a){const s=o.indexOf(t);s>0&&!n.test(o.substring(0,s))&&(a=!0)}return a},oe=(o,e,t=".")=>{if(!o)return;if(o[e])return Object.prototype.hasOwnProperty.call(o,e)?o[e]:void 0;const i=e.split(t);let n=o;for(let a=0;a<i.length;){if(!n||typeof n!="object")return;let s,r="";for(let l=a;l<i.length;++l)if(l!==a&&(r+=t),r+=i[l],s=n[r],s!==void 0){if(["string","number","boolean"].includes(typeof s)&&l<i.length-1)continue;a+=l-a+1;break}n=s}return n},V=o=>o?.replace(/_/g,"-"),Ss={type:"logger",log(o){this.output("log",o)},warn(o){this.output("warn",o)},error(o){this.output("error",o)},output(o,e){console?.[o]?.apply?.(console,e)}};class Q{constructor(e,t={}){this.init(e,t)}init(e,t={}){this.prefix=t.prefix||"i18next:",this.logger=e||Ss,this.options=t,this.debug=t.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,t,i,n){return n&&!this.debug?null:(e=e.map(a=>p(a)?a.replace(/[\r\n\x00-\x1F\x7F]/g," "):a),p(e[0])&&(e[0]=`${i}${this.prefix} ${e[0]}`),this.logger[t](e))}create(e){return new Q(this.logger,{prefix:`${this.prefix}:${e}:`,...this.options})}clone(e){return e=e||this.options,e.prefix=e.prefix||this.prefix,new Q(this.logger,e)}}var R=new Q;class ee{constructor(){this.observers={}}on(e,t){return e.split(" ").forEach(i=>{this.observers[i]||(this.observers[i]=new Map);const n=this.observers[i].get(t)||0;this.observers[i].set(t,n+1)}),this}off(e,t){if(this.observers[e]){if(!t){delete this.observers[e];return}this.observers[e].delete(t)}}once(e,t){const i=(...n)=>{t(...n),this.off(e,i)};return this.on(e,i),this}emit(e,...t){this.observers[e]&&Array.from(this.observers[e].entries()).forEach(([n,a])=>{for(let s=0;s<a;s++)n(...t)}),this.observers["*"]&&Array.from(this.observers["*"].entries()).forEach(([n,a])=>{for(let s=0;s<a;s++)n(e,...t)})}}class me extends ee{constructor(e,t={ns:["translation"],defaultNS:"translation"}){super(),this.data=e||{},this.options=t,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.options.ignoreJSONStructure===void 0&&(this.options.ignoreJSONStructure=!0)}addNamespaces(e){this.options.ns.includes(e)||this.options.ns.push(e)}removeNamespaces(e){const t=this.options.ns.indexOf(e);t>-1&&this.options.ns.splice(t,1)}getResource(e,t,i,n={}){const a=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator,s=n.ignoreJSONStructure!==void 0?n.ignoreJSONStructure:this.options.ignoreJSONStructure;let r;e.includes(".")?r=e.split("."):(r=[e,t],i&&(Array.isArray(i)?r.push(...i):p(i)&&a?r.push(...i.split(a)):r.push(i)));const l=J(this.data,r);return!l&&!t&&!i&&e.includes(".")&&(e=r[0],t=r[1],i=r.slice(2).join(".")),l||!s||!p(i)?l:oe(this.data?.[e]?.[t],i,a)}addResource(e,t,i,n,a={silent:!1}){const s=a.keySeparator!==void 0?a.keySeparator:this.options.keySeparator;let r=[e,t];i&&(r=r.concat(s?i.split(s):i)),e.includes(".")&&(r=e.split("."),n=t,t=r[1]),this.addNamespaces(t),ge(this.data,r,n),a.silent||this.emit("added",e,t,i,n)}addResources(e,t,i,n={silent:!1}){for(const a in i)(p(i[a])||Array.isArray(i[a]))&&this.addResource(e,t,a,i[a],{silent:!0});n.silent||this.emit("added",e,t,i)}addResourceBundle(e,t,i,n,a,s={silent:!1,skipCopy:!1}){let r=[e,t];e.includes(".")&&(r=e.split("."),n=i,i=t,t=r[1]),this.addNamespaces(t);let l=J(this.data,r)||{};s.skipCopy||(i=JSON.parse(JSON.stringify(i))),n?Ce(l,i,a):l={...l,...i},ge(this.data,r,l),s.silent||this.emit("added",e,t,i)}removeResourceBundle(e,t){this.hasResourceBundle(e,t)&&delete this.data[e][t],this.removeNamespaces(t),this.emit("removed",e,t)}hasResourceBundle(e,t){return this.getResource(e,t)!==void 0}getResourceBundle(e,t){return t||(t=this.options.defaultNS),this.getResource(e,t)}getDataByLanguage(e){return this.data[e]}hasLanguageSomeTranslations(e){const t=this.getDataByLanguage(e);return!!(t&&Object.keys(t)||[]).find(n=>t[n]&&Object.keys(t[n]).length>0)}toJSON(){return this.data}}var Ie={processors:{},addPostProcessor(o){this.processors[o.name]=o},handle(o,e,t,i,n){return o.forEach(a=>{e=this.processors[a]?.process(e,t,i,n)??e}),e}};const Le=Symbol("i18next/PATH_KEY");function ks(){const o=[],e=Object.create(null);let t;return e.get=(i,n)=>(t?.revoke?.(),n===Le?o:(o.push(n),t=Proxy.revocable(i,e),t.proxy)),Proxy.revocable(Object.create(null),e).proxy}function K(o,e){const{[Le]:t}=o(ks()),i=e?.keySeparator??".",n=e?.nsSeparator??":";if(t.length>1&&n){const a=e?.ns,s=Array.isArray(a)?a:null;if(s&&s.length>1&&s.slice(1).includes(t[0]))return`${t[0]}${n}${t.slice(1).join(i)}`}return t.join(i)}const te=o=>!p(o)&&typeof o!="boolean"&&typeof o!="number";class X extends ee{constructor(e,t={}){super(),_s(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector","i18nFormat","utils"],e,this),this.options=t,this.options.keySeparator===void 0&&(this.options.keySeparator="."),this.logger=R.create("translator"),this.checkedLoadedFor={}}changeLanguage(e){e&&(this.language=e)}exists(e,t={interpolation:{}}){const i={...t};if(e==null)return!1;const n=this.resolve(e,i);if(n?.res===void 0)return!1;const a=te(n.res);return!(i.returnObjects===!1&&a)}extractFromKey(e,t){let i=t.nsSeparator!==void 0?t.nsSeparator:this.options.nsSeparator;i===void 0&&(i=":");const n=t.keySeparator!==void 0?t.keySeparator:this.options.keySeparator;let a=t.ns||this.options.defaultNS||[];const s=i&&e.includes(i),r=!this.options.userDefinedKeySeparator&&!t.keySeparator&&!this.options.userDefinedNsSeparator&&!t.nsSeparator&&!vs(e,i,n);if(s&&!r){const l=e.match(this.interpolator.nestingRegexp);if(l&&l.length>0)return{key:e,namespaces:p(a)?[a]:a};const c=e.split(i);(i!==n||i===n&&this.options.ns.includes(c[0]))&&(a=c.shift()),e=c.join(n)}return{key:e,namespaces:p(a)?[a]:a}}translate(e,t,i){let n=typeof t=="object"?{...t}:t;if(typeof n!="object"&&this.options.overloadTranslationOptionHandler&&(n=this.options.overloadTranslationOptionHandler(arguments)),typeof n=="object"&&(n={...n}),n||(n={}),e==null)return"";typeof e=="function"&&(e=K(e,{...this.options,...n})),Array.isArray(e)||(e=[String(e)]),e=e.map(v=>typeof v=="function"?K(v,{...this.options,...n}):String(v));const a=n.returnDetails!==void 0?n.returnDetails:this.options.returnDetails,s=n.keySeparator!==void 0?n.keySeparator:this.options.keySeparator,{key:r,namespaces:l}=this.extractFromKey(e[e.length-1],n),c=l[l.length-1];let _=n.nsSeparator!==void 0?n.nsSeparator:this.options.nsSeparator;_===void 0&&(_=":");const d=n.lng||this.language,u=n.appendNamespaceToCIMode||this.options.appendNamespaceToCIMode;if(d?.toLowerCase()==="cimode")return u?a?{res:`${c}${_}${r}`,usedKey:r,exactUsedKey:r,usedLng:d,usedNS:c,usedParams:this.getUsedParamsDetails(n)}:`${c}${_}${r}`:a?{res:r,usedKey:r,exactUsedKey:r,usedLng:d,usedNS:c,usedParams:this.getUsedParamsDetails(n)}:r;const f=this.resolve(e,n);let h=f?.res;const m=f?.usedKey||r,b=f?.exactUsedKey||r,w=["[object Number]","[object Function]","[object RegExp]"],y=n.joinArrays!==void 0?n.joinArrays:this.options.joinArrays,E=!this.i18nFormat||this.i18nFormat.handleAsObject,S=n.count!==void 0&&!p(n.count),I=X.hasDefaultValue(n),M=S?this.pluralResolver.getSuffix(d,n.count,n):"",j=n.ordinal&&S?this.pluralResolver.getSuffix(d,n.count,{ordinal:!1}):"",ce=S&&!n.ordinal&&n.count===0,L=ce&&n[`defaultValue${this.options.pluralSeparator}zero`]||n[`defaultValue${M}`]||n[`defaultValue${j}`]||n.defaultValue;let O=h;E&&!h&&I&&(O=L);const cs=te(O),ds=Object.prototype.toString.apply(O);if(E&&O&&cs&&!w.includes(ds)&&!(p(y)&&Array.isArray(O))){if(!n.returnObjects&&!this.options.returnObjects){this.options.returnedObjectHandler||this.logger.warn("accessing an object - but returnObjects options is not enabled!");const v=this.options.returnedObjectHandler?this.options.returnedObjectHandler(m,O,{...n,ns:l}):`key '${r} (${this.language})' returned an object instead of string.`;return a?(f.res=v,f.usedParams=this.getUsedParamsDetails(n),f):v}if(s){const v=Array.isArray(O),x=v?[]:{},de=v?b:m;for(const T in O)if(Object.prototype.hasOwnProperty.call(O,T)){const A=`${de}${s}${T}`;I&&!h?x[T]=this.translate(A,{...n,defaultValue:te(L)?L[T]:void 0,joinArrays:!1,ns:l}):x[T]=this.translate(A,{...n,joinArrays:!1,ns:l}),x[T]===A&&(x[T]=O[T])}h=x}}else if(E&&p(y)&&Array.isArray(h))h=h.join(y),h&&(h=this.extendTranslation(h,e,n,i));else{let v=!1,x=!1;!this.isValidLookup(h)&&I&&(v=!0,h=L),this.isValidLookup(h)||(x=!0,h=r);const T=(n.missingKeyNoValueFallbackToKey||this.options.missingKeyNoValueFallbackToKey)&&x?void 0:h,A=I&&L!==h&&this.options.updateMissing;if(x||v||A){if(this.logger.log(A?"updateKey":"missingKey",d,c,S&&!A?`${r}${this.pluralResolver.getSuffix(d,n.count,n)}`:r,A?L:h),s){const k=this.resolve(r,{...n,keySeparator:!1});k&&k.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 F=[];const q=this.languageUtils.getFallbackCodes(this.options.fallbackLng,n.lng||this.language);if(this.options.saveMissingTo==="fallback"&&q&&q[0])for(let k=0;k<q.length;k++)F.push(q[k]);else this.options.saveMissingTo==="all"?F=this.languageUtils.toResolveHierarchy(n.lng||this.language):F.push(n.lng||this.language);const _e=(k,P,z)=>{const ue=I&&z!==h?z:T;this.options.missingKeyHandler?this.options.missingKeyHandler(k,c,P,ue,A,n):this.backendConnector?.saveMissing&&this.backendConnector.saveMissing(k,c,P,ue,A,n),this.emit("missingKey",k,c,P,h)};this.options.saveMissing&&(this.options.saveMissingPlurals&&S?F.forEach(k=>{const P=this.pluralResolver.getSuffixes(k,n);ce&&n[`defaultValue${this.options.pluralSeparator}zero`]&&!P.includes(`${this.options.pluralSeparator}zero`)&&P.push(`${this.options.pluralSeparator}zero`),P.forEach(z=>{_e([k],r+z,n[`defaultValue${z}`]||L)})}):_e(F,r,L))}h=this.extendTranslation(h,e,n,f,i),x&&h===r&&this.options.appendNamespaceToMissingKey&&(h=`${c}${_}${r}`),(x||v)&&this.options.parseMissingKeyHandler&&(h=this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey?`${c}${_}${r}`:r,v?h:void 0,n))}return a?(f.res=h,f.usedParams=this.getUsedParamsDetails(n),f):h}extendTranslation(e,t,i,n,a){if(this.i18nFormat?.parse)e=this.i18nFormat.parse(e,{...this.options.interpolation.defaultVariables,...i},i.lng||this.language||n.usedLng,n.usedNS,n.usedKey,{resolved:n});else if(!i.skipInterpolation){i.interpolation&&this.interpolator.init({...i,interpolation:{...this.options.interpolation,...i.interpolation}});const l=p(e)&&(i?.interpolation?.skipOnVariables!==void 0?i.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables);let c;if(l){const d=e.match(this.interpolator.nestingRegexp);c=d&&d.length}let _=i.replace&&!p(i.replace)?i.replace:i;if(this.options.interpolation.defaultVariables&&(_={...this.options.interpolation.defaultVariables,..._}),e=this.interpolator.interpolate(e,_,i.lng||this.language||n.usedLng,i),l){const d=e.match(this.interpolator.nestingRegexp),u=d&&d.length;c<u&&(i.nest=!1)}!i.lng&&n&&n.res&&(i.lng=this.language||n.usedLng),i.nest!==!1&&(e=this.interpolator.nest(e,(...d)=>a?.[0]===d[0]&&!i.context?(this.logger.warn(`It seems you are nesting recursively key: ${d[0]} in key: ${t[0]}`),null):this.translate(...d,t),i)),i.interpolation&&this.interpolator.reset()}const s=i.postProcess||this.options.postProcess,r=p(s)?[s]:s;return e!=null&&r?.length&&i.applyPostProcessor!==!1&&(e=Ie.handle(r,e,t,this.options&&this.options.postProcessPassResolved?{i18nResolved:{...n,usedParams:this.getUsedParamsDetails(i)},...i}:i,this)),e}resolve(e,t={}){let i,n,a,s,r;return p(e)&&(e=[e]),Array.isArray(e)&&(e=e.map(l=>typeof l=="function"?K(l,{...this.options,...t}):l)),e.forEach(l=>{if(this.isValidLookup(i))return;const c=this.extractFromKey(l,t),_=c.key;n=_;let d=c.namespaces;this.options.fallbackNS&&(d=d.concat(this.options.fallbackNS));const u=t.count!==void 0&&!p(t.count),f=u&&!t.ordinal&&t.count===0,h=t.context!==void 0&&(p(t.context)||typeof t.context=="number")&&t.context!=="",m=t.lngs?t.lngs:this.languageUtils.toResolveHierarchy(t.lng||this.language,t.fallbackLng);d.forEach(b=>{this.isValidLookup(i)||(r=b,!this.checkedLoadedFor[`${m[0]}-${b}`]&&this.utils?.hasLoadedNamespace&&!this.utils?.hasLoadedNamespace(r)&&(this.checkedLoadedFor[`${m[0]}-${b}`]=!0,this.logger.warn(`key "${n}" for languages "${m.join(", ")}" won't get resolved as namespace "${r}" 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!!!")),m.forEach(w=>{if(this.isValidLookup(i))return;s=w;const y=[_];if(this.i18nFormat?.addLookupKeys)this.i18nFormat.addLookupKeys(y,_,w,b,t);else{let S;u&&(S=this.pluralResolver.getSuffix(w,t.count,t));const I=`${this.options.pluralSeparator}zero`,M=`${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`;if(u&&(t.ordinal&&S.startsWith(M)&&y.push(_+S.replace(M,this.options.pluralSeparator)),y.push(_+S),f&&y.push(_+I)),h){const j=`${_}${this.options.contextSeparator||"_"}${t.context}`;y.push(j),u&&(t.ordinal&&S.startsWith(M)&&y.push(j+S.replace(M,this.options.pluralSeparator)),y.push(j+S),f&&y.push(j+I))}}let E;for(;E=y.pop();)this.isValidLookup(i)||(a=E,i=this.getResource(w,b,E,t))}))})}),{res:i,usedKey:n,exactUsedKey:a,usedLng:s,usedNS:r}}isValidLookup(e){return e!==void 0&&!(!this.options.returnNull&&e===null)&&!(!this.options.returnEmptyString&&e==="")}getResource(e,t,i,n={}){return this.i18nFormat?.getResource?this.i18nFormat.getResource(e,t,i,n):this.resourceStore.getResource(e,t,i,n)}getUsedParamsDetails(e={}){const t=["defaultValue","ordinal","context","replace","lng","lngs","fallbackLng","ns","keySeparator","nsSeparator","returnObjects","returnDetails","joinArrays","postProcess","interpolation"],i=e.replace&&!p(e.replace);let n=i?e.replace:e;if(i&&typeof e.count<"u"&&(n.count=e.count),this.options.interpolation.defaultVariables&&(n={...this.options.interpolation.defaultVariables,...n}),!i){n={...n};for(const a of t)delete n[a]}return n}static hasDefaultValue(e){const t="defaultValue";for(const i in e)if(Object.prototype.hasOwnProperty.call(e,i)&&i.startsWith(t)&&e[i]!==void 0)return!0;return!1}}class ye{constructor(e){this.options=e,this.supportedLngs=this.options.supportedLngs||!1,this.logger=R.create("languageUtils")}getScriptPartFromCode(e){if(e=V(e),!e||!e.includes("-"))return null;const t=e.split("-");return t.length===2||(t.pop(),t[t.length-1].toLowerCase()==="x")?null:this.formatLanguageCode(t.join("-"))}getLanguagePartFromCode(e){if(e=V(e),!e||!e.includes("-"))return e;const t=e.split("-");return this.formatLanguageCode(t[0])}formatLanguageCode(e){if(p(e)&&e.includes("-")){let t;try{t=Intl.getCanonicalLocales(e)[0]}catch{}return t&&this.options.lowerCaseLng&&(t=t.toLowerCase()),t||(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.includes(e)}getBestMatchFromCodes(e){if(!e)return null;let t;return e.forEach(i=>{if(t)return;const n=this.formatLanguageCode(i);(!this.options.supportedLngs||this.isSupportedCode(n))&&(t=n)}),!t&&this.options.supportedLngs&&e.forEach(i=>{if(t)return;const n=this.getScriptPartFromCode(i);if(this.isSupportedCode(n))return t=n;const a=this.getLanguagePartFromCode(i);if(this.isSupportedCode(a))return t=a;t=this.options.supportedLngs.find(s=>s===a?!0:!s.includes("-")&&!a.includes("-")?!1:!!(s.includes("-")&&!a.includes("-")&&s.slice(0,s.indexOf("-"))===a||s.startsWith(a)&&a.length>1))}),t||(t=this.getFallbackCodes(this.options.fallbackLng)[0]),t}getFallbackCodes(e,t){if(!e)return[];if(typeof e=="function"&&(e=e(t)),p(e)&&(e=[e]),Array.isArray(e))return e;if(!t)return e.default||[];let i=e[t];return i||(i=e[this.getScriptPartFromCode(t)]),i||(i=e[this.formatLanguageCode(t)]),i||(i=e[this.getLanguagePartFromCode(t)]),i||(i=e.default),i||[]}toResolveHierarchy(e,t){const i=this.getFallbackCodes((t===!1?[]:t)||this.options.fallbackLng||[],e),n=[],a=s=>{s&&(this.isSupportedCode(s)?n.push(s):this.logger.warn(`rejecting language code not found in supportedLngs: ${s}`))};return p(e)&&(e.includes("-")||e.includes("_"))?(this.options.load!=="languageOnly"&&a(this.formatLanguageCode(e)),this.options.load!=="languageOnly"&&this.options.load!=="currentOnly"&&a(this.getScriptPartFromCode(e)),this.options.load!=="currentOnly"&&a(this.getLanguagePartFromCode(e))):p(e)&&a(this.formatLanguageCode(e)),i.forEach(s=>{n.includes(s)||a(this.formatLanguageCode(s))}),n}}const be={zero:0,one:1,two:2,few:3,many:4,other:5},ve={select:o=>o===1?"one":"other",resolvedOptions:()=>({pluralCategories:["one","other"]})};class ws{constructor(e,t={}){this.languageUtils=e,this.options=t,this.logger=R.create("pluralResolver"),this.pluralRulesCache={}}clearCache(){this.pluralRulesCache={}}getRule(e,t={}){const i=V(e==="dev"?"en":e),n=t.ordinal?"ordinal":"cardinal",a=JSON.stringify({cleanedCode:i,type:n});if(a in this.pluralRulesCache)return this.pluralRulesCache[a];let s;try{s=new Intl.PluralRules(i,{type:n})}catch{if(typeof Intl>"u")return this.logger.error("No Intl support, please use an Intl polyfill!"),ve;if(!e.match(/-|_/))return ve;const l=this.languageUtils.getLanguagePartFromCode(e);s=this.getRule(l,t)}return this.pluralRulesCache[a]=s,s}needsPlural(e,t={}){let i=this.getRule(e,t);return i||(i=this.getRule("dev",t)),i?.resolvedOptions().pluralCategories.length>1}getPluralFormsOfKey(e,t,i={}){return this.getSuffixes(e,i).map(n=>`${t}${n}`)}getSuffixes(e,t={}){let i=this.getRule(e,t);return i||(i=this.getRule("dev",t)),i?i.resolvedOptions().pluralCategories.sort((n,a)=>be[n]-be[a]).map(n=>`${this.options.prepend}${t.ordinal?`ordinal${this.options.prepend}`:""}${n}`):[]}getSuffix(e,t,i={}){const n=this.getRule(e,i);return n?`${this.options.prepend}${i.ordinal?`ordinal${this.options.prepend}`:""}${n.select(t)}`:(this.logger.warn(`no plural rule found for: ${e}`),this.getSuffix("dev",t,i))}}const Se=(o,e,t,i=".",n=!0)=>{let a=hs(o,e,t);return!a&&n&&p(t)&&(a=oe(o,t,i),a===void 0&&(a=oe(e,t,i))),a},ie=o=>o.replace(/\$/g,"$$$$");class ke{constructor(e={}){this.logger=R.create("interpolator"),this.options=e,this.format=e?.interpolation?.format||(t=>t),this.init(e)}init(e={}){e.interpolation||(e.interpolation={escapeValue:!0});const{escape:t,escapeValue:i,useRawValueToEscape:n,prefix:a,prefixEscaped:s,suffix:r,suffixEscaped:l,formatSeparator:c,unescapeSuffix:_,unescapePrefix:d,nestingPrefix:u,nestingPrefixEscaped:f,nestingSuffix:h,nestingSuffixEscaped:m,nestingOptionsSeparator:b,maxReplaces:w,alwaysFormat:y}=e.interpolation;this.escape=t!==void 0?t:gs,this.escapeValue=i!==void 0?i:!0,this.useRawValueToEscape=n!==void 0?n:!1,this.prefix=a?C(a):s||"{{",this.suffix=r?C(r):l||"}}",this.formatSeparator=c||",",this.unescapePrefix=_?"":d?C(d):"-",this.unescapeSuffix=this.unescapePrefix?"":_?C(_):"",this.nestingPrefix=u?C(u):f||C("$t("),this.nestingSuffix=h?C(h):m||C(")"),this.nestingOptionsSeparator=b||",",this.maxReplaces=w||1e3,this.alwaysFormat=y!==void 0?y:!1,this.resetRegExp()}reset(){this.options&&this.init(this.options)}resetRegExp(){const e=(t,i)=>t?.source===i?(t.lastIndex=0,t):new RegExp(i,"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,t,i,n){let a,s,r;const l=this.options&&this.options.interpolation&&this.options.interpolation.defaultVariables||{},c=f=>{if(!f.includes(this.formatSeparator)){const w=Se(t,l,f,this.options.keySeparator,this.options.ignoreJSONStructure);return this.alwaysFormat?this.format(w,void 0,i,{...n,...t,interpolationkey:f}):w}const h=f.split(this.formatSeparator),m=h.shift().trim(),b=h.join(this.formatSeparator).trim();return this.format(Se(t,l,m,this.options.keySeparator,this.options.ignoreJSONStructure),b,i,{...n,...t,interpolationkey:m})};this.resetRegExp(),!this.escapeValue&&typeof e=="string"&&/\$t\([^)]*\{[^}]*\{\{/.test(e)&&this.logger.warn("nesting options string contains interpolated variables with escapeValue: false — if any of those values are attacker-controlled they can inject additional nesting options (e.g. redirect lng/ns). Sanitise untrusted input before passing it to t(), or keep escapeValue: true.");const _=n?.missingInterpolationHandler||this.options.missingInterpolationHandler,d=n?.interpolation?.skipOnVariables!==void 0?n.interpolation.skipOnVariables:this.options.interpolation.skipOnVariables;return[{regex:this.regexpUnescape,safeValue:f=>ie(f)},{regex:this.regexp,safeValue:f=>this.escapeValue?ie(this.escape(f)):ie(f)}].forEach(f=>{for(r=0;a=f.regex.exec(e);){const h=a[1].trim();if(s=c(h),s===void 0)if(typeof _=="function"){const b=_(e,a,n);s=p(b)?b:""}else if(n&&Object.prototype.hasOwnProperty.call(n,h))s="";else if(d){s=a[0];continue}else this.logger.warn(`missed to pass in variable ${h} for interpolating ${e}`),s="";else!p(s)&&!this.useRawValueToEscape&&(s=pe(s));const m=f.safeValue(s);if(e=e.replace(a[0],m),d?(f.regex.lastIndex+=s.length,f.regex.lastIndex-=a[0].length):f.regex.lastIndex=0,r++,r>=this.maxReplaces)break}}),e}nest(e,t,i={}){let n,a,s;const r=(l,c)=>{const _=this.nestingOptionsSeparator;if(!l.includes(_))return l;const d=l.split(new RegExp(`${C(_)}[ ]*{`));let u=`{${d[1]}`;l=d[0],u=this.interpolate(u,s);const f=u.match(/'/g),h=u.match(/"/g);((f?.length??0)%2===0&&!h||(h?.length??0)%2!==0)&&(u=u.replace(/'/g,'"'));try{s=JSON.parse(u),c&&(s={...c,...s})}catch(m){return this.logger.warn(`failed parsing options string in nesting for key ${l}`,m),`${l}${_}${u}`}return s.defaultValue&&s.defaultValue.includes(this.prefix)&&delete s.defaultValue,l};for(;n=this.nestingRegexp.exec(e);){let l=[];s={...i},s=s.replace&&!p(s.replace)?s.replace:s,s.applyPostProcessor=!1,delete s.defaultValue;const c=/{.*}/.test(n[1])?n[1].lastIndexOf("}")+1:n[1].indexOf(this.formatSeparator);if(c!==-1&&(l=n[1].slice(c).split(this.formatSeparator).map(_=>_.trim()).filter(Boolean),n[1]=n[1].slice(0,c)),a=t(r.call(this,n[1].trim(),s),s),a&&n[0]===e&&!p(a))return a;p(a)||(a=pe(a)),a||(this.logger.warn(`missed to resolve ${n[1]} for nesting ${e}`),a=""),l.length&&(a=l.reduce((_,d)=>this.format(_,d,i.lng,{...i,interpolationkey:n[1].trim()}),a.trim())),e=e.replace(n[0],a),this.regexp.lastIndex=0}return e}}const xs=o=>{let e=o.toLowerCase().trim();const t={};if(o.includes("(")){const i=o.split("(");e=i[0].toLowerCase().trim();const n=i[1].slice(0,-1);e==="currency"&&!n.includes(":")?t.currency||(t.currency=n.trim()):e==="relativetime"&&!n.includes(":")?t.range||(t.range=n.trim()):n.split(";").forEach(s=>{if(s){const[r,...l]=s.split(":"),c=l.join(":").trim().replace(/^'+|'+$/g,""),_=r.trim();t[_]||(t[_]=c),c==="false"&&(t[_]=!1),c==="true"&&(t[_]=!0),isNaN(c)||(t[_]=parseInt(c,10))}})}return{formatName:e,formatOptions:t}},we=o=>{const e={};return(t,i,n)=>{let a=n;n&&n.interpolationkey&&n.formatParams&&n.formatParams[n.interpolationkey]&&n[n.interpolationkey]&&(a={...a,[n.interpolationkey]:void 0});const s=i+JSON.stringify(a);let r=e[s];return r||(r=o(V(i),n),e[s]=r),r(t)}},Os=o=>(e,t,i)=>o(V(t),i)(e);class Ts{constructor(e={}){this.logger=R.create("formatter"),this.options=e,this.init(e)}init(e,t={interpolation:{}}){this.formatSeparator=t.interpolation.formatSeparator||",";const i=t.cacheInBuiltFormats?we:Os;this.formats={number:i((n,a)=>{const s=new Intl.NumberFormat(n,{...a});return r=>s.format(r)}),currency:i((n,a)=>{const s=new Intl.NumberFormat(n,{...a,style:"currency"});return r=>s.format(r)}),datetime:i((n,a)=>{const s=new Intl.DateTimeFormat(n,{...a});return r=>s.format(r)}),relativetime:i((n,a)=>{const s=new Intl.RelativeTimeFormat(n,{...a});return r=>s.format(r,a.range||"day")}),list:i((n,a)=>{const s=new Intl.ListFormat(n,{...a});return r=>s.format(r)})}}add(e,t){this.formats[e.toLowerCase().trim()]=t}addCached(e,t){this.formats[e.toLowerCase().trim()]=we(t)}format(e,t,i,n={}){if(!t||e==null)return e;const a=t.split(this.formatSeparator);if(a.length>1&&a[0].indexOf("(")>1&&!a[0].includes(")")&&a.find(r=>r.includes(")"))){const r=a.findIndex(l=>l.includes(")"));a[0]=[a[0],...a.splice(1,r)].join(this.formatSeparator)}return a.reduce((r,l)=>{const{formatName:c,formatOptions:_}=xs(l);if(this.formats[c]){let d=r;try{const u=n?.formatParams?.[n.interpolationkey]||{},f=u.locale||u.lng||n.locale||n.lng||i;d=this.formats[c](r,f,{..._,...n,...u})}catch(u){this.logger.warn(u)}return d}else this.logger.warn(`there was no format function for ${c}`);return r},e)}}const As=(o,e)=>{o.pending[e]!==void 0&&(delete o.pending[e],o.pendingCount--)};class Rs extends ee{constructor(e,t,i,n={}){super(),this.backend=e,this.store=t,this.services=i,this.languageUtils=i.languageUtils,this.options=n,this.logger=R.create("backendConnector"),this.waitingReads=[],this.maxParallelReads=n.maxParallelReads||10,this.readingCalls=0,this.maxRetries=n.maxRetries>=0?n.maxRetries:5,this.retryTimeout=n.retryTimeout>=1?n.retryTimeout:350,this.state={},this.queue=[],this.backend?.init?.(i,n.backend,n)}queueLoad(e,t,i,n){const a={},s={},r={},l={};return e.forEach(c=>{let _=!0;t.forEach(d=>{const u=`${c}|${d}`;!i.reload&&this.store.hasResourceBundle(c,d)?this.state[u]=2:this.state[u]<0||(this.state[u]===1?s[u]===void 0&&(s[u]=!0):(this.state[u]=1,_=!1,s[u]===void 0&&(s[u]=!0),a[u]===void 0&&(a[u]=!0),l[d]===void 0&&(l[d]=!0)))}),_||(r[c]=!0)}),(Object.keys(a).length||Object.keys(s).length)&&this.queue.push({pending:s,pendingCount:Object.keys(s).length,loaded:{},errors:[],callback:n}),{toLoad:Object.keys(a),pending:Object.keys(s),toLoadLanguages:Object.keys(r),toLoadNamespaces:Object.keys(l)}}loaded(e,t,i){const n=e.split("|"),a=n[0],s=n[1];t&&this.emit("failedLoading",a,s,t),!t&&i&&this.store.addResourceBundle(a,s,i,void 0,void 0,{skipCopy:!0}),this.state[e]=t?-1:2,t&&i&&(this.state[e]=0);const r={};this.queue.forEach(l=>{ps(l.loaded,[a],s),As(l,e),t&&l.errors.push(t),l.pendingCount===0&&!l.done&&(Object.keys(l.loaded).forEach(c=>{r[c]||(r[c]={});const _=l.loaded[c];_.length&&_.forEach(d=>{r[c][d]===void 0&&(r[c][d]=!0)})}),l.done=!0,l.errors.length?l.callback(l.errors):l.callback())}),this.emit("loaded",r),this.queue=this.queue.filter(l=>!l.done)}read(e,t,i,n=0,a=this.retryTimeout,s){if(!e.length)return s(null,{});if(this.readingCalls>=this.maxParallelReads){this.waitingReads.push({lng:e,ns:t,fcName:i,tried:n,wait:a,callback:s});return}this.readingCalls++;const r=(c,_)=>{if(this.readingCalls--,this.waitingReads.length>0){const d=this.waitingReads.shift();this.read(d.lng,d.ns,d.fcName,d.tried,d.wait,d.callback)}if(c&&_&&n<this.maxRetries){setTimeout(()=>{this.read(e,t,i,n+1,a*2,s)},a);return}s(c,_)},l=this.backend[i].bind(this.backend);if(l.length===2){try{const c=l(e,t);c&&typeof c.then=="function"?c.then(_=>r(null,_)).catch(r):r(null,c)}catch(c){r(c)}return}return l(e,t,r)}prepareLoading(e,t,i={},n){if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),n&&n();p(e)&&(e=this.languageUtils.toResolveHierarchy(e)),p(t)&&(t=[t]);const a=this.queueLoad(e,t,i,n);if(!a.toLoad.length)return a.pending.length||n(),null;a.toLoad.forEach(s=>{this.loadOne(s)})}load(e,t,i){this.prepareLoading(e,t,{},i)}reload(e,t,i){this.prepareLoading(e,t,{reload:!0},i)}loadOne(e,t=""){const i=e.split("|"),n=i[0],a=i[1];this.read(n,a,"read",void 0,void 0,(s,r)=>{s&&this.logger.warn(`${t}loading namespace ${a} for language ${n} failed`,s),!s&&r&&this.logger.log(`${t}loaded namespace ${a} for language ${n}`,r),this.loaded(e,s,r)})}saveMissing(e,t,i,n,a,s={},r=()=>{}){if(this.services?.utils?.hasLoadedNamespace&&!this.services?.utils?.hasLoadedNamespace(t)){this.logger.warn(`did not save key "${i}" as the namespace "${t}" 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(!(i==null||i==="")){if(this.backend?.create){const l={...s,isUpdate:a},c=this.backend.create.bind(this.backend);if(c.length<6)try{let _;c.length===5?_=c(e,t,i,n,l):_=c(e,t,i,n),_&&typeof _.then=="function"?_.then(d=>r(null,d)).catch(r):r(null,_)}catch(_){r(_)}else c(e,t,i,n,r,l)}!e||!e[0]||this.store.addResource(e[0],t,i,n)}}}const ne=()=>({debug:!1,initAsync:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,supportedLngs:!1,nonExplicitSupportedLngs:!1,load:"all",preload:!1,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:o=>{let e={};if(typeof o[1]=="object"&&(e=o[1]),p(o[1])&&(e.defaultValue=o[1]),p(o[2])&&(e.tDescription=o[2]),typeof o[2]=="object"||typeof o[3]=="object"){const t=o[3]||o[2];Object.keys(t).forEach(i=>{e[i]=t[i]})}return e},interpolation:{escapeValue:!0,prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",nestingOptionsSeparator:",",maxReplaces:1e3,skipOnVariables:!0},cacheInBuiltFormats:!0}),xe=o=>(p(o.ns)&&(o.ns=[o.ns]),p(o.fallbackLng)&&(o.fallbackLng=[o.fallbackLng]),p(o.fallbackNS)&&(o.fallbackNS=[o.fallbackNS]),o.supportedLngs&&!o.supportedLngs.includes("cimode")&&(o.supportedLngs=o.supportedLngs.concat(["cimode"])),o),G=()=>{},Cs=o=>{Object.getOwnPropertyNames(Object.getPrototypeOf(o)).forEach(t=>{typeof o[t]=="function"&&(o[t]=o[t].bind(o))})};class H extends ee{constructor(e={},t){if(super(),this.options=xe(e),this.services={},this.logger=R,this.modules={external:[]},Cs(this),t&&!this.isInitialized&&!e.isClone){if(!this.options.initAsync)return this.init(e,t),this;setTimeout(()=>{this.init(e,t)},0)}}init(e={},t){this.isInitializing=!0,typeof e=="function"&&(t=e,e={}),e.defaultNS==null&&e.ns&&(p(e.ns)?e.defaultNS=e.ns:e.ns.includes("translation")||(e.defaultNS=e.ns[0]));const i=ne();this.options={...i,...this.options,...xe(e)},this.options.interpolation={...i.interpolation,...this.options.interpolation},e.keySeparator!==void 0&&(this.options.userDefinedKeySeparator=e.keySeparator),e.nsSeparator!==void 0&&(this.options.userDefinedNsSeparator=e.nsSeparator),typeof this.options.overloadTranslationOptionHandler!="function"&&(this.options.overloadTranslationOptionHandler=i.overloadTranslationOptionHandler);const n=c=>c?typeof c=="function"?new c:c:null;if(!this.options.isClone){this.modules.logger?R.init(n(this.modules.logger),this.options):R.init(null,this.options);let c;this.modules.formatter?c=this.modules.formatter:c=Ts;const _=new ye(this.options);this.store=new me(this.options.resources,this.options);const d=this.services;d.logger=R,d.resourceStore=this.store,d.languageUtils=_,d.pluralResolver=new ws(_,{prepend:this.options.pluralSeparator}),c&&(d.formatter=n(c),d.formatter.init&&d.formatter.init(d,this.options),this.options.interpolation.format=d.formatter.format.bind(d.formatter)),d.interpolator=new ke(this.options),d.utils={hasLoadedNamespace:this.hasLoadedNamespace.bind(this)},d.backendConnector=new Rs(n(this.modules.backend),d.resourceStore,d,this.options),d.backendConnector.on("*",(u,...f)=>{this.emit(u,...f)}),this.modules.languageDetector&&(d.languageDetector=n(this.modules.languageDetector),d.languageDetector.init&&d.languageDetector.init(d,this.options.detection,this.options)),this.modules.i18nFormat&&(d.i18nFormat=n(this.modules.i18nFormat),d.i18nFormat.init&&d.i18nFormat.init(this)),this.translator=new X(this.services,this.options),this.translator.on("*",(u,...f)=>{this.emit(u,...f)}),this.modules.external.forEach(u=>{u.init&&u.init(this)})}if(this.format=this.options.interpolation.format,t||(t=G),this.options.fallbackLng&&!this.services.languageDetector&&!this.options.lng){const c=this.services.languageUtils.getFallbackCodes(this.options.fallbackLng);c.length>0&&c[0]!=="dev"&&(this.options.lng=c[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(c=>{this[c]=(..._)=>this.store[c](..._)}),["addResource","addResources","addResourceBundle","removeResourceBundle"].forEach(c=>{this[c]=(..._)=>(this.store[c](..._),this)});const r=B(),l=()=>{const c=(_,d)=>{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),r.resolve(d),t(_,d)};if((this.languages||this.isLanguageChangingTo)&&!this.isInitialized)return c(null,this.t.bind(this));this.changeLanguage(this.options.lng,c)};return this.options.resources||!this.options.initAsync?l():setTimeout(l,0),r}loadResources(e,t=G){let i=t;const n=p(e)?e:this.language;if(typeof e=="function"&&(i=e),!this.options.resources||this.options.partialBundledLanguages){if(n?.toLowerCase()==="cimode"&&(!this.options.preload||this.options.preload.length===0))return i();const a=[],s=r=>{if(!r||r==="cimode")return;this.services.languageUtils.toResolveHierarchy(r).forEach(c=>{c!=="cimode"&&(a.includes(c)||a.push(c))})};n?s(n):this.services.languageUtils.getFallbackCodes(this.options.fallbackLng).forEach(l=>s(l)),this.options.preload?.forEach?.(r=>s(r)),this.services.backendConnector.load(a,this.options.ns,r=>{!r&&!this.resolvedLanguage&&this.language&&this.setResolvedLanguage(this.language),i(r)})}else i(null)}reloadResources(e,t,i){const n=B();return typeof e=="function"&&(i=e,e=void 0),typeof t=="function"&&(i=t,t=void 0),e||(e=this.languages),t||(t=this.options.ns),i||(i=G),this.services.backendConnector.reload(e,t,a=>{n.resolve(),i(a)}),n}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"&&Ie.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"].includes(e)){for(let t=0;t<this.languages.length;t++){const i=this.languages[t];if(!["cimode","dev"].includes(i)&&this.store.hasLanguageSomeTranslations(i)){this.resolvedLanguage=i;break}}!this.resolvedLanguage&&!this.languages.includes(e)&&this.store.hasLanguageSomeTranslations(e)&&(this.resolvedLanguage=e,this.languages.unshift(e))}}changeLanguage(e,t){this.isLanguageChangingTo=e;const i=B();this.emit("languageChanging",e);const n=r=>{this.language=r,this.languages=this.services.languageUtils.toResolveHierarchy(r),this.resolvedLanguage=void 0,this.setResolvedLanguage(r)},a=(r,l)=>{l?this.isLanguageChangingTo===e&&(n(l),this.translator.changeLanguage(l),this.isLanguageChangingTo=void 0,this.emit("languageChanged",l),this.logger.log("languageChanged",l)):this.isLanguageChangingTo=void 0,i.resolve((...c)=>this.t(...c)),t&&t(r,(...c)=>this.t(...c))},s=r=>{!e&&!r&&this.services.languageDetector&&(r=[]);const l=p(r)?r:r&&r[0],c=this.store.hasLanguageSomeTranslations(l)?l:this.services.languageUtils.getBestMatchFromCodes(p(r)?[r]:r);c&&(this.language||n(c),this.translator.language||this.translator.changeLanguage(c),this.services.languageDetector?.cacheUserLanguage?.(c)),this.loadResources(c,_=>{a(_,c)})};return!e&&this.services.languageDetector&&!this.services.languageDetector.async?s(this.services.languageDetector.detect()):!e&&this.services.languageDetector&&this.services.languageDetector.async?this.services.languageDetector.detect.length===0?this.services.languageDetector.detect().then(s):this.services.languageDetector.detect(s):s(e),i}getFixedT(e,t,i){const n=(a,s,...r)=>{let l;typeof s!="object"?l=this.options.overloadTranslationOptionHandler([a,s].concat(r)):l={...s},l.lng=l.lng||n.lng,l.lngs=l.lngs||n.lngs,l.ns=l.ns||n.ns,l.keyPrefix!==""&&(l.keyPrefix=l.keyPrefix||i||n.keyPrefix);const c={...this.options,...l};typeof l.keyPrefix=="function"&&(l.keyPrefix=K(l.keyPrefix,c));const _=this.options.keySeparator||".";let d;return l.keyPrefix&&Array.isArray(a)?d=a.map(u=>(typeof u=="function"&&(u=K(u,c)),`${l.keyPrefix}${_}${u}`)):(typeof a=="function"&&(a=K(a,c)),d=l.keyPrefix?`${l.keyPrefix}${_}${a}`:a),this.t(d,l)};return p(e)?n.lng=e:n.lngs=e,n.ns=t,n.keyPrefix=i,n}t(...e){return this.translator?.translate(...e)}exists(...e){return this.translator?.exists(...e)}setDefaultNamespace(e){this.options.defaultNS=e}hasLoadedNamespace(e,t={}){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 i=t.lng||this.resolvedLanguage||this.languages[0],n=this.options?this.options.fallbackLng:!1,a=this.languages[this.languages.length-1];if(i.toLowerCase()==="cimode")return!0;const s=(r,l)=>{const c=this.services.backendConnector.state[`${r}|${l}`];return c===-1||c===0||c===2};if(t.precheck){const r=t.precheck(this,s);if(r!==void 0)return r}return!!(this.hasResourceBundle(i,e)||!this.services.backendConnector.backend||this.options.resources&&!this.options.partialBundledLanguages||s(i,e)&&(!n||s(a,e)))}loadNamespaces(e,t){const i=B();return this.options.ns?(p(e)&&(e=[e]),e.forEach(n=>{this.options.ns.includes(n)||this.options.ns.push(n)}),this.loadResources(n=>{i.resolve(),t&&t(n)}),i):(t&&t(),Promise.resolve())}loadLanguages(e,t){const i=B();p(e)&&(e=[e]);const n=this.options.preload||[],a=e.filter(s=>!n.includes(s)&&this.services.languageUtils.isSupportedCode(s));return a.length?(this.options.preload=n.concat(a),this.loadResources(s=>{i.resolve(),t&&t(s)}),i):(t&&t(),Promise.resolve())}dir(e){if(e||(e=this.resolvedLanguage||(this.languages?.length>0?this.languages[0]:this.language)),!e)return"rtl";try{const n=new Intl.Locale(e);if(n&&n.getTextInfo){const a=n.getTextInfo();if(a&&a.direction)return a.direction}}catch{}const t=["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"],i=this.services?.languageUtils||new ye(ne());return e.toLowerCase().indexOf("-latn")>1?"ltr":t.includes(i.getLanguagePartFromCode(e))||e.toLowerCase().indexOf("-arab")>1?"rtl":"ltr"}static createInstance(e={},t){const i=new H(e,t);return i.createInstance=H.createInstance,i}cloneInstance(e={},t=G){const i=e.forkResourceStore;i&&delete e.forkResourceStore;const n={...this.options,...e,isClone:!0},a=new H(n);if((e.debug!==void 0||e.prefix!==void 0)&&(a.logger=a.logger.clone(e)),["store","services","language"].forEach(r=>{a[r]=this[r]}),a.services={...this.services},a.services.utils={hasLoadedNamespace:a.hasLoadedNamespace.bind(a)},i){const r=Object.keys(this.store.data).reduce((l,c)=>(l[c]={...this.store.data[c]},l[c]=Object.keys(l[c]).reduce((_,d)=>(_[d]={...l[c][d]},_),l[c]),l),{});a.store=new me(r,n),a.services.resourceStore=a.store}if(e.interpolation){const l={...ne().interpolation,...this.options.interpolation,...e.interpolation},c={...n,interpolation:l};a.services.interpolator=new ke(c)}return a.translator=new X(a.services,n),a.translator.on("*",(r,...l)=>{a.emit(r,...l)}),a.init(n,t),a.translator.options=n,a.translator.backendConnector.services.utils={hasLoadedNamespace:a.hasLoadedNamespace.bind(a)},a}toJSON(){return{options:this.options,store:this.store,language:this.language,languages:this.languages,resolvedLanguage:this.resolvedLanguage}}}const g=H.createInstance();g.createInstance;g.dir;g.init;g.loadResources;g.reloadResources;g.use;g.changeLanguage;g.getFixedT;g.t;g.exists;g.setDefaultNamespace;g.hasLoadedNamespace;g.loadNamespaces;g.loadLanguages;const $e={ok:"OK",cancel:"Cancel",confirm:"Confirm",save:"Save",close:"Close",retry:"Retry",clear:"Clear",remove:"Remove",add:"Add",back:"Back",next:"Next",done:"Done",skip:"Skip",copy:"Copy",edit:"Edit",search:"Search",loading:"Loading…"},Ee={system:"System","zh-CN":"简体中文","zh-TW":"繁體中文",en:"English"},Pe={system_default:"System default",system_default_with_current:"System default ({{name}})",auto_detect:"Auto-detect",none:"None"},Is={actions:$e,lang:Ee,value:Pe},Ls=Object.freeze(Object.defineProperty({__proto__:null,actions:$e,default:Is,lang:Ee,value:Pe},Symbol.toStringTag,{value:"Module"})),Ne={title:"Hotkey conflict",description_one:"The shortcut below is currently invalid (claimed by the system or against the latest rules). Bind a new combo right here.",description_other:"{{count}} shortcuts are currently invalid (claimed by the system or against the latest rules). Bind new combos right here."},Me={title_pending:"Finishing your last recording",title_success:"Transcription ready",title_error:"Transcription failed",description_pending:"You're signed back in — re-running the cloud transcription on your last recording, hang tight…",description_success:"Here is the final transcript. Tap the button below to copy it to the clipboard.",description_error:"Signed back in successfully, but re-transcribing the saved audio failed again. You can retry it manually from History.",empty_transcript:"(Nothing was recognized)",copy:"Copy",copied:"Copied",close:"Close",close_disabled:"Working…"},je={title:"Sign in to OpenLoaf",openloaf_note:"OpenSpeech is an OpenLoaf product — one OpenLoaf account works across the family.",description:"Choose a sign-in method to continue",subtitle:{idle:"Choose how you'd like to sign in",opening:"Opening your browser...",polling:"Waiting for you to finish in the browser",success:"Signed in"},providers:{wechat:"Continue with WeChat",google:"Continue with Google"},or:"OR",byo_button:"Use your own STT endpoint",byo_hint:"Don't want to sign in to OpenLoaf? Point OpenSpeech at your own STT REST endpoint and audio stays local — never routed through our cloud.",retry:"Retry",close:"Close",cancel:"Cancel sign-in",details_show:"Show details",details_hide:"Hide details"},De={title:"Account",description:"OpenSpeech account and subscription",loading:"// loading //",section:{identity:"Identity",subscription:"Subscription",recharge:"Top up credits",session:"Session"},row:{email:"Email",wechat:"WeChat",subscription:"Plan",credits_balance:"Credit balance"},membership:{free:"FREE",lite:"LITE",pro:"PRO",premium:"PREMIUM"},subscribe_button:{default:"Subscribe / upgrade plan",upgrade_to_premium:"Upgrade to PREMIUM",manage:"Manage subscription"},subscribe_hint:"Manage your subscription and plan on the OpenLoaf website.",recharge_button:"Top up",recharge_hint:"1 CNY = 100 credits. You can top up without subscribing to a plan.",logout_button:"Sign out",logout_busy:"Signing out...",logout_hint:"Signing out clears your local sign-in state. Local recordings, history and dictionary are kept."},Ke={title:"Close to background",description:"OpenSpeech is about to close the main window. The app will keep running in the background.",body_1_prefix:"OpenSpeech will keep running in the ",body_1_highlight:"background",body_1_suffix:". Global hotkeys remain available.",body_2:'Reopen the main window from the tray icon, or choose "Quit" to fully exit.',remember:"Don't ask again",quit:"Quit",stay:"Run in background"},Fe={title:"No internet connection",description:"Your computer is offline. Check your network and try again.",body:"Your computer isn't connected to the internet. Check your network and try again.",still_offline:"Still offline",retry:"Retry"},ze={press_new:"Press a new hotkey...",recording_hint:"ESC to cancel · auto-exit in 4s",clear_title:"Clear",clear_aria:"Clear hotkey",error_prefix:"ERROR",error_illegal_combo:"Illegal combination",conflict_with:'Already used by "{{name}}"',conflict_reason:{equal:'Already used by "{{name}}"',subset_modifier_only:'Modifier set is a subset of "{{name}}" — will cause phantom triggers',subset_combo:'Modifier set is a subset of "{{name}}" — pressing this will double-fire',double_tap_overlap_modifier:'Shares a modifier with "{{name}}" — double-tap window will conflict'},replace:"Replace",rebind:"Re-record",cancel:"Cancel",replaced_toast:`Replaced "{{name}}"'s previous binding`,undo:"Undo"},Be={default_title:"Dictation hotkey / PUSH-TO-TALK",unbound:"Unbound",default_hint:"Tap to start · tap again to stop"},Ue={initializing:"INITIALIZING",tagline:"Speak less, write more.",loading:"Loading"},$s={hotkey_conflict:Ne,auth_recovery:Me,login:je,account:De,close_to_bg:Ke,no_internet:Fe,hotkey_field:ze,hotkey_preview:Be,loading_screen:Ue},Es=Object.freeze(Object.defineProperty({__proto__:null,account:De,auth_recovery:Me,close_to_bg:Ke,default:$s,hotkey_conflict:Ne,hotkey_field:ze,hotkey_preview:Be,loading_screen:Ue,login:je,no_internet:Fe},Symbol.toStringTag,{value:"Module"})),We={title:"Meeting recording in progress",description:"{{action}} is paused — stop the meeting recording first.",action_dictate:"Dictation",action_translate:"Translation",action_ask_ai:"Ask AI"},He={login_timeout:"Login timed out. Please try again.",login_failed:"Login failed. Please try again.",login_connection_reset:"Connection to the login server was reset. Please try again later.",login_unreachable:"Can't reach the login server. Check your network and try again.",internal:"Internal error. Please try again later.",not_authenticated:"Not signed in",not_authenticated_openloaf:"Not signed in to OpenLoaf",not_authenticated_openspeech:"Not signed in to OpenSpeech",session_expired:"Your session has expired. Please sign in again."},Ve={offline:"No internet connection",unreachable:"Network unreachable",service_unreachable:"Can't reach the service",service_unreachable_desc:"Network or server error. This recording was cancelled.",check_and_retry:"Check your network and try again."},qe={start_failed:"Failed to start recording",save_failed:"Failed to save recording",mic_not_ready:"Microphone is not ready",realtime_not_started:"Realtime transcription didn't start",hotkey_sync_failed:"Failed to sync hotkeys to Rust: {{error}}"},Ge={refine:"AI refine",translate:"Translation"},Ye={transcribe_failed:"Transcription failed",transcribe_empty:"No transcript returned",transcribe_empty_desc:"Server timed out or audio was silent.",transcribe_placeholder:"(no transcript)",session_timeout:"Session timed out",saas_5xx:"SaaS server error (5xx)",saas_4xx:"SaaS authentication failed (4xx)",unknown:"Unknown error"},Je={copy_failed:"Failed to copy to clipboard",paste_failed:"Failed to auto-paste"},Qe={check_failed:"Failed to check for updates",available:"New version {{version}} available"},Xe={action:"Report error",sending:"Reporting…",sent:"Reported",toast_success:"Error reported. Thanks for the feedback!",toast_failed:"Report failed: {{message}}",toast_auth_lost:"Session expired. Please sign in again before reporting.",toast_network:"Network error. Couldn't send the report, please try again later.",toast_timeout:"Request timed out. Check your network and try again."},Ze={go_to_settings:"Open settings",meeting_provider_unsupported:"Channel doesn't support meeting transcription",meeting_provider_unsupported_hint:"Open Settings → Dictation and switch to SaaS or Custom → Tencent.",meeting_provider_not_configured:"Dictation channel not configured",meeting_provider_not_configured_hint:"Open Settings → Dictation and pick SaaS or add a Custom → Tencent provider.",network_exit:"Connection lost",network_exit_hint:"The realtime ASR connection was dropped. Check your network and try again.",idle_timeout:"Disconnected due to silence",idle_timeout_hint:"The provider closed the session after a long silence. Resume to reconnect.",start_failed:"Failed to start meeting",pause_failed:"Failed to pause",resume_failed:"Failed to resume",history_save_failed:"Failed to save meeting record",history_open_failed:"Failed to open meeting record",history_delete_failed:"Failed to delete meeting record",unauthenticated_byok:"Custom provider authentication failed",unauthenticated_byok_hint:"Tencent rejected the credentials. Open Settings → Dictation and double-check AppID / SecretId / SecretKey of the active provider.",insufficient_funds:"Provider balance exhausted",insufficient_funds_hint:"Top up the Tencent ASR account or switch to another provider.",engine_not_authorized:"Tencent account hasn't enabled engine 16k_zh_en_speaker",engine_not_authorized_hint:'"Realtime Speaker Diarization" is a separate Tencent SKU — the "Realtime ASR Large Model" pack does NOT cover it. Enable this engine via the Tencent Cloud ASR console (or open a support ticket):',open_tencent_console:"Open",unauthenticated_saas:"SaaS session expired",unauthenticated_saas_hint:"Please sign in to OpenSpeech again before starting the meeting.",insufficient_funds_saas:"SaaS credits exhausted",insufficient_funds_saas_hint:"Top up your account in the user portal or switch to Custom → Tencent.",not_authenticated:"Not signed in",not_authenticated_hint:"The SaaS channel requires sign-in. Sign in to OpenSpeech first, or switch to Custom → Tencent."},Ps={hotkey_blocked:We,auth:He,network:Ve,recording:qe,phase:Ge,stt:Ye,clipboard:Je,update:Qe,report:Xe,meetings:Ze},Ns=Object.freeze(Object.defineProperty({__proto__:null,auth:He,clipboard:Je,default:Ps,hotkey_blocked:We,meetings:Ze,network:Ve,phase:Ge,recording:qe,report:Xe,stt:Ye,update:Qe},Symbol.toStringTag,{value:"Module"})),et="Feedback",tt="Send feedback",it="Tell us what's working, what's broken, or what you wish OpenSpeech could do.",nt="Type",ot={bug:"Bug",feature:"Feature request",ui:"UI / interaction",performance:"Performance",chat:"AI chat",other:"Other"},at="Details",st="Describe what happened, the steps to reproduce, or the feature you'd like…",rt="Contact email (optional)",lt="you@example.com",ct="Leave an email so we can follow up. Otherwise it's submitted anonymously.",dt="Include recent app logs",_t="Sends the most recent app logs along with your report to help us debug. Enabled by default for bug reports.",ut="Couldn't read the log file. Submitting without logs.",pt="Submit feedback",ht="Submitting…",ft="Cancel",gt={content_required:"Please write a sentence about what you'd like to share",email_invalid:"That email doesn't look right"},mt={success:"Feedback received — thank you!",auth_lost:"Your session expired. Please sign in again before submitting.",network:"Network error. Please try again later.",timeout:"Request timed out. Check your connection and retry.",generic:"Submission failed: {{message}}"},Ms={menu_label:et,dialog_title:tt,dialog_description:it,type_label:nt,type:ot,content_label:at,content_placeholder:st,email_label:rt,email_placeholder:lt,email_hint:ct,attach_logs_label:dt,attach_logs_hint:_t,attach_logs_failed:ut,submit:pt,submit_loading:ht,cancel:ft,validation:gt,toast:mt},js=Object.freeze(Object.defineProperty({__proto__:null,attach_logs_failed:ut,attach_logs_hint:_t,attach_logs_label:dt,cancel:ft,content_label:at,content_placeholder:st,default:Ms,dialog_description:it,dialog_title:tt,email_hint:ct,email_label:rt,email_placeholder:lt,menu_label:et,submit:pt,submit_loading:ht,toast:mt,type:ot,type_label:nt,validation:gt},Symbol.toStringTag,{value:"Module"})),yt={dictate_ptt:"Dictation",translate:"Translate dictation",show_main_window:"Open main window",open_toolbox:"Open AI Tools",edit_last_record:"Polish last result"},bt={dictate_ptt:"Press to record, release to transcribe and inject at the cursor",translate:"Press to record, release to translate and inject at the cursor",show_main_window:"Bring the OpenSpeech main window forward from any app",open_toolbox:"Jump straight to the AI Tools page from any app",edit_last_record:"Open the quick panel to polish the latest dictation result without disturbing the main window"},vt={unbound:"Unbound",double_tap:"2× {{mod}}",left:"Left",right:"Right"},St={needs_main_key:"Needs to be combined with a main key",special_keys_locked:"Esc / Enter / arrow keys require enabling them in advanced settings",typing_key_needs_modifier:"Letters / digits / Space / punctuation would intercept normal typing — pair them with a modifier",fn_macos_only:"Fn is only reliable on macOS — use Alt + Win or Right Alt instead",modifier_only_no_main:"Modifier-only bindings can't include a main key",modifier_only_min:"At least one modifier key is required",combo_disallowed_main:"Tab / Backspace / Delete / CapsLock / NumLock / ScrollLock can't be used as a main key — too easy to misfire",combo_no_fn:"Fn can't be combined with a main key — the OS won't register it",double_tap_no_main:"Double-tap bindings can't include a main key",double_tap_single_mod:"Double-tap only supports a single modifier key",double_tap_fn_macos:"On macOS, double-tap Fn is the default system Dictation shortcut and will be intercepted"},kt={system_shortcut:"This combo may conflict with a common system shortcut",f_key_bare:"F1-F12 are wired to brightness / volume by default on most Macs",modifier_only_single_macos:"A single modifier swallows every native chord using it (⌘+Space, ⌥+Arrow, ⌃+Space, …)",modifier_only_single_windows:"A single modifier swallows every native chord using it (Alt+Tab, Win+E, Ctrl+C, …)",modifier_only_single_linux:"A single modifier swallows every native chord using it (Alt+Tab, Super+Space, Ctrl+C, …)"},Ds={binding:yt,binding_hint:bt,format:vt,validation:St,warning:kt},Ks=Object.freeze(Object.defineProperty({__proto__:null,binding:yt,binding_hint:bt,default:Ds,format:vt,validation:St,warning:kt},Symbol.toStringTag,{value:"Module"})),wt={subtitle:"// first run setup"},xt={tag:"// welcome to",headline_part1:"Speak it.",headline_part2:"Type it.",subhead:"Press the hotkey to start talking, press it again to stop — text appears instantly in whatever app you are using."},Ot={section_tag:"// step 01 / permissions · {{platform}}",title_macos:"Grant microphone and accessibility access",title_windows:"Grant microphone access",title_linux:"Pick a microphone and an injection tool",recheck_all:"Recheck",recheck_all_title:"Recheck all permissions",recheck_one_title:"Recheck",summary_macos:"macOS needs three permissions: Microphone (recording), Accessibility (writing transcribed text into the focused app), and Input Monitoring (listening for global hotkeys). Permission caches are bound to the running process — if you ticked the toggle in System Settings but it still shows as not granted, click Restart OpenSpeech in the top right so the new grants take effect.",summary_windows:"Windows needs Microphone access for recording. If your target app runs as Administrator, OpenSpeech must run with the same privileges to inject text into it.",summary_linux:"Linux has no permission prompt: pick a PipeWire / PulseAudio input device, and make sure ydotool / wtype (Wayland) or xdotool (X11) is installed.",badge_required:"Required",badge_recommended:"Recommended",status_checking:"Checking",status_granted:"Granted",primary_acknowledged:"Got it",primary_open_settings:"Open System Settings",primary_request:"Request access",primary_grant:"Grant",tcc_hint:"Toggle on but still says not granted? Remove OpenSpeech from this permission list in System Settings, add it back, then click Restart OpenSpeech.",footer_next:"Next",footer_relaunch:"Restart OpenSpeech",footer_hint_ok:"2 steps left: sign in → try it",footer_hint_relaunch:"Restart after granting · the next step opens automatically",mic:{title:"Microphone",title_linux:"Microphone device",rationale:"Records your voice and sends it to the recognition engine.",rationale_linux:"Linux has no permission prompt; just pick a PipeWire / PulseAudio input device.",hint_macos:"Grant in: System Settings → Privacy & Security → Microphone",hint_windows:"Grant in: Windows Settings → Privacy → Microphone"},accessibility:{title:"Accessibility",rationale:"Simulates keyboard input to write recognized text into the focused field.",hint_macos:"Grant in: System Settings → Privacy & Security → Accessibility"},input_monitoring:{title:"Input Monitoring",rationale:"Listens for global hotkeys (e.g. Fn / Alt+Win) to start recording while you are using other apps.",hint_macos:"Grant in: System Settings → Privacy & Security → Input Monitoring"},inject_tools:{title_windows:"Target app privilege note",rationale_windows:"If the app you write into runs as Administrator (e.g. cmd), OpenSpeech needs the same privileges to inject text.",title_linux:"Detect injection tools",rationale_linux:"Wayland needs ydotool / wtype, X11 needs xdotool. OpenSpeech detects this automatically."}},Tt={section_tag:"// step 02 / account",title:"Sign in to OpenLoaf",subtitle_openloaf:"OpenSpeech is part of the OpenLoaf product family — one OpenLoaf account works across every product, with shared credits.",bonus_main:"200 credits granted to new accounts",bonus_minutes_prefix:"· about",bonus_minutes_value:"30 minutes",bonus_minutes_suffix:"of speech",method_wechat_label:"Sign in with WeChat",method_wechat_sub:"Scan a QR code to sign in",method_google_label:"Sign in with Google",method_google_sub:"Continue in your browser",status_success:"Signed in. Continuing…",status_opening:"Opening your browser…",status_polling:"Waiting for you to finish in the browser…",cancel:"Cancel",advanced_collapse:"↑ Hide",advanced_expand:"↓ I have my own STT endpoint",advanced_desc:"Configure a custom REST STT endpoint (OpenAI / Groq / Deepgram / self-hosted). Recommended for developers only — most users should sign in above.",advanced_cta:"Skip sign-in and configure a custom endpoint",error_default:"Sign-in failed. Please try again.",error_reset:"Connection to the sign-in server was reset. Please try again.",error_timeout:"Sign-in timed out. Please try again.",error_network:"Cannot reach the sign-in server. Check your network and try again."},At={section_tag:"// step 03 / try it",title:"Try it once.",subhead:"Press the hotkey below · say a sentence · press it again to stop",checklist_tag:"// CHECKLIST",checklist:{step1:"Press the dictation hotkey to start",step2:"Say something into the microphone",step3:"Press the hotkey again to stop",step4:"Watch the text appear below"},mock_slices:["Today","Today the","Today the weather","Today the weather is","Today the weather is great","Today the weather is great, so","Today the weather is great, so I opened OpenSpeech","Today the weather is great, so I opened OpenSpeech to try it out."],hotkey_title:"Your dictation hotkey",hotkey_hint:"Press to start · press again to stop",samples_label:"AUDIO · {{count}} SAMPLES",live_transcript_tag:"// LIVE TRANSCRIPT",transcript_chars:"{{count}} CHARS",transcript_placeholder:"Live transcript will appear here…",completed_title:"Setup complete — you are ready to go",completed_desc:"In real use, text is written into whichever app has focus.",reset:"Reset",mock_running:"Demoing…",mock_run:"▶ Run a demo",finish:"Finish setup",skip_finish:"Skip and finish",status:{ready_tag:"// READY",ready_primary:"Start speaking…",ready_secondary:"Esc to cancel",listening_tag:"// LISTENING",listening_primary:"Press the hotkey again to stop and transcribe",listening_secondary:"Esc to cancel this recording",transcribing_tag:"// TRANSCRIBING",transcribing_primary:"Transcribing…",transcribing_secondary:"Esc to discard this result",injecting_tag:"// INJECTING",injecting_primary:"Writing into the input…",error_tag:"// ERROR",error_primary:"Something went wrong — check the log or retry",idle_tag:"// IDLE"}},Fs={header:wt,welcome:xt,permissions:Ot,login:Tt,try_it:At},zs=Object.freeze(Object.defineProperty({__proto__:null,default:Fs,header:wt,login:Tt,permissions:Ot,try_it:At,welcome:xt},Symbol.toStringTag,{value:"Module"})),Rt={cancel:"Cancel",confirm:"Confirm",close_result:"Close result"},Ct={target:"Translate target: {{lang}}",mode_label:"Translate mode",lang:{en:"English",zh:"Chinese","zh-TW":"Traditional Chinese",ja:"Japanese",ko:"Korean",fr:"French",de:"German",es:"Spanish"}},It={to_translate:"Switched to translate mode",to_dictation:"Switched to dictation mode",tap_again_to_output:"Press {{hotkey}} again to output"},Lt={error_fallback:"Error",transcribing:"Thinking…",injecting:"Inserting…",translating:"Translating…"},$t={tag:{ready:"// READY",listening:"// LISTENING",transcribing:"// TRANSCRIBING",injecting:"// INJECTING",error:"// ERROR",idle:"// IDLE",processing:"// PROCESSING"},primary:{ready:"Start speaking…",listening:"Press the hotkey again to stop and transcribe",transcribing:"Transcribing…",injecting:"Inserting into input…",error:"Something went wrong — check logs or retry",result:"Inserted into input · press the hotkey to dictate again"},secondary:{ready:"Esc to cancel",listening:"Esc to cancel this recording",transcribing:"Esc to discard this result",result:"Or click ✕ to dismiss"},placeholder:"Live transcript will appear here…",utterance_timer_label:"UTTERANCE",result_label:{original:"Original",translation:"Translation",polished:"Polished"},result_stats:{recording:"Recording",response:"Response"},dictate_status:{ai_on:"AI refine on",ai_off:"AI refine off"},mode_action:{dictate:"Dictate",translate:"Translate"},mode_segment:{utterance:"Utterance",realtime:"Realtime"},action:{stop:"Stop & transcribe",stop_translate:"Stop & translate",cancel:"Cancel recording",retry_hint:"Press the hotkey to retry",kbd_esc:"Esc",copy:"Copy",copied:"Copied",edit:"Edit",refine:"Polish",refining:"Polishing…",translate:"Translate",translating:"Translating…"},coming_soon:"Coming soon",coming_soon_tag:"// SOON",refine_scenario:{menu_aria:"Pick refine scenarios",helper:"Pick scenarios for sharper polish",count:"{{count}} scenarios",limit_hint:"Up to 3"},translate_lang:{menu_aria:"Pick translation target language"},meter:{live:"LIVE",chars:"{{count}} CHARS",samples:"AUDIO · {{count}} SAMPLES"}},Et={stt_start_failed:{title:"Live transcription didn't start",description:"{{reason}} · recording locally only"},recording_start_failed:{title:"Failed to start recording"},transcribe_failed:{title:"Transcription failed",no_transcript:"Nothing was recognized — retry from History"},byok_switch_to_saas:{action:"Use cloud",switched_title:"Switched to OpenLoaf cloud",switched_description:"Press the hotkey to record again"},recording_save_failed:{title:"Failed to save recording"},clipboard_failed:{title:"Failed to copy to clipboard"},paste_failed:{title:"Auto-paste failed",description:"Text is on the clipboard — press Cmd/Ctrl+V manually"},not_logged_in:{title:"Not signed in to OpenSpeech",description:"Sign in to use voice input",action:"Sign in"},dictation_fallback:{title:"Switched to OpenLoaf SaaS",description:"Custom provider isn't configured — this run used the cloud service"},ai_refine_auto_fallback:{title:"AI refine switched to OpenLoaf SaaS",description:"Custom AI provider isn't fully configured — switched to the cloud service"},ai_refine_custom_failed:{title:"AI refine failed (custom provider)",description_missing_key:"ApiKey for the custom provider is missing — tap the button to fall back to the cloud service",description_runtime:`Custom provider unreachable: {{error}}
|
|
2
|
-
Tap the button to fall back to the cloud service`,action:"Use SaaS"},asr_error:{title:"Transcription error",unknown:"Unknown error"},worker_dead:{title:"Voice channel disconnected",description:"This recording has been stopped — please try again",error_message:"Voice channel disconnected; recording stopped"},insufficient_credits:{title:"Insufficient credits",description:"This transcription was cancelled — top up in your account",error_message:"Insufficient credits — transcription cancelled"},session_timeout:{title:"Session timed out",description:"Reached the 2-hour server limit"},preflight_failed:{title:"Can't start recording"},aborted_saved:{title:"Cancelled, not transcribed",description:"Recording saved to history"},silent_recording:{title:"No speech detected"},realtime_degraded:{title:"Realtime ASR glitch",description:"Re-transcribing from the recording…",realtime_mode:"First half kept; retry the full take from history"}},Pt={placeholder:"(Transcript unavailable)",aborted_placeholder:"(Cancelled, not transcribed)"},Nt={title:"Couldn't auto-insert",copy:"Copy",copied:"Copied"},Mt={stt_not_authenticated:"Not signed in to OpenLoaf",stt_5xx:"SaaS server error (5xx)",stt_4xx:"SaaS auth failed (4xx)",stt_mic_not_ready:"Microphone not ready",stt_network:"Network unreachable",sync_hotkey_failed:"Failed to sync hotkeys to Rust: {{error}}",preflight_permission_denied:"Microphone permission not granted",preflight_no_device:"No microphone available",byok_not_implemented:"Custom BYOK channel under development; ships in the next release",byok_missing_credentials:"Custom provider credentials missing — set them in Settings → Dictation → Custom providers",byok_keyring_error:"Failed to read custom provider credentials from the system keychain",file_too_large_for_tencent_byok:"Recording exceeds the Tencent BYOK file transcription limit (~5 minutes). Switch to REALTIME mode or shorten the recording.",tencent_task_failed:"Tencent task failed: {{msg}}",tencent_task_timeout:"Tencent task timed out (no result after 24 minutes)",transcribe_timeout:"Transcription timed out — the server didn't respond, so we stopped waiting.",tencent_unauthenticated:"Tencent BYOK auth failed — check the SecretId / SecretKey in Settings",tencent_rate_limited:"Tencent BYOK rate-limited — wait a moment and retry",tencent_cos_unauthenticated:"Tencent COS auth failed — check SecretId / SecretKey and bucket permissions",tencent_cos_forbidden:"Tencent COS rejected the upload — verify bucket name, region and access policy",tencent_cos_network:"Tencent COS network error — check your connection and try again",tencent_cos_unknown:"Tencent COS upload failed (unknown error)",unauthenticated_byok:"Custom credentials rejected — check the SecretId / SecretKey",insufficient_funds:"Tencent Cloud account is out of credits or service is not enabled",idle_timeout:"Disconnected after a long silence with no audio",rate_limited:"Provider rate-limited the request — wait a moment and retry",aliyun_invalid_audio_format:"Audio format not supported by Aliyun DashScope — check the sample rate / bit depth",aliyun_quota_exceeded:"Aliyun DashScope quota exhausted",aliyun_unauthenticated:"Aliyun DashScope auth failed — check the ApiKey in Settings",aliyun_rate_limited:"Aliyun DashScope rate-limited — wait a moment and retry",aliyun_upload_failed:"Aliyun DashScope OSS upload failed: {{msg}}",aliyun_filetrans_failed:"Aliyun DashScope task failed: {{msg}}",aliyun_filetrans_timeout:"Aliyun DashScope task timed out (no result after 24 minutes)",aliyun_file_too_large:"Recording exceeds the Aliyun DashScope BYOK single-file limit (default 100 MB)"},jt={aria:{dismiss:"Don't show this hint again"},recordingControls:{text:"Release to finish · ESC to cancel"},resultActions:{text:"⌘C copy · Edit · Polish · Translate"},firstResultConfirm:{text:"Inserted · Revise",action_correct:"OK",action_revise:"Revise"}},Bs={aria:Rt,translate:Ct,mode_switch:It,status:Lt,panel:$t,toast:Et,transcript:Pt,result:Nt,error:Mt,hints:jt},Us=Object.freeze(Object.defineProperty({__proto__:null,aria:Rt,default:Bs,error:Mt,hints:jt,mode_switch:It,panel:$t,result:Nt,status:Lt,toast:Et,transcript:Pt,translate:Ct},Symbol.toStringTag,{value:"Module"})),Dt={too_long_for_utterance:"Recording exceeds 5 minutes — UTTERANCE mode is not supported, switch to REALTIME",aliyun_oss_upload_failed:"Aliyun OSS upload failed — credentials may be expired or the network is unstable",aliyun_filetrans_failed:"Aliyun file transcription task failed — please retry later",aliyun_file_too_large:"File exceeds 100 MB — Aliyun OSS single-file limit reached",tencent_cos_upload_failed:"Tencent COS upload failed — check credentials and network",tencent_cos_bucket_required:"Tencent COS bucket is required for transcription. Open Settings → Dictation and fill it in."},Kt={hero:{title_line1:"Just speak.",title_line2:"It becomes text.",description:"Press the hotkey, talk, press again to finish — your words appear in any app, instantly. No editor lock-in, audio stays on-device, zero telemetry.",feature_push_to_talk:"// PUSH-TO-TALK DICTATION",feature_cross_platform:"// CROSS-PLATFORM WIN · MAC · LINUX"},hotkey_hint:"Press the hotkey to start recording, press again to stop and inject the text into the focused field. Press <esc>Esc</esc> to cancel; an editable field must be focused.",translate_hint:"Press the translate hotkey to start recording, press again to stop. The system transcribes then translates to the target language before injecting into the focused field.",translate_bilingual:"Bilingual output",translate_bilingual_aria:"Bilingual output (source + translation)",edit_hotkey:"Edit hotkey",edit_hotkey_dialog_title:"Edit hotkey",edit_hotkey_dialog_description:"Record or change the current hotkey binding.",quick_dict:{button_aria:"Add a word",title:"My dictionary",empty:"// No entries yet //",domains_label:"// Common domains"},hotkey_tab:{dictate:"Dictate",translate:"Translate"},hotkey_title:{dictate:"Dictation / PUSH-TO-TALK",translate:"Translate / TRANSLATE"},stats:{section_title:"Today / This session",section_title_today:"Today's session stats",section_title_all:"All-time session stats",tab_today:"Today",tab_all:"All time",live_metrics:"// LIVE METRICS",duration_label:"Spoken time",duration_unit:"HH:MM",words_label:"Spoken words",words_unit:"Total",wpm_label:"Average speed",wpm_unit:"WPM",saved_label:"Time saved",saved_unit:"HH:MM",open_dialog_aria:"Open detailed stats for {{label}}"},stats_dialog:{title:"Statistics",subtitle:"Dictation · ask · translate · stays on device",close:"Close",range:{today:"Today","7d":"7d","30d":"30d","90d":"90d",all:"All"},metric_switcher_label:"Focus",kpi:{duration:"Time",words:"Words",wpm:"WPM",saved:"Saved",sessions:"Sessions"},main:{duration:{title:"Time trend",hint:"Total recording time per day (HH:MM)"},words:{title:"Words cumulative",hint:"Total words produced over time"},wpm:{title:"WPM trend",hint:"Average speaking speed per day"},saved:{title:"Time saved cumulative",hint:"Saved versus a {{baseline}} WPM typing baseline"},sessions:{title:"Sessions trend",hint:"Daily dictation session count"}},facet:{heatmap:{title:"When you dictate",hint:"Mon–Sun × 0–23h; darker means more usage",weekdays:"M,T,W,T,F,S,S"},top_apps:{title:"Top target apps",hint:"Where you write the most",unknown:"Unknown app"},wpm_by_mode:{title:"WPM × segment mode",hint:"REALTIME vs UTTERANCE side by side"},saved_equivalent:{title:"Worth translation",hint:"What that saved time looks like in everyday units",items:{typing_hours:"≈ {{value}} of typing",podcasts:"≈ {{value}} podcast episodes",coffees:"≈ {{value}} cups of coffee",books_pages:"≈ {{value}} pages of reading"}},session_dist:{title:"Session length distribution",hint:"Short / medium / long mix",buckets:{short:"Short ≤ 20 words",medium:"Medium 21–100 words",long:"Long > 100 words"}},duration_dist:{title:"Session length distribution",hint:"How long each recording lasts — short bursts vs long takes",buckets:{lt10s:"< 10s",s10_30:"10–30s",s30_60:"30–60s",s60_120:"1–2 min",gt120s:"> 2 min"}},type_mix:{title:"Usage mix",hint:"Dictation vs ask vs translate",buckets:{dictation:"Dictation",ask:"Ask",translate:"Translate"}},provider_dist:{title:"Provider mix",hint:"Sessions and average speed by ASR channel",unknown:"Unknown"},ai_refine_rate:{title:"AI refine usage",hint:"How often AI cleanup ran, and how long it took on average",used_label:"Used",avg_label:"Avg latency"},status_mix:{title:"Status mix",hint:"Success / failed / cancelled ratio",buckets:{success:"Success",failed:"Failed",cancelled:"Cancelled"}},asr_source_dist:{title:"ASR source mix",hint:"Realtime vs file transcription vs custom endpoint",buckets:{"saas-realtime":"Realtime","saas-rest":"File",byo:"Custom",unknown:"Unknown"}}},empty:"// No dictation records yet — give it a try //"}},Ft={title:"History",subtitle:"History stays on this device.",search_placeholder:"Search history...",more:"More",stats:"Stats",refresh:"Refresh",retention:{label:"Keep history",title:"How long history is kept on this device",options:{forever:"Forever","90d":"90 days","30d":"30 days","7d":"7 days",off:"Don't save"}},open_folder:"Open recordings folder",open_folder_failed:"Failed to open recordings folder",delete_all:"Delete all history",filters:{all:"All",dictation:"Dictation",ask:"Ask anything",translate:"Translate"},buckets:{today:"Today",yesterday:"Yesterday",this_week:"This week",earlier:"Earlier"},empty:"// No records //",loading_more:"// loading more //",list_end:"// end · {{count}} total //",status:{success:"Success",failed:"Failed",cancelled:"Cancelled",retrying:"Regenerating"},player:{play:"Play",pause:"Pause"},row:{play:"Play original recording",pause:"Pause",copy:"Copy to clipboard",copied:"Copied",reinject:"Re-inject",export:"Export audio",delete:"Delete",retry:"Regenerate",transcribe:"Transcribe",retrying_label:"Regenerating",retrying_placeholder:"Regenerating transcript…",retry_no_audio:"No audio available — can't regenerate",retry_too_long:"Regeneration isn't supported for recordings over 5 minutes",retry_in_progress:"Regenerating…",retry_tooltip:"Regenerate transcript",failed_placeholder:"Your transcription was interrupted. You can regenerate it.",cancelled_placeholder:"{{duration}} recording cancelled · not transcribed · retry available",view_refined:"AI enhanced",view_translation:"Translation",view_raw:"Raw text",view_details:"View details",copy_debug:"Copy debug info"},detail:{title:"Record details",description:"View full content of the history record and run actions",meta:{duration:"Duration",target:"Target app",error:"Error",warn:"Note",asr:"Speech-to-text",ai:"AI refine",segment_mode:"Mode",provider_kind:"Channel"},asr:{"saas-realtime":"OpenLoaf SaaS · realtime","saas-rest":"OpenLoaf SaaS · REST",byo:"Custom STT endpoint"},ai:{none:"Off"},segment_mode:{REALTIME:"Realtime",UTTERANCE:"Utterance"},provider_kind:{"saas-realtime":"OpenLoaf · realtime","saas-file":"OpenLoaf · file","tencent-realtime":"Tencent · realtime","tencent-file":"Tencent · file","aliyun-realtime":"Aliyun · realtime","aliyun-file":"Aliyun · file"},unknown:"—",empty_text:"(no text content)"},toast:{copy_success:"Copied to clipboard",copy_failed:"Copy failed",copy_debug_success:"Debug info copied",copy_debug_failed:"Failed to copy debug info",copy_debug_missing:"No request snapshot captured for this record (likely a release-build entry or a pre-dispatch failure)",retry_success:"Regenerated",retry_failed:"Regeneration failed",delete_failed:"Delete failed",export_success:"Audio exported",export_failed:"Export failed",refresh_failed:"Refresh failed"},edit:{title:"Edit transcript",description:"Edit the final text of this history record",edit_button:"Edit",edit_tooltip:"Fix misrecognized words so the next session is more accurate",original_label:"Original (AI's final version)",diff_label:"Diff (red = removed, green = added)",edited_label:"Your edit",hint:"Save when done; learning happens in the background",placeholder:"Edit the text here…",save:"Save",revert:"Revert edit",revert_tooltip:"Discard your edit on this record and restore the AI's version",edited_chip:"Edited",edited_tooltip:"You've edited the text of this record",toast:{save_success:"Edit saved",save_failed:"Save failed",revert_success:"Restored original",dict_added:"Added to dictionary: {{term}}",dict_updated:"Dictionary updated: {{term}}",dict_removed:"Removed from dictionary: {{term}}",dict_hint:"AI learned from your edit"}},confirm_clear:{title:"Delete all history",description:"Clear local history records",body:"This will delete <count>{{count}}</count> records on this device. The action can't be undone.",tip:"// Consider exporting a backup first",confirm:"Confirm delete"}},zt={title:"Dictionary",subtitle:"Custom vocabulary · up to 2,000 entries",new_word:"+ New word",search_placeholder:"Search entries...",filters:{all:"All",domains:"Domains",manual:"Manually added"},empty:"// No entries //",count_total:"// {{count}} total //",divider_label:"Custom entries",card:{domain_tooltip:"Selected domain",manual_tooltip:"Manually added",edit:"Edit",delete:"Delete"},domains:{helper:"Pick the topics you often dictate — the AI will lean on their terminology and tone.",limit_hint:"Up to {{limit}}",counter:"{{count}} / {{limit}} selected",items:{programming:"Programming",ai_ml:"AI / ML",medicine:"Medicine",law:"Law",finance:"Finance",academic:"Academic",engineering:"Engineering",marketing:"Marketing",psychology:"Psychology",design:"Design",film_production:"Film & Video",cybersecurity:"Cybersecurity",photography:"Photography",tcm:"TCM",automotive:"Automotive"}},new_dialog:{title:"New word",description:"Add a custom dictionary entry",term_label:"term",term_placeholder:"e.g. OpenSpeech",error_empty:"Term can't be empty",error_duplicate:"This entry already exists",submitting:"Adding…",submit:"Add"}},Bt={nav:{home:"Home",toolbox:"Translate & Polish",meetings:"Meetings",history:"History",dictionary:"Dictionary"},account_fallback:"ACCOUNT",login:"LOGIN",credits:"Credits",time_left:"LEFT",time_minutes:"{{minutes}} MIN",settings:"Settings",tray:{update_found_title:"Update available",update_none:"You're on the latest version",update_check_failed:"Update check failed"}},Ut={placeholder:"Search...",clear:"Clear search",open:"Search"},Wt={title:"Translate & Polish",subtitle:"Speak or type. Polish, translate, or read it aloud.",flow_hint:"Provide input above · pick a tool below · get the processed result inline",input:{section_label:"// 01 · INPUT",tabs:{text:"Text",voice:"Voice",history:"History",file:"Audio file"},text_placeholder:"Type or paste text here…",dictate_hint:"Press the hotkey · talk to dictate",dictate_unbound:"Dictation hotkey not bound",voice_hint:"Hold the button and speak — release to transcribe.",voice_button_idle:"Hold to talk",voice_button_recording:"Listening…",voice_recorded:"Recorded · 0:08",history_hint:"Pick a previous transcription.",history_empty:"No history yet.",file_hint:"Drop an audio file (mp3 / wav / m4a) or click to choose.",file_button:"Choose audio file",file_loaded:"demo.mp3 · 12s · 1.2 MB",char_count:"{{count}} chars",right_label:"Text",right_hint_voice:"Transcribed from voice",right_hint_history:"From history",right_hint_file:"Transcribed from audio",right_empty:"Provide an input on the left first.",use_sample:"Use sample text",replaced_hint:"Replaced with previous step's output",restore_original:"Restore original",paste:"Paste",history:"History",clear:"Clear",clipboard_detected:"Clipboard content detected",clipboard_translate:"Paste & translate",clipboard_fill_only:"Paste only"},tools:{section_label:"// 02 · TOOLS",tabs:{polish:"Polish",translate:"Translate",tts:"Read aloud"},tutorial:{polish:{title:"Polish",headline:"Rewrite spoken drafts to match a scenario — email, message, report, you name it."},translate:{title:"Translate",headline:"Convert your text to another language while keeping its tone."},tts:{title:"Read aloud",headline:"Generate natural-sounding audio from any text."}},polish:{scenario_label:"Scenario",scenarios_empty:"No scenarios configured",add_scenario:"+ Add",examples:{email:"Email",wechat:"Message",report:"Report",meeting_notes:"Meeting notes",social_post:"Social post"}},translate:{target_label:"To",languages:{en:"English",zh:"中文","zh-TW":"繁體",ja:"日本語",ko:"한국어",fr:"Français",de:"Deutsch",es:"Español"}},tts:{voice_label:"Voice",speed_label:"Speed",voices:{natural_f:"Natural · F",natural_m:"Natural · M",calm_f:"Calm · F"},audio_placeholder:"▶ ━━━━━━━━━━━━━━━━━━━━ 0:08 / 0:12"},run:"Run",run_hint:"Configure the params above, then run.",ready_to_run:"Ready · click Run",running:"Running…",error_title:"Run failed",error:"Failed · {{message}}",rerun:"Rerun",copy:"Copy",save_history:"Save",use_as_input:"Use as input",download:"Download",elapsed:"{{seconds}}s",idle:"Awaiting input",output_empty:"Provide an input above to see the result here."},output:{idle_label:"Awaiting run",ready:"READY",waiting_input:"WAITING FOR INPUT…",generating:"GENERATING…",meta_chars:"{{count}} chars",meta_elapsed:"{{seconds}}s"},footer:{ui_only_notice:"// UI PREVIEW — actions are not wired up yet"}},Ht={title:"Meetings",subtitle:"Long-form recording · Speaker labels · Timeline review",idle:{hint:"Click to start recording",recent:"Recent meetings",items:"items",empty:"No meetings yet",empty_transcript:"(empty)",loading:"Loading…",starting:"Connecting to provider…",language_support:"// Currently supports Chinese, English, Cantonese & several Mandarin dialects"},live:{recording:"Recording",paused:"Paused",pause:"Pause",resume:"Resume",stop:"Stop",listening:"Listening...",reconnecting:"Network hiccup, reconnecting… ({{attempt}}/{{max}})",reconnect_gave_up:"Reconnect failed, meeting disconnected"},speaker:{label:"Speaker {{letter}}",pending:"Speaker …"},review:{back:"Back",speakers:"speakers",delete:"Delete",delete_confirm:"Delete this meeting record?",summary:"Summary",transcript:"Transcript",summary_topic:"Topic",summary_speakers:"Speakers",summary_abstract:"Abstract",summary_section:"Key points",summary_loading:"Loading summary…",summary_generate:"Generate",summary_regenerate:"Regenerate",summary_failed:"Summary failed",summary_idle_hint:'Click "Generate" above to draft a Markdown summary using the active AI channel (Settings → AI → Prompts → Meeting summary to tweak the default prompt).',summary_empty_transcript:"This meeting has no transcript to summarize.",export:"Export",export_default_name:"meeting-{{date}}-{{shortId}}",export_md_filter:"Markdown",export_doc_title:"Meeting Transcript",export_meta_created:"Created",export_meta_duration:"Duration",export_meta_speakers:"Speakers",export_meta_segments:"Segments",export_success:"Exported to {{path}}",export_failed:"Export failed"}},Ws={transcribe:Dt,home:Kt,history:Ft,dictionary:zt,layout:Bt,search_box:Ut,toolbox:Wt,meetings:Ht},Hs=Object.freeze(Object.defineProperty({__proto__:null,default:Ws,dictionary:zt,history:Ft,home:Kt,layout:Bt,meetings:Ht,search_box:Ut,toolbox:Wt,transcribe:Dt},Symbol.toStringTag,{value:"Module"})),Vt={title:"Polish",empty:"No recent result to polish yet",cancel:"Cancel",save:"Polish & copy",saving:"Polishing…",learn_hint:"AI learns from this edit — future dictation gets sharper",close_aria:"Close"},qt={saved_title:"Polish saved",saved_description:"The new text is on your clipboard — paste it back into the original input",save_failed_title:"Save failed"},Vs={edit_last_record:Vt,toast:qt},qs=Object.freeze(Object.defineProperty({__proto__:null,default:Vs,edit_last_record:Vt,toast:qt},Symbol.toStringTag,{value:"Module"})),Gt={section_index:"[04] System",title:"Settings",subtitle:"Configure dictation, model endpoints and app behavior. Changes apply instantly — no save needed.",dialog_title:"Settings",dialog_sr:"OpenSpeech settings"},Yt={title:"Reverted to OpenLoaf SaaS",description:"Your {{which}} custom provider didn't pass the test — switched to the cloud service",dictation:"dictation",ai:"AI refine",both:"dictation and AI refine",confirm_title:"Custom provider hasn't passed testing",confirm_description:"Your {{which}} custom provider hasn't been validated yet, so it can't be applied. Closing now will revert to the OpenLoaf SaaS cloud service.",confirm_back_to_test:"Back to test",confirm_proceed:"Revert to SaaS and close"},Jt={general:"General",hotkeys:"Hotkeys",dictation:"Dictation",model:"Model",ai:"AI",about:"About",dev_hints:"Hint debug"},Qt={reset_all:"Reset all",reset_all_confirm:"Reset all hotkeys to their defaults?",reset_all_done:"Hotkeys restored to defaults"},Xt={shortcuts:"Keyboard shortcuts",language:"Language",audio:"Audio",asr_segment:"Dictation mode",text_injection:"Text injection",behavior:"Behavior",model_rest:"Large model (REST)",build:"Build",output:"Output"},Zt={interface_lang:"Interface language",translate_target_lang:"Translate target language",translate_target_lang_hint:"When the translate-dictation hotkey fires, the transcript is translated into this language and then injected at the cursor.",translate_output_mode:"Translate output",translate_output_mode_hint:'"Bilingual" keeps the source and appends the translation; "Target only" outputs just the translation, faster.',input_device:"Input device",input_level:"Input level",input_level_hint_listening:"Live level · listening on: {{name}}",input_level_hint:"Live microphone level",cue_sound:"Start / stop cue sound",restore_clipboard:"Restore clipboard after paste",restore_clipboard_hint:"Recommended to keep on",launch_startup:"Launch at login",close_to_tray:"Minimize to tray on close",close_to_tray_hint:"When on, closing the main window hides it to the tray; otherwise a confirm dialog appears each time.",update_policy:"Updates",update_policy_hint:"Choose how OpenSpeech handles new versions discovered in the background.",update_policy_options:{prompt:"Notify me",auto:"Auto-install when idle",disabled:"Off"},loading:"// loading settings…",dictation_output_lang:"Dictation output language",dictation_output_lang_hint:'Which language the dictation transcript is rendered in. "Auto" lets the upstream ASR decide, falling back to the interface language for tie-breaking.',translate_conflict_warning:"Target language matches the dictation output language — translation would be a no-op."},ei={system_default:"System default",system_default_with_current:"System default (currently: {{name}})",is_default_suffix:"{{name}} · system default",disconnected_with_fallback:"{{name}} · disconnected, using system default ({{fallback}})",disconnected:"{{name}} · disconnected"},ti={realtime_label:"Realtime",realtime_hint:"Server splits at pauses and streams partials in real time. Best for long meeting captions, live transcription and other unattended scenarios.",utterance_label:"Whole utterance",utterance_hint:"Treat the whole recording as a single utterance and return the transcript only after you release the key. The model gets full context — more accurate and won't be split by pauses.",ai_refine_toggle:{label:"Enable AI enhancement",hint:'On top of "whole utterance", run an LLM pass to remove fillers, dedupe, and recognise self-corrections. Same language — no translation.',disabled_in_realtime:"Not available in realtime mode"}},ii={streaming_inject:{label:"Stream characters into the input",hint:"On by default — characters land at the cursor as the model produces them. Turn off to paste the whole text in one shot, bypassing per-character interception by IMEs like WeChat or full-pinyin (which can swallow the first character or duplicate punctuation)."},clipboard_copy:{label:"Auto copy to clipboard",hint:"Off by default — OpenSpeech restores your previous clipboard contents after injection, so your copy queue stays clean. Turn on to keep the full text on the clipboard so you can paste it again manually."}},ni={byo_unavailable_tag:"// BYO-MODEL · not yet available",byo_unavailable_body:"Custom STT REST endpoints (endpoint URL / API Key / model name / test connection) aren't wired up yet. All dictation currently goes through OpenLoaf SaaS. This surface is under active development and will be enabled in the next release.",endpoint:"Endpoint URL",api_key:"API Key",api_key_hint:"Stored in the system keychain; saved automatically on blur.",model_name:"Model name",timeout_seconds:"Request timeout (seconds)",audio_format:"Audio format",test_connection_disabled:"Test connection (not yet available)",show_key:"Show API Key",hide_key:"Hide API Key",key_saved_toast:"API Key saved to system keychain",key_save_failed_toast:"Failed to save API Key: {{error}}"},oi={section_mode:"AI channel",mode_saas_label:"Cloud (recommended)",mode_saas_hint:"Use the fast chat model on your signed-in OpenLoaf account; billed by credits.",mode_custom_label:"Custom provider",mode_custom_hint:"OpenAI-compatible endpoints with your own API Key. Multiple providers allowed, but only one active at a time.",section_providers:"Custom providers",providers_empty:"No custom providers yet",provider_name:"Name",provider_base_url:"Base URL",provider_model:"Model",provider_api_key:"API Key",provider_api_key_hint:"Stored in the system keychain; saved automatically on blur.",provider_active:"Active",provider_set_active:"Set active",provider_remove:"Remove",provider_test:"Test",provider_test_running:"Testing…",provider_test_pass:"Test passed",provider_test_fail:"Test failed: {{message}}",provider_test_missing_fields:"Base URL or model is empty",provider_test_empty_reply:"Model returned no content",provider_add:"Add provider",provider_default_name:"New provider",provider_default_base_url:"https://api.openai.com/v1",provider_default_model:"gpt-4o-mini",section_prompts:"System prompt",prompts_hint:"Defaults follow the interface language. Edit to customize; the same custom prompt then applies to all languages.",prompt_tab_refine:"Dictation refine",prompt_tab_translate:"Translate",prompt_tab_polish:"Polish",prompt_tab_meeting:"Meeting summary",prompt_edit:"Edit",prompt_status_custom:"Custom",prompt_status_default:"Default",prompt_desc_refine:"After you release the dictation key, the AI rewrites the raw transcript into clean written text (typos, fillers, sentence breaks) and injects it into the current app.",prompt_desc_translate:"Triggered by the Translate hotkey to translate the transcript into the target language set above.",prompt_desc_polish:'Used by the AI Toolbox "Polish" page; pair it with the scenario list below (email, WeChat, etc.) to switch tone.',prompt_desc_meeting:"After the Meetings page transcribes a recording, this prompt formats it into a structured meeting note.",prompt_dialog_title_refine:"Dictation refine prompt",prompt_dialog_title_translate:"Translation prompt",prompt_dialog_title_meeting:"Meeting summary prompt",prompt_dialog_textarea_label:"System prompt",polish_dialog_title:"Polish settings",polish_dialog_subtitle:"Tune the polish system prompt and manage the scenario list shown in the AI Toolbox.",polish_dialog_tab_prompt:"Prompt",polish_dialog_tab_scenarios:"Scenarios",polish_dialog_prompt_label:"Polish prompt",polish_scenarios_title:"Polish scenarios",polish_scenarios_hint:`Source for the chip list at the bottom of the AI Toolbox "Polish" tab; the selected scenario's instruction is appended to the polish system prompt at runtime.`,polish_scenarios_empty:"No polish scenarios yet",polish_scenario_default_name:"New scenario",polish_scenario_remove:"Remove",polish_scenario_add:"Add scenario",polish_scenario_instruction_placeholder:"e.g. Target scenario: business email. Formal tone. Use greeting / body / sign-off paragraphs.",refine_dialog_tab_prompt:"Prompt",refine_dialog_tab_examples:"Examples",refine_dialog_tab_overrides:"Per-app overrides",refine_examples_builtin_title:"Built-in examples",refine_examples_builtin_hint:"{{count}} preset examples · click to expand · clone any one to edit as your own",refine_example_clone:"Clone",refine_rules_builtin_title:"Built-in rules",refine_rules_builtin_hint:"{{count}} preset core rules · click to expand · clone any one to edit as your own",refine_rules_title:"Custom rules",refine_rules_hint:'Default uses the built-in rules; click "Add rule" or clone a built-in rule to switch to custom mode. In custom mode, only the rules listed here are sent to the model at runtime.',refine_rules_using_default:'Using built-in rules. Click "Add rule" below or "Clone" above to start customizing.',refine_rules_empty:"In custom mode but no rules yet — runtime will send an empty core_rules block.",refine_rules_count:"{{current}} / {{max}}",refine_rule_add:"Add rule",refine_rule_remove:"Remove",refine_rule_clone:"Clone",refine_rule_body_placeholder:"Rule body (separate paragraphs with blank lines)",refine_rule_why_placeholder:"Why — rationale for this rule (optional)",refine_examples_title:"Custom examples",refine_examples_hint:'Pair "messy transcript → polished output" so the model learns your style. At runtime they are appended after the built-in examples, in order — earlier entries take priority.',refine_examples_empty:"No custom examples yet",refine_examples_count:"{{current}} / {{max}}",refine_example_add:"Add example",refine_example_remove:"Remove",refine_example_target_placeholder:"target (e.g. *, chat)",refine_example_focus_placeholder:"focus — what this example illustrates (optional)",refine_example_input_placeholder:"input — raw / messy transcript",refine_example_output_placeholder:"output — desired polished text",app_overrides_title:"Per-app overrides",app_overrides_hint:"Configure rules and examples for a specific app: when a match hits, these rules take precedence and the examples are prepended to the global list. Only apps that have run refine (and thus have a stable appId) appear here.",app_overrides_empty:"No overrides yet",app_overrides_count:"{{current}} / {{max}}",app_override_add:"Add override",app_override_remove:"Remove",app_override_enabled:"Enabled",app_override_expand:"Expand",app_override_collapse:"Collapse",app_override_core_rules_label:"Override core rules (leave empty to use global)",app_override_core_rules_clear:"Clear",app_override_core_rules_placeholder:"App-specific <core_rules>...</core_rules>; empty means inherit the global core rules.",app_override_picker_title:"Pick an app to override",app_override_no_history:"No apps available — run refine in the target app once so it shows up in history.",prompt_reset:"Reset to default",section_history:"Context",include_history:"Send recent dictations as context",include_history_hint:"Recent transcripts help the model carry over tone and terminology.",recent_history_count:"Recent items to send",recent_history_count_hint:"Maximum number of recent dictations to attach. More items bias the model harder, but use more tokens.",minutes_ago:"minutes ago",history_truncated:"+{{count}} more words"},ai={en:"English",zh:"Simplified Chinese (简体中文)","zh-TW":"Traditional Chinese (繁體中文)",ja:"Japanese (日本語)",ko:"Korean (한국어)",fr:"French (Français)",de:"German (Deutsch)",es:"Spanish (Español)"},si={target_only:"Target only",bilingual:"Bilingual (source + translation)"},ri={label:"Dictation language",hint:`Pick the language you'll speak in. "Auto" lets the upstream ASR detect it; ambiguous cases fall back to the interface language.`,follow_interface:"Follow interface",auto:"Auto",zh:"Chinese",en:"English",ja:"Japanese",ko:"Korean",yue:"Cantonese"},li={section_mode:"Dictation channel",mode_saas_label:"OpenLoaf Cloud (default)",mode_saas_hint:"Use the speech recognition managed by your OpenLoaf account, billed via credits. Shared between dictation and meeting transcription.",mode_custom_label:"Custom provider",mode_custom_hint:"Connect directly to Tencent Cloud / Aliyun with your own keys, bypassing the SaaS. Meeting transcription requires Tencent Cloud (built-in speaker diarization).",section_providers:"Custom providers",providers_empty:"No custom providers yet",add_tencent:"Add Tencent Cloud",add_aliyun:"Add Aliyun",vendor_tencent:"Tencent Cloud",vendor_aliyun:"Aliyun DashScope",active_label:"Active · {{vendor}}",set_active:"Set active",remove:"Remove",name_label:"Name",tencent_default_name:"Tencent Cloud ASR",tencent_app_id:"AppID",tencent_region:"Region",tencent_secret_id:"Secret ID",tencent_secret_key:"Secret Key",tencent_credentials_hint:"Stored in the OS keychain; saved automatically on blur. Get them from the Tencent Cloud console → API Keys.",tencent_cos_bucket_label:"COS Bucket",tencent_cos_bucket_placeholder:"myaudio-1234567890",tencent_cos_bucket_hint:"Required: recordings are uploaded to your Tencent COS bucket before transcription (single file ≤512MB). Leaving this blank falls back to base64 inline upload, which the Tencent file API caps at 5MB — anything larger will fail.",aliyun_default_name:"Aliyun DashScope",aliyun_api_key:"ApiKey",aliyun_api_key_hint:"Stored in the OS keychain; saved automatically on blur. Get it from the DashScope console.",test:"Test",test_running:"Testing…",test_pass:"Test passed: credentials are valid",test_fail:"Test failed: {{message}}",test_missing_fields:"Required fields are missing",verified_badge:"Verified",unverified_badge:"Unverified",test_code:{ok:"Test passed",unauthenticated:"Authentication failed: check your Secret/ApiKey",service_not_enabled:"Credentials valid, but the speech service is not yet enabled on this account",missing_fields:"Required fields are missing",network:"Network unreachable; check connectivity and firewalls",timeout:"Request timed out, please retry",rate_limited:"Rate limit hit",cos_unauthorized:"ASR credentials are valid, but this SecretId cannot access the COS bucket",cos_not_found:"ASR credentials are valid, but the COS bucket does not exist or the region does not match",oss_policy_failed:"ApiKey is valid, but fetching the OSS upload policy failed: this account may not have DashScope audio file resources enabled",unknown:"Unknown error"}},ci={version:"Version",platform:"Platform",license:"License",source:"Source code",check_update:"Check for updates",dev_build:"Development build",rerun_onboarding:"Re-run first-launch onboarding",install_now:"Install now",skip_version:"Skip this version",install_in_progress:"Downloading and installing update…",install_progress:"{{version}} · {{percent}}% · {{downloaded}} / {{total}}",install_starting:"{{version}} · {{downloaded}} downloaded",install_finalizing:"Download complete, installing…",install_failed:"Update install failed",update_channel:"Update channel",update_channel_stable:"Stable",update_channel_beta:"Beta (early access)",update_channel_hint:"Beta gets new features sooner but may be unstable. Switching back to Stable only delivers updates whose version is higher than the current beta.",open_log_dir:"Open log directory",saas_sdk_version:"SaaS SDK version"},di={title:"Interaction hint debugger",subtitle:"Dev build only · regression harness for hint behavior",global_switch:"Show hints globally",reset_all:"Reset all",col_id:"ID",col_category:"Category",col_threshold:"Threshold",col_success:"Success count",col_dismissed:"Dismissed",col_should:"Should show",col_actions:"Actions",yes:"Yes",no:"No",dismiss:"Dismiss",reset:"Reset",force:"Force show",forcing:"Forcing",note:"Adding a hint: 1) extend HintId in settings.ts 2) register in HINT_REGISTRY (lib/hints.ts) 3) add overlay.json copy 4) call useHintBubble at the trigger site. The row appears here automatically."},Gs={page:Gt,provider_rollback:Yt,tabs:Jt,hotkeys:Qt,section:Xt,general:Zt,device:ei,asr_segment:ti,output:ii,model:ni,ai:oi,translate_target_lang:ai,translate_output_mode:si,dictation_lang:ri,dictation_provider:li,about:ci,dev_hints:di},Ys=Object.freeze(Object.defineProperty({__proto__:null,about:ci,ai:oi,asr_segment:ti,default:Gs,dev_hints:di,device:ei,dictation_lang:ri,dictation_provider:li,general:Zt,hotkeys:Qt,model:ni,output:ii,page:Gt,provider_rollback:Yt,section:Xt,tabs:Jt,translate_output_mode:si,translate_target_lang:ai},Symbol.toStringTag,{value:"Module"})),_i="Feedback",ui="Open home",pi="AI Tools",hi="History",fi="Settings…",gi="Microphone",mi="Auto-detect",yi="Auto-detect ({{name}})",bi="Dictionary",vi="Check for updates",Si="Quit OpenSpeech",Js={feedback:_i,open_home:ui,open_toolbox:pi,open_history:hi,open_settings:fi,mic_submenu:gi,auto_detect:mi,auto_detect_with_name:yi,open_dictionary:bi,check_update:vi,quit:Si},Qs=Object.freeze(Object.defineProperty({__proto__:null,auto_detect:mi,auto_detect_with_name:yi,check_update:vi,default:Js,feedback:_i,mic_submenu:gi,open_dictionary:bi,open_history:hi,open_home:ui,open_settings:fi,open_toolbox:pi,quit:Si},Symbol.toStringTag,{value:"Module"})),ki={ok:"确定",cancel:"取消",confirm:"确认",save:"保存",close:"关闭",retry:"重试",clear:"清除",remove:"删除",add:"添加",back:"返回",next:"下一步",done:"完成",skip:"跳过",copy:"复制",edit:"编辑",search:"搜索",loading:"加载中…"},wi={system:"跟随系统","zh-CN":"简体中文","zh-TW":"繁體中文",en:"English"},xi={system_default:"跟随系统",system_default_with_current:"跟随系统(当前:{{name}})",auto_detect:"自动检测",none:"无"},Xs={actions:ki,lang:wi,value:xi},Zs=Object.freeze(Object.defineProperty({__proto__:null,actions:ki,default:Xs,lang:wi,value:xi},Symbol.toStringTag,{value:"Module"})),Oi={title:"快捷键冲突",description_one:"下面这条快捷键当前无效(被系统占用或不符合最新规则),请在此处重新绑定一个新组合。",description_other:"以下 {{count}} 条快捷键当前无效(被系统占用或不符合最新规则),请在此处重新绑定。"},Ti={title_pending:"正在为你完成刚才的转写",title_success:"转写完成",title_error:"转写未完成",description_pending:"登录已恢复,正在用刚才的录音继续走云端转写,请稍候…",description_success:"下面是这次录音的最终结果,点击右下角即可复制到剪贴板。",description_error:"登录已恢复,但用录音重新转写时再次失败。可以从历史记录里手动重试。",empty_transcript:"(未识别到内容)",copy:"复制结果",copied:"已复制",close:"关闭",close_disabled:"请稍候…"},Ai={title:"登录 OpenLoaf",openloaf_note:"OpenSpeech 是 OpenLoaf 旗下产品,所有产品共用同一个 OpenLoaf 账号。",description:"选择一种登录方式以继续",subtitle:{idle:"选择登录方式继续",opening:"正在打开浏览器...",polling:"等待在浏览器完成授权",success:"登录成功"},providers:{wechat:"使用微信登录",google:"使用 Google 登录"},or:"或",byo_button:"使用自己的 STT 端点",byo_hint:"不想登录 OpenLoaf?填写你自己的 STT REST 端点,音频从本机直发,不经云端。",retry:"重试",close:"关闭",cancel:"取消登录",details_show:"查看详情",details_hide:"收起详情"},Ri={title:"账户",description:"OpenSpeech 账户与订阅",loading:"// 正在加载 //",section:{identity:"身份",subscription:"订阅",recharge:"充值积分",session:"会话"},row:{email:"电子邮件",wechat:"微信账户",subscription:"订阅",credits_balance:"剩余积分"},membership:{free:"FREE / 免费",lite:"LITE / 轻享",pro:"PRO / 专业",premium:"PREMIUM / 旗舰"},subscribe_button:{default:"订阅 / 升级套餐",upgrade_to_premium:"升级到 PREMIUM",manage:"管理订阅"},subscribe_hint:"在 OpenLoaf 网站完成订阅与套餐管理。",recharge_button:"充值",recharge_hint:"1 元 = 100 积分。不订阅套餐也可直接充值。",logout_button:"退出登录",logout_busy:"正在退出...",logout_hint:"退出后将清除本地登录状态。本地录音、历史与词典将保留。"},Ci={title:"关闭到后台",description:"OpenSpeech 即将关闭主窗口,应用将继续在后台运行",body_1_prefix:"OpenSpeech 将继续在 ",body_1_highlight:"后台",body_1_suffix:" 运行,全局快捷键仍然可用。",body_2:"可通过系统托盘图标重新打开主窗口,或选择「退出」完全结束进程。",remember:"不再提醒",quit:"退出",stay:"后台运行"},Ii={title:"没有互联网连接",description:"您的计算机未连接到互联网,请检查网络后重试",body:"您的计算机未连接到互联网。请检查网络连接后重试。",still_offline:"仍未检测到网络",retry:"重试"},Li={press_new:"按下新快捷键...",recording_hint:"ESC 取消 · 4 秒后自动退出",clear_title:"清除",clear_aria:"清除快捷键",error_prefix:"ERROR",error_illegal_combo:"非法组合",conflict_with:"已被「{{name}}」使用",conflict_reason:{equal:"已被「{{name}}」使用",subset_modifier_only:"与「{{name}}」修饰键集合互为子集,会出现幻影录音",subset_combo:"与「{{name}}」修饰键集合互为子集,按下时会双触发",double_tap_overlap_modifier:"与「{{name}}」共用同一颗修饰键,双击窗口会冲突"},replace:"替换",rebind:"重新录入",cancel:"取消",replaced_toast:"已替换「{{name}}」原本的绑定",undo:"撤销"},$i={default_title:"听写快捷键 / PUSH-TO-TALK",unbound:"未绑定",default_hint:"按一下开始 · 再按一次结束"},Ei={initializing:"INITIALIZING",tagline:"Speak less, write more.",loading:"Loading"},er={hotkey_conflict:Oi,auth_recovery:Ti,login:Ai,account:Ri,close_to_bg:Ci,no_internet:Ii,hotkey_field:Li,hotkey_preview:$i,loading_screen:Ei},tr=Object.freeze(Object.defineProperty({__proto__:null,account:Ri,auth_recovery:Ti,close_to_bg:Ci,default:er,hotkey_conflict:Oi,hotkey_field:Li,hotkey_preview:$i,loading_screen:Ei,login:Ai,no_internet:Ii},Symbol.toStringTag,{value:"Module"})),Pi={title:"会议录制中",description:"{{action}}已被暂停——请先结束当前会议录制再使用",action_dictate:"听写",action_translate:"翻译",action_ask_ai:"问 AI"},Ni={login_timeout:"登录超时,请重试",login_failed:"登录失败,请重试",login_connection_reset:"登录服务器连接被重置,请稍后重试",login_unreachable:"无法连接登录服务器,请检查网络后重试",internal:"内部错误,请稍后再试",not_authenticated:"未登录",not_authenticated_openloaf:"未登录 OpenLoaf",not_authenticated_openspeech:"未登录 OpenSpeech",session_expired:"会话已过期,请重新登录"},Mi={offline:"无互联网连接",unreachable:"网络不可达",service_unreachable:"无法连接到服务",service_unreachable_desc:"网络不可达或服务端异常,已取消本次录音",check_and_retry:"请检查网络后重试"},ji={start_failed:"录音启动失败",save_failed:"录音保存失败",mic_not_ready:"麦克风未就绪",realtime_not_started:"实时转写未启动",hotkey_sync_failed:"同步快捷键到 Rust 失败:{{error}}"},Di={refine:"AI 整理",translate:"翻译"},Ki={transcribe_failed:"转写失败",transcribe_empty:"未拿到转写结果",transcribe_empty_desc:"服务端超时或全程静音",transcribe_placeholder:"(未能获取转写结果)",session_timeout:"会话超时",saas_5xx:"SaaS 服务端错误(5xx)",saas_4xx:"SaaS 鉴权失败(4xx)",unknown:"未知错误"},Fi={copy_failed:"复制到剪贴板失败",paste_failed:"自动粘贴失败"},zi={check_failed:"检查更新失败",available:"发现新版本 {{version}}"},Bi={action:"上报错误",sending:"上报中…",sent:"已上报",toast_success:"错误已上报,感谢反馈!",toast_failed:"上报失败:{{message}}",toast_auth_lost:"登录状态已失效,请重新登录后再上报",toast_network:"网络异常,无法上报,请稍后再试",toast_timeout:"请求超时,请检查网络后重试"},Ui={go_to_settings:"前往设置",meeting_provider_unsupported:"当前通道不支持会议转录",meeting_provider_unsupported_hint:"请到「设置 → 听写」切换到「SaaS」或「自定义 → 腾讯」。",meeting_provider_not_configured:"未配置听写通道",meeting_provider_not_configured_hint:"请到「设置 → 听写」选择「SaaS」或新增「自定义 → 腾讯」供应商。",network_exit:"连接已断开",network_exit_hint:"实时语音识别连接被中断,请检查网络后重试。",idle_timeout:"长时间无声音被断开",idle_timeout_hint:"供应商在长时间静音后关闭了会话,点击「继续」可重连。",start_failed:"无法开始会议",pause_failed:"无法暂停",resume_failed:"无法继续",history_save_failed:"保存会议记录失败",history_open_failed:"打开会议记录失败",history_delete_failed:"删除会议记录失败",unauthenticated_byok:"自定义供应商鉴权失败",unauthenticated_byok_hint:"腾讯返回了鉴权失败。请到「设置 → 听写」检查当前自定义供应商的 AppID / SecretId / SecretKey 是否填写正确。",insufficient_funds:"供应商余额不足",insufficient_funds_hint:"请充值腾讯语音识别账户,或切换到其他供应商。",engine_not_authorized:"腾讯账号未开通 16k_zh_en_speaker 引擎",engine_not_authorized_hint:"「实时说话人分离」是腾讯独立 SKU,「实时语音识别大模型」资源包并不覆盖。请到腾讯云语音识别控制台开通该引擎,或提工单确认:",open_tencent_console:"打开",unauthenticated_saas:"SaaS 登录已失效",unauthenticated_saas_hint:"请重新登录 OpenSpeech 后再开始会议。",insufficient_funds_saas:"SaaS 积分不足",insufficient_funds_saas_hint:"请前往个人中心充值积分,或切换到「自定义 → 腾讯」。",not_authenticated:"未登录",not_authenticated_hint:"SaaS 通道需要先登录 OpenSpeech。请登录后再开始会议,或切换到「自定义 → 腾讯」。"},ir={hotkey_blocked:Pi,auth:Ni,network:Mi,recording:ji,phase:Di,stt:Ki,clipboard:Fi,update:zi,report:Bi,meetings:Ui},nr=Object.freeze(Object.defineProperty({__proto__:null,auth:Ni,clipboard:Fi,default:ir,hotkey_blocked:Pi,meetings:Ui,network:Mi,phase:Di,recording:ji,report:Bi,stt:Ki,update:zi},Symbol.toStringTag,{value:"Module"})),Wi="反馈建议",Hi="反馈建议",Vi="把使用过程中的问题或想法告诉我们。我们会读每一条反馈。",qi="反馈类型",Gi={bug:"Bug 问题",feature:"功能建议",ui:"界面/交互",performance:"性能/卡顿",chat:"AI 对话",other:"其他"},Yi="内容",Ji="描述一下你遇到的情况、复现步骤或者想要的功能…",Qi="联系邮箱(可选)",Xi="you@example.com",Zi="留下邮箱方便我们在解决后回复你;不留也能匿名提交。",en="附带最近日志",tn="勾选后会把最近的应用日志一起发给我们,帮助定位问题。Bug 类反馈默认勾选。",nn="读取日志失败,将不附带日志提交。",on="提交反馈",an="提交中…",sn="取消",rn={content_required:"请填写反馈内容(至少一句话)",email_invalid:"邮箱格式看起来不对"},ln={success:"反馈已提交,谢谢你的反馈!",auth_lost:"登录状态已失效,请重新登录后再提交",network:"网络异常,请稍后再试",timeout:"请求超时,请检查网络后重试",generic:"提交失败:{{message}}"},or={menu_label:Wi,dialog_title:Hi,dialog_description:Vi,type_label:qi,type:Gi,content_label:Yi,content_placeholder:Ji,email_label:Qi,email_placeholder:Xi,email_hint:Zi,attach_logs_label:en,attach_logs_hint:tn,attach_logs_failed:nn,submit:on,submit_loading:an,cancel:sn,validation:rn,toast:ln},ar=Object.freeze(Object.defineProperty({__proto__:null,attach_logs_failed:nn,attach_logs_hint:tn,attach_logs_label:en,cancel:sn,content_label:Yi,content_placeholder:Ji,default:or,dialog_description:Vi,dialog_title:Hi,email_hint:Zi,email_label:Qi,email_placeholder:Xi,menu_label:Wi,submit:on,submit_loading:an,toast:ln,type:Gi,type_label:qi,validation:rn},Symbol.toStringTag,{value:"Module"})),cn={dictate_ptt:"听写",translate:"翻译听写",show_main_window:"打开主窗口",open_toolbox:"打开 AI 工具",edit_last_record:"优化上一条"},dn={dictate_ptt:"按下开始录音,松开后转写并写入光标处",translate:"按下开始录音,松开后翻译并写入光标处",show_main_window:"在任意应用中唤起 OpenSpeech 主窗口",open_toolbox:"在任意应用中跳到 AI 工具页",edit_last_record:"弹出快捷面板优化最近一条识别结果,主窗口不打扰"},_n={unbound:"未绑定",double_tap:"2× {{mod}}",left:"左",right:"右"},un={needs_main_key:"需要配合主键使用",special_keys_locked:"Esc / Enter / 方向键等特殊键需在高级设置开启后使用",typing_key_needs_modifier:"字母 / 数字 / 空格 / 标点等输入键单按会拦截正常打字,必须配修饰键",fn_macos_only:"Fn 键仅在 macOS 可靠可用;请用 Alt + Win 或 Right Alt",modifier_only_no_main:"modifier-only 绑定不能包含主键",modifier_only_min:"至少需要一个修饰键",combo_disallowed_main:"Tab / Backspace / Delete / CapsLock / NumLock / ScrollLock 不可作为主键,误触代价过高",combo_no_fn:"Fn 键不能与主键组合,系统层无法注册",double_tap_no_main:"双击绑定不能包含主键",double_tap_single_mod:"双击只支持单个修饰键",double_tap_fn_macos:"macOS 双击 Fn 是系统听写默认快捷键,会被系统先吞"},pn={system_shortcut:"该组合可能与系统常用快捷键冲突",f_key_bare:"F1-F12 在多数 Mac 默认是亮度 / 音量等系统功能键",modifier_only_single_macos:"单修饰键会吞掉它的所有原生组合(如 ⌘+空格、⌥+方向键、⌃+空格)",modifier_only_single_windows:"单修饰键会吞掉它的所有原生组合(如 Alt+Tab、Win+E、Ctrl+C)",modifier_only_single_linux:"单修饰键会吞掉它的所有原生组合(如 Alt+Tab、Super+空格、Ctrl+C)"},sr={binding:cn,binding_hint:dn,format:_n,validation:un,warning:pn},rr=Object.freeze(Object.defineProperty({__proto__:null,binding:cn,binding_hint:dn,default:sr,format:_n,validation:un,warning:pn},Symbol.toStringTag,{value:"Module"})),hn={subtitle:"// first run setup"},fn={tag:"// welcome to",headline_part1:"说出来。",headline_part2:"就成文。",subhead:"按一下快捷键开始说话,再按一下结束——文字立即出现在你正在使用的任何 App 里。"},gn={section_tag:"// step 01 / permissions · {{platform}}",title_macos:"授权 麦克风 与 辅助功能",title_windows:"授权 麦克风",title_linux:"选择麦克风与注入工具",recheck_all:"重新检测",recheck_all_title:"重新检测全部权限",recheck_one_title:"重新检测",summary_macos:"macOS 需要三项系统权限:「麦克风」(录音)、「辅助功能」(把转写的文字写到当前 App)、「输入监控」(监听全局快捷键)。系统的权限缓存与进程绑定——若已在系统设置勾选但仍显示未授权,点击右上角「重启 OpenSpeech」让新权限生效。",summary_windows:"Windows 需要授权「麦克风」(用于录音)。若你常用的目标程序以管理员身份运行,OpenSpeech 也需相同权限才能注入文字。",summary_linux:"Linux 不需要授权弹窗:选择一个 PipeWire / PulseAudio 输入设备,并确保安装了 ydotool / wtype(Wayland)或 xdotool(X11)即可。",badge_required:"必需",badge_recommended:"推荐",status_checking:"检测中",status_granted:"已授权",primary_acknowledged:"我已知晓",primary_open_settings:"去系统设置",primary_request:"请求授权",primary_grant:"授权",tcc_hint:"已勾选但仍提示未授权?在系统设置该权限列表里移除 OpenSpeech 后重新加入,再点「重启 OpenSpeech」。",footer_next:"下一步",footer_relaunch:"重启 OpenSpeech",footer_hint_ok:"接下来 2 步:登录 → 试用",footer_hint_relaunch:"授权后请重启 · 重启后将自动进入下一步",mic:{title:"麦克风",title_linux:"麦克风设备",rationale:"用于录制你的语音并送到识别引擎。",rationale_linux:"Linux 不需要授权弹窗;从 PipeWire / PulseAudio 选一个输入设备即可。",hint_macos:"授权位置:系统设置 → 隐私与安全性 → 麦克风",hint_windows:"授权位置:Windows 设置 → 隐私 → 麦克风"},accessibility:{title:"辅助功能",rationale:"用于把识别出的文字模拟键盘输入到当前焦点的输入框。",hint_macos:"授权位置:系统设置 → 隐私与安全性 → 辅助功能"},input_monitoring:{title:"输入监控",rationale:"用于在你正在使用其它 App 时,监听全局快捷键(如 Fn / Alt+Win)触发录音。",hint_macos:"授权位置:系统设置 → 隐私与安全性 → 输入监控"},inject_tools:{title_windows:"目标程序权限提示",rationale_windows:"若你常用的程序以管理员身份运行(如 cmd),OpenSpeech 也需要相同权限才能注入文字。",title_linux:"检测注入工具",rationale_linux:"Wayland 下需要 ydotool / wtype,X11 下需要 xdotool。OpenSpeech 会自动检测。"}},mn={section_tag:"// step 02 / account",title:"登录 OpenLoaf 账号",subtitle_openloaf:"OpenSpeech 是 OpenLoaf 旗下产品,所有 OpenLoaf 产品共用同一个账号与积分。",bonus_main:"新用户立即到账 200 积分",bonus_minutes_prefix:"· 约",bonus_minutes_value:"30 分钟",bonus_minutes_suffix:"语音",method_wechat_label:"微信登录",method_wechat_sub:"扫码即可登录",method_google_label:"Google 登录",method_google_sub:"浏览器跳转登录",status_success:"登录成功,正在进入下一步…",status_opening:"正在打开浏览器…",status_polling:"等待在浏览器完成授权…",cancel:"取消",advanced_collapse:"↑ 收起",advanced_expand:"↓ 我有自己的 STT 端点",advanced_desc:"配置自定义 REST STT 端点(OpenAI / Groq / Deepgram / 自部署)。此选项仅推荐给开发者;普通用户请用上方账号登录。",advanced_cta:"跳过登录,去配置自定义端点",error_default:"登录失败,请重试",error_reset:"登录服务器连接被重置,请重试",error_timeout:"登录超时,请重试",error_network:"无法连接登录服务器,请检查网络后重试"},yn={section_tag:"// step 03 / try it",title:"试一次。",subhead:"按一下下方快捷键开始 · 说一句话 · 再按一下结束",checklist_tag:"// CHECKLIST",checklist:{step1:"按一下听写快捷键开始",step2:"对着麦克风说一句话",step3:"再按一下结束",step4:"看到文字写入下方"},mock_slices:["今","今天","今天天气","今天天气真好","今天天气真好,","今天天气真好,我打开","今天天气真好,我打开了 OpenSpeech","今天天气真好,我打开了 OpenSpeech 试试看。"],hotkey_title:"你的听写快捷键",hotkey_hint:"按一下开始 · 再按一次结束",samples_label:"AUDIO · {{count}} SAMPLES",live_transcript_tag:"// LIVE TRANSCRIPT",transcript_chars:"{{count}} CHARS",transcript_placeholder:"实时转写文字将出现在这里…",completed_title:"配置完成,可以开始使用了",completed_desc:"正式使用时光标在哪个 App,文字就写到哪个 App。",reset:"重置",mock_running:"演示中…",mock_run:"▶ 模拟一次",finish:"完成引导",skip_finish:"跳过并完成",status:{ready_tag:"// READY",ready_primary:"开始说话…",ready_secondary:"Esc 取消",listening_tag:"// LISTENING",listening_primary:"再按一次快捷键 结束并转写",listening_secondary:"Esc 取消本次录音",transcribing_tag:"// TRANSCRIBING",transcribing_primary:"正在转写…",transcribing_secondary:"Esc 放弃这次结果",injecting_tag:"// INJECTING",injecting_primary:"正在写入输入框…",error_tag:"// ERROR",error_primary:"出错了,检查日志或重试",idle_tag:"// IDLE"}},lr={header:hn,welcome:fn,permissions:gn,login:mn,try_it:yn},cr=Object.freeze(Object.defineProperty({__proto__:null,default:lr,header:hn,login:mn,permissions:gn,try_it:yn,welcome:fn},Symbol.toStringTag,{value:"Module"})),bn={cancel:"取消",confirm:"确定",close_result:"关闭结果"},vn={target:"翻译目标语言:{{lang}}",mode_label:"翻译模式",lang:{en:"英文",zh:"中文","zh-TW":"繁体中文",ja:"日文",ko:"韩文",fr:"法文",de:"德文",es:"西班牙文"}},Sn={to_translate:"切换为翻译模式",to_dictation:"切换为听写模式",tap_again_to_output:"再按 {{hotkey}} 输出"},kn={error_fallback:"错误",transcribing:"正在思考中…",injecting:"正在输出中…",translating:"正在翻译中…"},wn={tag:{ready:"// READY",listening:"// LISTENING",transcribing:"// TRANSCRIBING",injecting:"// INJECTING",error:"// ERROR",idle:"// IDLE",processing:"// PROCESSING"},primary:{ready:"开始说话…",listening:"再按一次快捷键 结束并转写",transcribing:"正在转写…",injecting:"正在写入输入框…",error:"出错了,检查日志或重试",result:"已写入输入框 · 按快捷键开始下一次"},secondary:{ready:"Esc 取消",listening:"Esc 取消本次录音",transcribing:"Esc 放弃这次结果",result:"或点击 ✕ 关闭"},placeholder:"实时转写文字将出现在这里…",utterance_timer_label:"整句模式",result_label:{original:"原文",translation:"译文",polished:"润色版"},result_stats:{recording:"录音",response:"响应"},dictate_status:{ai_on:"AI 优化已启用",ai_off:"AI 优化未启用"},mode_action:{dictate:"听写",translate:"翻译"},mode_segment:{utterance:"整句",realtime:"实时"},action:{stop:"结束并转写",stop_translate:"结束并翻译",cancel:"取消本次录音",retry_hint:"按快捷键重试",kbd_esc:"Esc",copy:"复制",copied:"已复制",edit:"修改",refine:"润色",refining:"润色中…",translate:"翻译",translating:"翻译中…"},coming_soon:"即将上线",coming_soon_tag:"// SOON",refine_scenario:{menu_aria:"选择润色场景",helper:"选场景,提升润色精度",count:"{{count}} 个场景",limit_hint:"最多选 3 个"},translate_lang:{menu_aria:"选择翻译目标语言"},meter:{live:"LIVE",chars:"{{count}} CHARS",samples:"AUDIO · {{count}} SAMPLES"}},xn={stt_start_failed:{title:"实时转写未启动",description:"{{reason}} · 本次仅本地录音"},recording_start_failed:{title:"录音启动失败"},transcribe_failed:{title:"转写失败",no_transcript:"未识别到内容,可在历史里点重试"},byok_switch_to_saas:{action:"切到云端",switched_title:"已切换到 OpenLoaf 云端",switched_description:"请按快捷键重新录音"},recording_save_failed:{title:"录音保存失败"},clipboard_failed:{title:"复制到剪贴板失败"},paste_failed:{title:"自动粘贴失败",description:"文字已复制,请手动按 Cmd/Ctrl+V"},not_logged_in:{title:"未登录 OpenSpeech",description:"请登录后再使用语音输入",action:"登录"},dictation_fallback:{title:"已切换到 OpenLoaf SaaS",description:"自定义供应商尚未配置,本次转写已自动改用云端服务"},ai_refine_auto_fallback:{title:"AI 改写已切换到 OpenLoaf SaaS",description:"自定义 AI 供应商尚未配置完成,已自动改用云端服务"},ai_refine_custom_failed:{title:"AI 改写失败(自定义供应商)",description_missing_key:"未找到自定义供应商的 ApiKey,可点击按钮切回云端服务",description_runtime:`自定义供应商无法访问:{{error}}
|
|
3
|
-
可点击按钮切回云端服务`,action:"切到 SaaS"},asr_error:{title:"转写异常",unknown:"未知错误"},worker_dead:{title:"语音通道异常中断",description:"已停止本次录音,请重新开始",error_message:"语音通道异常中断,已停止录音"},insufficient_credits:{title:"余额不足",description:"已取消本次转写,请前往账户页充值",error_message:"余额不足,已取消本次转写"},session_timeout:{title:"会话超时",description:"达到 2 小时服务端上限"},preflight_failed:{title:"无法开始录音"},aborted_saved:{title:"已取消,未转录",description:"录音已保存到历史"},silent_recording:{title:"未检测到语音"},realtime_degraded:{title:"实时识别异常",description:"正在用录音重转,请稍候",realtime_mode:"已保留前半段,可在历史里重试整段"}},On={placeholder:"(未能获取转写结果)",aborted_placeholder:"(已取消,未转录)"},Tn={title:"未自动输入",copy:"复制",copied:"已复制"},An={stt_not_authenticated:"未登录 OpenLoaf",stt_5xx:"SaaS 服务端错误(5xx)",stt_4xx:"SaaS 鉴权失败(4xx)",stt_mic_not_ready:"麦克风未就绪",stt_network:"网络不可达",sync_hotkey_failed:"同步快捷键到 Rust 失败:{{error}}",preflight_permission_denied:"未授予麦克风权限",preflight_no_device:"未找到可用麦克风",byok_not_implemented:"自定义 BYOK 通道开发中,将在下个版本启用",byok_missing_credentials:"自定义供应商凭证缺失,请到设置 → 听写 → 自定义供应商配置",byok_keyring_error:"无法从系统密钥链读取自定义供应商凭证",file_too_large_for_tencent_byok:"单个文件超过腾讯 BYOK 文件转写上限(约 5 分钟),请改用 REALTIME 模式或缩短录音",tencent_task_failed:"腾讯任务执行失败:{{msg}}",tencent_task_timeout:"腾讯任务超时(>24 分钟未返回结果)",transcribe_timeout:"转写请求超时(服务端无响应,已自动结束等待)",tencent_unauthenticated:"腾讯 BYOK 鉴权失败 —— 请检查设置里的 SecretId / SecretKey",tencent_rate_limited:"腾讯 BYOK 触发限流,请稍候再试",tencent_cos_unauthenticated:"腾讯 COS 鉴权失败 —— 请检查 SecretId / SecretKey 与存储桶权限",tencent_cos_forbidden:"腾讯 COS 拒绝了上传 —— 请确认 Bucket 名称、Region 与访问策略",tencent_cos_network:"腾讯 COS 网络异常 —— 请检查网络后重试",tencent_cos_unknown:"腾讯 COS 上传失败(未知错误)",unauthenticated_byok:"自定义凭证鉴权失败:请检查 SecretId / SecretKey",insufficient_funds:"腾讯云账户余额不足或服务未开通",idle_timeout:"长时间无音频,已自动断开",rate_limited:"供应商触发限流,请稍候再试",aliyun_invalid_audio_format:"音频格式不被阿里 DashScope 支持,请检查采样率与位深",aliyun_quota_exceeded:"阿里 DashScope 配额已用尽",aliyun_unauthenticated:"阿里 DashScope 鉴权失败 —— 请检查设置里的 ApiKey",aliyun_rate_limited:"阿里 DashScope 触发限流,请稍候再试",aliyun_upload_failed:"阿里 DashScope OSS 上传失败:{{msg}}",aliyun_filetrans_failed:"阿里 DashScope 任务执行失败:{{msg}}",aliyun_filetrans_timeout:"阿里 DashScope 任务超时(>24 分钟未返回结果)",aliyun_file_too_large:"文件大小超过阿里 DashScope BYOK 单文件上限(默认 100MB)"},Rn={aria:{dismiss:"不再显示该提示"},recordingControls:{text:"松开结束 · ESC 取消"},resultActions:{text:"⌘C 复制 · 编辑 · 润色 · 翻译"},firstResultConfirm:{text:"已输入 · 修正",action_correct:"正确",action_revise:"修正"}},dr={aria:bn,translate:vn,mode_switch:Sn,status:kn,panel:wn,toast:xn,transcript:On,result:Tn,error:An,hints:Rn},_r=Object.freeze(Object.defineProperty({__proto__:null,aria:bn,default:dr,error:An,hints:Rn,mode_switch:Sn,panel:wn,result:Tn,status:kn,toast:xn,transcript:On,translate:vn},Symbol.toStringTag,{value:"Module"})),Cn={too_long_for_utterance:"单次录音超过 5 分钟,UTTERANCE 模式不支持,请切换到 REALTIME 模式",aliyun_oss_upload_failed:"阿里云 OSS 上传失败,凭证可能已过期或网络不稳定",aliyun_filetrans_failed:"阿里云文件转写任务失败,请稍后重试",aliyun_file_too_large:"文件超过 100 MB,已达到阿里云 OSS 单文件上限",tencent_cos_upload_failed:"腾讯云 COS 上传失败,请检查凭证与网络",tencent_cos_bucket_required:"需要先在听写设置中填写腾讯 COS 存储桶才能转写(旧凭证可能没填)"},In={hero:{title_line1:"说出来。",title_line2:"就成文。",description:"按一下快捷键,开口说话,再按一下结束——文字即刻出现在任意应用中。不绑定编辑器,录音只留本机,无任何遥测。",feature_push_to_talk:"// PUSH-TO-TALK 按键听写",feature_cross_platform:"// 跨平台 WIN · MAC · LINUX"},hotkey_hint:"按一下快捷键开始录音,再按一下结束并把文字写入当前输入框。按 <esc>Esc</esc> 取消;焦点必须在可编辑区域。",translate_hint:"按一下翻译快捷键开始录音,再按一下结束。系统会先转写再翻译为目标语言,并写入当前输入框。",translate_bilingual:"双语输出",translate_bilingual_aria:"双语输出(原文 + 译文)",edit_hotkey:"编辑快捷键",edit_hotkey_dialog_title:"编辑快捷键",edit_hotkey_dialog_description:"录入或修改当前快捷键绑定。",quick_dict:{button_aria:"添加新词",title:"我的词典",empty:"// 还没有任何词条 //",domains_label:"// 常用领域"},hotkey_tab:{dictate:"听写",translate:"翻译"},hotkey_title:{dictate:"听写 / PUSH-TO-TALK",translate:"翻译 / TRANSLATE"},stats:{section_title:"今日 / 本次会话",section_title_today:"今日会话统计",section_title_all:"累计会话统计",tab_today:"今日",tab_all:"累计",live_metrics:"// LIVE METRICS",duration_label:"口述时长",duration_unit:"HH:MM",words_label:"口述字数",words_unit:"总计",wpm_label:"平均速度",wpm_unit:"字/分钟",saved_label:"节省时间",saved_unit:"HH:MM",open_dialog_aria:"查看 {{label}} 详细统计"},stats_dialog:{title:"数据统计",subtitle:"含听写 / 问 AI / 翻译 · 数据仅本机",close:"关闭",range:{today:"今日","7d":"近 7 天","30d":"近 30 天","90d":"近 90 天",all:"全部"},metric_switcher_label:"聚焦",kpi:{duration:"时长",words:"字数",wpm:"WPM",saved:"节省",sessions:"次数"},main:{duration:{title:"时长走势",hint:"每日累计录音时长(HH:MM)"},words:{title:"字数累计",hint:"随时间累积的总产出字数"},wpm:{title:"WPM 走势",hint:"每日平均口述速度"},saved:{title:"节省累计",hint:"相对 {{baseline}} WPM 打字基线累计省下的时间"},sessions:{title:"次数走势",hint:"每日听写会话数"}},facet:{heatmap:{title:"活跃时段",hint:"周一–周日 × 0–23 时;色越深用得越多",weekdays:"一,二,三,四,五,六,日"},top_apps:{title:"Top 目标应用",hint:"你最常在哪些应用里写字",unknown:"未知应用"},wpm_by_mode:{title:"WPM × 分段模式",hint:"REALTIME 与 UTTERANCE 的速度对比"},saved_equivalent:{title:"等价折算",hint:"把节省的时间换算成更直观的单位",items:{typing_hours:"≈ 打字 {{value}}",podcasts:"≈ 听 {{value}} 集播客",coffees:"≈ 喝 {{value}} 杯咖啡",books_pages:"≈ 看 {{value}} 页书"}},session_dist:{title:"单次字数分布",hint:"短句、中段、长稿各占多少",buckets:{short:"短句 ≤ 20 字",medium:"中段 21–100 字",long:"长稿 > 100 字"}},duration_dist:{title:"单次时长分布",hint:"按一次录音的长度分桶,看你说短句多还是说长稿多",buckets:{lt10s:"< 10 秒",s10_30:"10–30 秒",s30_60:"30–60 秒",s60_120:"1–2 分钟",gt120s:"> 2 分钟"}},type_mix:{title:"类型分布",hint:"你都用 OpenSpeech 做什么——听写、问 AI 还是翻译",buckets:{dictation:"听写",ask:"问 AI",translate:"翻译"}},provider_dist:{title:"通道分布",hint:"不同 ASR 通道的次数与平均速度",unknown:"未知通道"},ai_refine_rate:{title:"AI 优化使用率",hint:"多少次会话用了 AI 整理;以及平均整理耗时",used_label:"已使用",avg_label:"平均耗时"},status_mix:{title:"成功率",hint:"成功 / 失败 / 取消 三态占比",buckets:{success:"成功",failed:"失败",cancelled:"已取消"}},asr_source_dist:{title:"ASR 通道分布",hint:"实时 / 文件转写 / 自定义端点 各占多少",buckets:{"saas-realtime":"实时","saas-rest":"文件转写",byo:"自定义",unknown:"未知"}}},empty:"// 还没有听写记录,去主界面试试 //"}},Ln={title:"历史记录",subtitle:"历史记录保存在本设备。",search_placeholder:"搜索历史...",more:"更多",refresh:"刷新",stats:"统计",retention:{label:"保留时长",title:"本机历史记录保留多久",options:{forever:"永远","90d":"90 天","30d":"30 天","7d":"7 天",off:"不保存"}},open_folder:"打开录音文件夹",open_folder_failed:"打开录音文件夹失败",delete_all:"删除全部历史",filters:{all:"全部",dictation:"听写",ask:"随便问",translate:"翻译"},buckets:{today:"今天",yesterday:"昨天",this_week:"本周",earlier:"更早"},empty:"// 暂无记录 //",loading_more:"// 加载更多 //",list_end:"// 已到底 · 共 {{count}} 条 //",status:{success:"成功",failed:"失败",cancelled:"已取消",retrying:"重新生成中"},player:{play:"播放",pause:"暂停"},row:{play:"播放原始录音",pause:"暂停",copy:"复制到剪贴板",copied:"已复制",reinject:"重新注入",export:"导出音频",delete:"删除",retry:"重新生成",transcribe:"转入",retrying_label:"重新生成中",retrying_placeholder:"正在重新生成转录…",retry_no_audio:"无可用音频,无法重新生成",retry_too_long:"超过 5 分钟的录音暂不支持重新生成",retry_in_progress:"重新生成中…",retry_tooltip:"重新生成转录",failed_placeholder:"您的转录被中断。可以重新生成一次。",cancelled_placeholder:"{{duration}} 录音已取消,未转录 · 可重新转录",view_refined:"AI 优化",view_translation:"译文",view_raw:"原始文本",view_details:"查看详情",copy_debug:"复制调试信息"},detail:{title:"记录详情",description:"查看历史记录完整内容并执行操作",meta:{duration:"时长",target:"目标应用",error:"错误",warn:"备注",asr:"音频识别",ai:"AI 优化",segment_mode:"模式",provider_kind:"通道"},asr:{"saas-realtime":"OpenLoaf SaaS · 实时识别","saas-rest":"OpenLoaf SaaS · REST 转写",byo:"自定义 STT 端点"},ai:{none:"未启用"},segment_mode:{REALTIME:"实时",UTTERANCE:"整句"},provider_kind:{"saas-realtime":"OpenLoaf 实时","saas-file":"OpenLoaf 文件","tencent-realtime":"腾讯实时","tencent-file":"腾讯文件","aliyun-realtime":"阿里实时","aliyun-file":"阿里文件"},unknown:"—",empty_text:"(无文本内容)"},toast:{copy_success:"已复制到剪贴板",copy_failed:"复制失败",copy_debug_success:"调试信息已复制",copy_debug_failed:"复制调试信息失败",copy_debug_missing:"该记录未捕获到请求快照(可能为正式版录入或调用前已失败)",retry_success:"重新生成成功",retry_failed:"重新生成失败",delete_failed:"删除失败",export_success:"音频已导出",export_failed:"导出失败",refresh_failed:"刷新失败"},edit:{title:"修改记录",description:"修改这条历史记录的最终文本",edit_button:"修改",edit_tooltip:"把识别错误的地方改对,下次更准",original_label:"原始内容(AI 给的最终版)",diff_label:"修改对比(红色=删除,绿色=新增)",edited_label:"你的修改",hint:"改完保存即可,系统会异步学习",placeholder:"在这里修改文本…",save:"保存",revert:"撤销修改",revert_tooltip:"丢弃这条记录的修改,恢复到 AI 原版",edited_chip:"已修改",edited_tooltip:"你修改过这条记录的文本",toast:{save_success:"已保存修改",save_failed:"保存失败",revert_success:"已恢复原版",dict_added:"已添加字典:{{term}}",dict_updated:"已更新字典:{{term}}",dict_removed:"已删除字典:{{term}}",dict_hint:"AI 根据你的修改自动学习"}},confirm_clear:{title:"删除全部历史",description:"清空本机历史记录",body:"将删除本机的 <count>{{count}}</count> 条历史记录,操作不可撤销。",tip:"// 建议先导出备份",confirm:"确认删除"}},$n={title:"词典",subtitle:"自定义词汇 · 最多 2,000 条",new_word:"+ 新词",search_placeholder:"搜索词条...",filters:{all:"全部",domains:"常见领域",manual:"手动添加"},empty:"// 暂无词条 //",count_total:"// 共 {{count}} 条 //",divider_label:"自定义词条",card:{domain_tooltip:"常用领域",manual_tooltip:"手动添加",edit:"编辑",delete:"删除"},domains:{helper:"勾选你常聊的领域,AI 会优先按这些场景调整术语和措辞",limit_hint:"最多选 {{limit}} 个",counter:"已选 {{count}} / {{limit}}",items:{programming:"软件开发",ai_ml:"AI / 机器学习",medicine:"医学健康",law:"法律",finance:"金融投资",academic:"学术科研",engineering:"工程制造",marketing:"营销增长",psychology:"心理学",design:"设计创意",film_production:"影视制作",cybersecurity:"网络安全",photography:"摄影",tcm:"中医",automotive:"汽车"}},new_dialog:{title:"新词",description:"添加自定义词典条目",term_label:"term",term_placeholder:"例如 OpenSpeech",error_empty:"term 不能为空",error_duplicate:"该词条已存在",submitting:"添加中…",submit:"添加"}},En={nav:{home:"首页",toolbox:"翻译 / 润色",meetings:"会议录制",history:"历史",dictionary:"词典"},account_fallback:"账户",login:"登录",credits:"Credits",time_left:"LEFT",time_minutes:"{{minutes}} MIN",settings:"设置",tray:{update_found_title:"发现新版本",update_none:"当前已是最新版本",update_check_failed:"检查更新失败"}},Pn={placeholder:"搜索...",clear:"清空搜索",open:"搜索"},Nn={title:"翻译 / 润色",subtitle:"随手输入或开口说话,再润色、翻译、朗读。",flow_hint:"上方给输入 · 下方挑工具 · 即刻拿到处理后的结果",input:{section_label:"// 01 · 输入",tabs:{text:"文字",voice:"语音",history:"历史",file:"音频文件"},text_placeholder:"在这里输入或粘贴文字…",dictate_hint:"按下快捷键 · 直接开口听写",dictate_unbound:"未绑定听写快捷键",voice_hint:"按住按钮说话,松开自动转写。",voice_button_idle:"按住说话",voice_button_recording:"正在听…",voice_recorded:"已录制 · 0:08",history_hint:"从历史记录里挑一条。",history_empty:"暂无历史记录。",file_hint:"拖入或选择音频文件(mp3 / wav / m4a)。",file_button:"选择音频文件",file_loaded:"demo.mp3 · 12s · 1.2 MB",char_count:"{{count}} 字",right_label:"文字",right_hint_voice:"来自语音转写",right_hint_history:"来自历史记录",right_hint_file:"来自音频转写",right_empty:"请先在左侧给一个输入。",use_sample:"用示例文字",replaced_hint:"已替换为上一步输出",restore_original:"还原原文",paste:"粘贴",history:"历史",clear:"清空",clipboard_detected:"检测到剪贴板内容",clipboard_translate:"粘贴并翻译",clipboard_fill_only:"仅粘贴"},tools:{section_label:"// 02 · 工具",tabs:{polish:"润色",translate:"翻译",tts:"朗读"},tutorial:{polish:{title:"润色",headline:"按场景把口语稿改写成成稿——邮件、微信、汇报随你挑。"},translate:{title:"翻译",headline:"把文字翻成另一种语言,尽量保留语气。"},tts:{title:"朗读",headline:"把文字合成自然的语音。"}},polish:{scenario_label:"场景",scenarios_empty:"未配置场景",add_scenario:"+ 新增",examples:{email:"邮件",wechat:"微信",report:"工作汇报",meeting_notes:"会议纪要",social_post:"朋友圈"}},translate:{target_label:"译为",languages:{en:"英文",zh:"中文","zh-TW":"繁体中文",ja:"日文",ko:"韩文",fr:"法文",de:"德文",es:"西班牙文"}},tts:{voice_label:"声音",speed_label:"语速",voices:{natural_f:"自然·女声",natural_m:"自然·男声",calm_f:"舒缓·女声"},audio_placeholder:"▶ ━━━━━━━━━━━━━━━━━━━━ 0:08 / 0:12"},run:"运行",run_hint:"配置好上方参数后点击运行",ready_to_run:"就绪 · 待运行",running:"运行中…",error_title:"运行失败",error:"失败 · {{message}}",rerun:"重跑",copy:"复制",save_history:"保存",use_as_input:"用作输入",download:"下载",elapsed:"{{seconds}}s",idle:"等待输入",output_empty:"在上方填入或选择一段输入"},output:{idle_label:"等待运行",ready:"READY",waiting_input:"等待输入完毕…",generating:"生成中…",meta_chars:"{{count}} 字",meta_elapsed:"耗时 {{seconds}}s"},footer:{ui_only_notice:"// UI 预览 — 业务尚未接入"}},Mn={title:"会议录制",subtitle:"长时间录音 · 自动分人 · 时间轴回看",idle:{hint:"点击开始记录",recent:"最近会议",items:"项",empty:"暂无会议记录",empty_transcript:"(无内容)",loading:"加载中…",starting:"正在连接供应商…",language_support:"// 当前仅支持 中文 / 英语 / 粤语 / 多种方言(川、陕、豫、沪、湘、鄂、皖)"},live:{recording:"录音中",paused:"已暂停",pause:"暂停",resume:"继续",stop:"结束",listening:"正在聆听...",reconnecting:"网络异常,正在重连… ({{attempt}}/{{max}})",reconnect_gave_up:"重连失败,会议已断开"},speaker:{label:"用户 {{letter}}",pending:"用户 …"},review:{back:"返回",speakers:"位说话人",delete:"删除",delete_confirm:"确认删除这条会议记录?",summary:"纪要",transcript:"逐字稿",summary_topic:"会议主题",summary_speakers:"发言人",summary_abstract:"会议摘要",summary_section:"讨论要点",summary_loading:"正在加载纪要…",summary_generate:"生成纪要",summary_regenerate:"重新生成",summary_failed:"纪要生成失败",summary_idle_hint:"点上方「生成纪要」按钮,按当前 AI 通道生成 Markdown 纪要(设置 → AI → 提示词 → 会议纪要 可改默认提示)。",summary_empty_transcript:"本次会议没有可总结的内容。",export:"导出",export_default_name:"会议-{{date}}-{{shortId}}",export_md_filter:"Markdown",export_doc_title:"会议记录",export_meta_created:"时间",export_meta_duration:"时长",export_meta_speakers:"说话人数",export_meta_segments:"段数",export_success:"已导出到 {{path}}",export_failed:"导出失败"}},ur={transcribe:Cn,home:In,history:Ln,dictionary:$n,layout:En,search_box:Pn,toolbox:Nn,meetings:Mn},pr=Object.freeze(Object.defineProperty({__proto__:null,default:ur,dictionary:$n,history:Ln,home:In,layout:En,meetings:Mn,search_box:Pn,toolbox:Nn,transcribe:Cn},Symbol.toStringTag,{value:"Module"})),jn={title:"优化",empty:"暂无可优化的识别结果",cancel:"取消",save:"优化并复制",saving:"优化中…",learn_hint:"AI 会从这次优化中学习,下次识别更懂你",close_aria:"关闭"},Dn={saved_title:"已保存优化",saved_description:"新文本已复制到剪贴板,回到原输入框粘贴即可",save_failed_title:"保存失败"},hr={edit_last_record:jn,toast:Dn},fr=Object.freeze(Object.defineProperty({__proto__:null,default:hr,edit_last_record:jn,toast:Dn},Symbol.toStringTag,{value:"Module"})),Kn={section_index:"[04] 系统",title:"设置",subtitle:"配置听写、模型端点与应用行为。改动即时生效,无需保存。",dialog_title:"设置",dialog_sr:"OpenSpeech 设置"},Fn={title:"已回退到 OpenLoaf SaaS",description:"{{which}}的自定义供应商未通过测试,已切换到云端服务",dictation:"听写",ai:"AI 改写",both:"听写与 AI 改写",confirm_title:"自定义供应商未通过测试",confirm_description:"{{which}}所选的自定义供应商还没有通过测试,无法在此模式下应用。继续关闭设置会自动回退到 OpenLoaf SaaS 云端服务。",confirm_back_to_test:"返回测试",confirm_proceed:"回退到 SaaS 并关闭"},zn={general:"通用",hotkeys:"快捷键",dictation:"听写",model:"模型",ai:"AI",about:"关于",dev_hints:"提示调试"},Bn={reset_all:"重置全部",reset_all_confirm:"确定将所有快捷键恢复为默认值?",reset_all_done:"已恢复默认快捷键"},Un={shortcuts:"键盘快捷键",language:"语言",audio:"音频",asr_segment:"听写模式",text_injection:"文本注入",behavior:"行为",model_rest:"大模型(REST)",build:"构建",output:"输出方式"},Wn={interface_lang:"界面语言",translate_target_lang:"翻译目标语言",translate_target_lang_hint:"翻译听写快捷键命中后,转写文本会被译成此语言再注入到当前焦点。",translate_output_mode:"翻译输出形态",translate_output_mode_hint:"「双语」保留原文并追加译文;「仅目标语言」只输出译文,速度更快。",input_device:"输入设备",input_level:"输入声音",input_level_hint_listening:"实时电平 · 正在监听:{{name}}",input_level_hint:"实时麦克风电平",cue_sound:"开始/结束提示音",restore_clipboard:"粘贴后恢复剪贴板",restore_clipboard_hint:"建议保持开启",launch_startup:"开机自启",close_to_tray:"关闭时最小化到托盘",close_to_tray_hint:"开启后关闭主窗口直接隐藏到托盘;关闭时每次弹确认对话框",update_policy:"自动更新",update_policy_hint:"选择后台发现新版本时的处理方式",update_policy_options:{prompt:"提示我安装",auto:"空闲时自动安装",disabled:"关闭"},loading:"// loading settings…",dictation_output_lang:"听写输出语言",dictation_output_lang_hint:"听写转写出来的文字使用哪种语言。「自动」时由 ASR 自行判定,并以界面语言作为默认对照。",translate_conflict_warning:"目标语言与听写输出语言相同,翻译将无意义。"},Hn={system_default:"跟随系统",system_default_with_current:"跟随系统(当前:{{name}})",is_default_suffix:"{{name}} · 系统默认",disconnected_with_fallback:"{{name}} · 已断开,暂用系统默认({{fallback}})",disconnected:"{{name}} · 已断开"},Vn={realtime_label:"实时转换",realtime_hint:"服务端按停顿自动切句、录音过程中实时回填;适合长会议字幕、直播转写等无人值守场景。",utterance_label:"整句听写",utterance_hint:"整段录音视为一次完整对话,松开按键后再返回转写结果;模型有完整上下文,更准、更不易被停顿误切。",ai_refine_toggle:{label:"启用 AI 优化",hint:"在「整句听写」基础上调用大模型整理:去口头禅、消重、识别自我修正;同语言不翻译。",disabled_in_realtime:"实时转换模式下不可用"}},qn={streaming_inject:{label:"文字逐字输出",hint:"默认开启:模型一边产出,文字一边敲到光标位置。关闭后改为整段一次粘贴,可绕开微信输入法 / 部分全拼输入法的逐字符拦截(首字吞、双逗号等异常)。"},clipboard_copy:{label:"自动复制到剪贴板",hint:"默认关闭:注入完成后会还原你原本的剪贴板内容,不污染复制队列。开启后整段文字保留在剪贴板,方便再次手动粘贴。"}},Gn={byo_unavailable_tag:"// BYO-MODEL · 暂未实现",byo_unavailable_body:"自定义 STT REST 端点(端点 URL / API Key / 模型名 / 测试连接)尚未接入,当前所有听写均走 OpenLoaf SaaS。该入口正在开发中,下一版本会启用。",endpoint:"端点 URL",api_key:"API Key",api_key_hint:"存储于系统密钥链;失去焦点时自动保存",model_name:"模型名称",timeout_seconds:"请求超时(秒)",audio_format:"音频格式",test_connection_disabled:"测试连接(暂未实现)",show_key:"显示 API Key",hide_key:"隐藏 API Key",key_saved_toast:"API Key 已保存到系统密钥链",key_save_failed_toast:"API Key 保存失败: {{error}}"},Yn={section_mode:"AI 通道",mode_saas_label:"云端(推荐)",mode_saas_hint:"走 OpenLoaf 已登录账号的快速 chat 模型,按积分计费。",mode_custom_label:"自定义供应商",mode_custom_hint:"OpenAI 兼容协议;自带 API Key,可加多个供应商但同一时刻只能激活一个。",section_providers:"自定义供应商",providers_empty:"尚未添加自定义供应商",provider_name:"名称",provider_base_url:"Base URL",provider_model:"模型",provider_api_key:"API Key",provider_api_key_hint:"存储于系统密钥链;失去焦点时自动保存",provider_active:"当前激活",provider_set_active:"设为激活",provider_remove:"删除",provider_test:"测试",provider_test_running:"测试中…",provider_test_pass:"测试通过",provider_test_fail:"测试失败:{{message}}",provider_test_missing_fields:"Base URL 或模型未填写",provider_test_empty_reply:"模型未返回内容",provider_add:"新增供应商",provider_default_name:"新供应商",provider_default_base_url:"https://api.openai.com/v1",provider_default_model:"gpt-4o-mini",section_prompts:"系统提示词",prompts_hint:"默认跟随当前界面语言;一旦修改即视为自定义,对所有语言生效。",prompt_tab_refine:"听写优化",prompt_tab_translate:"翻译",prompt_tab_polish:"润色",prompt_tab_meeting:"会议纪要",prompt_edit:"修改",prompt_status_custom:"已自定义",prompt_status_default:"默认",prompt_desc_refine:"松开听写按键后,AI 把语音转写整理成更通顺的书面文本(错字、口头禅、断句),再注入到当前应用。",prompt_desc_translate:"通过「翻译」快捷键触发,把听写文本翻译成上面设置的目标语言。",prompt_desc_polish:"AI 工具箱「润色」页面使用,可配合下方场景列表(邮件、微信等)按需切换语气。",prompt_desc_meeting:"「会议」页面把整段会议录音转写后,按本提示词整理成结构化纪要。",prompt_dialog_title_refine:"听写优化提示词",prompt_dialog_title_translate:"翻译提示词",prompt_dialog_title_meeting:"会议纪要提示词",prompt_dialog_textarea_label:"系统提示词",polish_dialog_title:"润色设置",polish_dialog_subtitle:"调整润色用的系统提示词,并维护 AI 工具箱里出现的场景列表。",polish_dialog_tab_prompt:"提示词",polish_dialog_tab_scenarios:"场景",polish_dialog_prompt_label:"润色提示词",polish_scenarios_title:"润色场景",polish_scenarios_hint:"AI 工具箱「润色」页底部 chip 列表的来源;运行时会把所选场景的指令拼接到润色系统提示词后。",polish_scenarios_empty:"尚未添加润色场景",polish_scenario_default_name:"新场景",polish_scenario_remove:"删除",polish_scenario_add:"新增场景",polish_scenario_instruction_placeholder:"例如:目标场景是商务邮件,语气正式,按问候 / 正文 / 结尾分段。",refine_dialog_tab_prompt:"提示词",refine_dialog_tab_examples:"案例",refine_dialog_tab_overrides:"按应用覆盖",refine_examples_builtin_title:"内置案例",refine_examples_builtin_hint:"{{count}} 条预置案例 · 点击展开 · 可克隆为自定义后修改",refine_example_clone:"克隆",refine_rules_builtin_title:"内置规则",refine_rules_builtin_hint:"{{count}} 条预置核心规则 · 点击展开 · 可克隆为自定义后修改",refine_rules_title:"自定义规则",refine_rules_hint:"未自定义时使用内置规则;点「添加规则」或克隆任一内置规则进入自定义模式。自定义模式下,运行时只发送你这里写的规则到模型。",refine_rules_using_default:"当前使用内置规则。点下方「添加规则」或上方「克隆」开始自定义。",refine_rules_empty:"已进入自定义模式但还没添加规则——运行时会只发空 core_rules 段。",refine_rules_count:"{{current}} / {{max}}",refine_rule_add:"添加规则",refine_rule_remove:"删除",refine_rule_clone:"克隆",refine_rule_body_placeholder:"规则正文(多段用空行分隔)",refine_rule_why_placeholder:"Why —— 该规则的 rationale(可选)",refine_examples_title:"自定义案例",refine_examples_hint:"把「差的转写 → 期望整理」成对喂给模型;运行时按顺序追加到内置案例之后,越靠前优先级越高。",refine_examples_empty:"还没添加案例",refine_examples_count:"{{current}} / {{max}}",refine_example_add:"添加案例",refine_example_remove:"删除",refine_example_target_placeholder:"target(如 *、chat)",refine_example_focus_placeholder:"focus —— 本条要点(可选)",refine_example_input_placeholder:"input —— 原始 / 有问题的转写",refine_example_output_placeholder:"output —— 期望整理后的文本",app_overrides_title:"按应用覆盖",app_overrides_hint:"对特定应用单独配置规则与案例:命中时优先使用此处规则,案例拼在全局之前。仅匹配跑过 refine 留下 appId 的应用。",app_overrides_empty:"还没添加覆盖",app_overrides_count:"{{current}} / {{max}}",app_override_add:"添加覆盖",app_override_remove:"删除",app_override_enabled:"启用",app_override_expand:"展开",app_override_collapse:"收起",app_override_core_rules_label:"覆盖核心规则(留空则用全局)",app_override_core_rules_clear:"清空",app_override_core_rules_placeholder:"为该应用定制的 <core_rules>...</core_rules>;为空表示沿用全局核心规则。",app_override_picker_title:"选择要覆盖的应用",app_override_no_history:"暂无可覆盖的应用——先在该应用里跑一次听写优化,让它出现在历史里。",prompt_reset:"恢复默认",section_history:"上下文",include_history:"把最近的历史一起发送",include_history_hint:"把最近的 transcript 作为参考上下文,帮助模型沿用一致的语气与术语。",recent_history_count:"携带条数",recent_history_count_hint:"AI 上下文最多带最近多少条历史;条数越多偏置越强,但 token 消耗也更多。",minutes_ago:"分钟前",history_truncated:"省略 {{count}} 字"},Jn={en:"English",zh:"简体中文","zh-TW":"繁體中文",ja:"日本語",ko:"한국어",fr:"Français",de:"Deutsch",es:"Español"},Qn={target_only:"仅目标语言",bilingual:"双语(原文 + 译文)"},Xn={label:"听写语种",hint:"选择你说话使用的语言;选「自动」让上游 ASR 自检测,遇歧义按界面语言对照。",follow_interface:"跟随界面语言",auto:"自动",zh:"中文",en:"English",ja:"日本語",ko:"한국어",yue:"粤语"},Zn={section_mode:"听写通道",mode_saas_label:"OpenLoaf 云端(默认)",mode_saas_hint:"使用已登录账号走 OpenLoaf 托管的语音识别,按积分计费。听写与会议转录共用同一通道。",mode_custom_label:"自定义供应商",mode_custom_hint:"用自己的腾讯云 / 阿里云密钥直连厂商 API,不经过 SaaS。会议转录需选择「腾讯云」(自带说话人分离)。",section_providers:"自定义供应商",providers_empty:"尚未添加任何自定义供应商",add_tencent:"新增腾讯云",add_aliyun:"新增阿里云",vendor_tencent:"腾讯云",vendor_aliyun:"阿里云 DashScope",active_label:"当前激活 · {{vendor}}",set_active:"设为激活",remove:"删除",name_label:"名称",tencent_default_name:"腾讯云语音识别",tencent_app_id:"AppID",tencent_region:"区域(Region)",tencent_secret_id:"Secret ID",tencent_secret_key:"Secret Key",tencent_credentials_hint:"凭证存储于系统密钥链;失去焦点时自动保存。可在腾讯云控制台 → API 密钥管理获取。",tencent_cos_bucket_label:"COS 存储桶",tencent_cos_bucket_placeholder:"myaudio-1234567890",tencent_cos_bucket_hint:"必填:录音通过 COS 上传后再转写,单文件 ≤512MB。不填则受腾讯文件接口 base64 5MB 限制,超过后无法转写。",aliyun_default_name:"阿里云 DashScope",aliyun_api_key:"ApiKey",aliyun_api_key_hint:"存储于系统密钥链;失去焦点时自动保存。可在 DashScope 控制台获取。",test:"测试",test_running:"测试中…",test_pass:"测试通过:凭证有效",test_fail:"测试失败:{{message}}",test_missing_fields:"必填字段未填",verified_badge:"已验证",unverified_badge:"未验证",test_code:{ok:"测试通过",unauthenticated:"鉴权失败:请检查 Secret/ApiKey 是否正确",service_not_enabled:"凭证有效,但语音识别服务尚未在该账号下开通",missing_fields:"必填字段未填",network:"网络不可达,请检查链路与防火墙",timeout:"请求超时,请稍后重试",rate_limited:"调用过于频繁",cos_unauthorized:"ASR 凭证有效,但当前 SecretId 无权访问该 COS 存储桶",cos_not_found:"ASR 凭证有效,但 COS 存储桶不存在或地域不匹配",oss_policy_failed:"ApiKey 有效,但获取 OSS 上传策略失败:账号可能未开通百炼录音文件资源",unknown:"未知错误"}},eo={version:"版本",platform:"平台",license:"许可证",source:"源代码",check_update:"检查更新",dev_build:"当前是开发版",rerun_onboarding:"重新运行首次引导",install_now:"立即安装",skip_version:"跳过此版本",install_in_progress:"正在下载并安装更新…",install_progress:"{{version}} · {{percent}}% · {{downloaded}} / {{total}}",install_starting:"{{version}} · 已下载 {{downloaded}}",install_finalizing:"下载完成,正在安装…",install_failed:"更新安装失败",update_channel:"更新通道",update_channel_stable:"正式版",update_channel_beta:"Beta(抢先体验)",update_channel_hint:"Beta 通道更早收到新功能,但可能不稳定。关闭 Beta 后只会接收到版本号高于当前 Beta 的正式版。",open_log_dir:"打开日志目录",saas_sdk_version:"SaaS SDK 版本"},to={title:"交互提示调试",subtitle:"仅 dev 构建可见 · 用于回归 hint 行为",global_switch:"全局显示提示",reset_all:"全部重置",col_id:"ID",col_category:"类别",col_threshold:"阈值",col_success:"成功次数",col_dismissed:"已关闭",col_should:"应显示",col_actions:"操作",yes:"是",no:"否",dismiss:"关闭",reset:"重置",force:"强制显示",forcing:"强制中",note:"新增 hint 步骤:① settings.ts 加 HintId ② lib/hints.ts 注册 HINT_REGISTRY ③ overlay.json 加文案 ④ 调用方挂 useHintBubble。完成后本表自动出现。"},gr={page:Kn,provider_rollback:Fn,tabs:zn,hotkeys:Bn,section:Un,general:Wn,device:Hn,asr_segment:Vn,output:qn,model:Gn,ai:Yn,translate_target_lang:Jn,translate_output_mode:Qn,dictation_lang:Xn,dictation_provider:Zn,about:eo,dev_hints:to},mr=Object.freeze(Object.defineProperty({__proto__:null,about:eo,ai:Yn,asr_segment:Vn,default:gr,dev_hints:to,device:Hn,dictation_lang:Xn,dictation_provider:Zn,general:Wn,hotkeys:Bn,model:Gn,output:qn,page:Kn,provider_rollback:Fn,section:Un,tabs:zn,translate_output_mode:Qn,translate_target_lang:Jn},Symbol.toStringTag,{value:"Module"})),io="反馈意见",no="打开首页",oo="AI 工具",ao="历史记录",so="设置…",ro="选择麦克风",lo="Auto-detect",co="Auto-detect ({{name}})",_o="字典",uo="检查更新",po="退出 OpenSpeech",yr={feedback:io,open_home:no,open_toolbox:oo,open_history:ao,open_settings:so,mic_submenu:ro,auto_detect:lo,auto_detect_with_name:co,open_dictionary:_o,check_update:uo,quit:po},br=Object.freeze(Object.defineProperty({__proto__:null,auto_detect:lo,auto_detect_with_name:co,check_update:uo,default:yr,feedback:io,mic_submenu:ro,open_dictionary:_o,open_history:ao,open_home:no,open_settings:so,open_toolbox:oo,quit:po},Symbol.toStringTag,{value:"Module"})),ho={ok:"確定",cancel:"取消",confirm:"確認",save:"儲存",close:"關閉",retry:"重試",clear:"清除",remove:"刪除",add:"新增",back:"返回",next:"下一步",done:"完成",skip:"略過",copy:"複製",edit:"編輯",search:"搜尋",loading:"載入中…"},fo={system:"跟隨系統","zh-CN":"简体中文","zh-TW":"繁體中文",en:"English"},go={system_default:"跟隨系統",system_default_with_current:"跟隨系統(目前:{{name}})",auto_detect:"自動偵測",none:"無"},vr={actions:ho,lang:fo,value:go},Sr=Object.freeze(Object.defineProperty({__proto__:null,actions:ho,default:vr,lang:fo,value:go},Symbol.toStringTag,{value:"Module"})),mo={title:"快速鍵衝突",description_one:"下面這條快速鍵目前無效(被系統佔用或不符合最新規則),請在此處重新綁定一個新組合。",description_other:"以下 {{count}} 條快速鍵目前無效(被系統佔用或不符合最新規則),請在此處重新綁定。"},yo={title_pending:"正在為你完成剛才的轉寫",title_success:"轉寫完成",title_error:"轉寫未完成",description_pending:"登入已恢復,正在用剛才的錄音繼續走雲端轉寫,請稍候…",description_success:"下面是這次錄音的最終結果,點擊右下角即可複製到剪貼簿。",description_error:"登入已恢復,但用錄音重新轉寫時再次失敗。可以從歷史記錄裡手動重試。",empty_transcript:"(未辨識到內容)",copy:"複製結果",copied:"已複製",close:"關閉",close_disabled:"請稍候…"},bo={title:"登入 OpenLoaf",openloaf_note:"OpenSpeech 屬於 OpenLoaf 產品線,所有產品共用同一個 OpenLoaf 帳號。",description:"選擇一種登入方式以繼續",subtitle:{idle:"選擇登入方式繼續",opening:"正在開啟瀏覽器...",polling:"等待在瀏覽器完成授權",success:"登入成功"},providers:{wechat:"使用微信登入",google:"使用 Google 登入"},or:"或",byo_button:"使用自己的 STT 端點",byo_hint:"不想登入 OpenLoaf?填寫你自己的 STT REST 端點,音訊從本機直發,不經雲端。",retry:"重試",close:"關閉",cancel:"取消登入",details_show:"檢視詳情",details_hide:"收起詳情"},vo={title:"帳戶",description:"OpenSpeech 帳戶與訂閱",loading:"// 載入中 //",section:{identity:"身分",subscription:"訂閱",recharge:"儲值積分",session:"工作階段"},row:{email:"電子郵件",wechat:"微信帳戶",subscription:"訂閱",credits_balance:"剩餘積分"},membership:{free:"FREE / 免費",lite:"LITE / 輕享",pro:"PRO / 專業",premium:"PREMIUM / 旗艦"},subscribe_button:{default:"訂閱 / 升級方案",upgrade_to_premium:"升級到 PREMIUM",manage:"管理訂閱"},subscribe_hint:"在 OpenLoaf 網站完成訂閱與方案管理。",recharge_button:"儲值",recharge_hint:"1 元 = 100 積分。不訂閱方案也可直接儲值。",logout_button:"登出",logout_busy:"正在登出...",logout_hint:"登出後將清除本機登入狀態。本機錄音、歷史與字典將保留。"},So={title:"關閉到背景",description:"OpenSpeech 即將關閉主視窗,應用程式將繼續在背景執行",body_1_prefix:"OpenSpeech 將繼續在 ",body_1_highlight:"背景",body_1_suffix:" 執行,全域快速鍵仍然可用。",body_2:"可透過系統工具列圖示重新開啟主視窗,或選擇「結束」完全結束處理程序。",remember:"不再提示",quit:"結束",stay:"背景執行"},ko={title:"沒有網際網路連線",description:"您的電腦未連線到網際網路,請檢查網路後重試",body:"您的電腦未連線到網際網路。請檢查網路連線後重試。",still_offline:"仍未偵測到網路",retry:"重試"},wo={press_new:"按下新快速鍵...",recording_hint:"ESC 取消 · 4 秒後自動退出",clear_title:"清除",clear_aria:"清除快速鍵",error_prefix:"ERROR",error_illegal_combo:"非法組合",conflict_with:"已被「{{name}}」使用",conflict_reason:{equal:"已被「{{name}}」使用",subset_modifier_only:"與「{{name}}」修飾鍵集合互為子集,會出現幻影錄音",subset_combo:"與「{{name}}」修飾鍵集合互為子集,按下時會雙觸發",double_tap_overlap_modifier:"與「{{name}}」共用同一顆修飾鍵,雙擊窗口會衝突"},replace:"取代",rebind:"重新錄入",cancel:"取消",replaced_toast:"已取代「{{name}}」原本的繫結",undo:"撤銷"},xo={default_title:"聽寫快速鍵 / PUSH-TO-TALK",unbound:"未繫結",default_hint:"按一下開始 · 再按一次結束"},Oo={initializing:"INITIALIZING",tagline:"Speak less, write more.",loading:"Loading"},kr={hotkey_conflict:mo,auth_recovery:yo,login:bo,account:vo,close_to_bg:So,no_internet:ko,hotkey_field:wo,hotkey_preview:xo,loading_screen:Oo},wr=Object.freeze(Object.defineProperty({__proto__:null,account:vo,auth_recovery:yo,close_to_bg:So,default:kr,hotkey_conflict:mo,hotkey_field:wo,hotkey_preview:xo,loading_screen:Oo,login:bo,no_internet:ko},Symbol.toStringTag,{value:"Module"})),To={title:"會議錄製中",description:"{{action}}已被暫停——請先結束目前會議錄製再使用",action_dictate:"聽寫",action_translate:"翻譯",action_ask_ai:"問 AI"},Ao={login_timeout:"登入逾時,請重試",login_failed:"登入失敗,請重試",login_connection_reset:"登入伺服器連線被重設,請稍後重試",login_unreachable:"無法連線到登入伺服器,請檢查網路後重試",internal:"內部錯誤,請稍後再試",not_authenticated:"尚未登入",not_authenticated_openloaf:"尚未登入 OpenLoaf",not_authenticated_openspeech:"尚未登入 OpenSpeech",session_expired:"工作階段已過期,請重新登入"},Ro={offline:"沒有網際網路連線",unreachable:"網路無法連線",service_unreachable:"無法連線到服務",service_unreachable_desc:"網路無法連線或服務端異常,已取消本次錄音",check_and_retry:"請檢查網路後重試"},Co={start_failed:"錄音啟動失敗",save_failed:"錄音儲存失敗",mic_not_ready:"麥克風尚未就緒",realtime_not_started:"即時轉寫尚未啟動",hotkey_sync_failed:"同步快速鍵到 Rust 失敗:{{error}}"},Io={refine:"AI 整理",translate:"翻譯"},Lo={transcribe_failed:"轉寫失敗",transcribe_empty:"未取得轉寫結果",transcribe_empty_desc:"伺服器逾時或全程靜音",transcribe_placeholder:"(未能取得轉寫結果)",session_timeout:"工作階段逾時",saas_5xx:"SaaS 伺服器錯誤(5xx)",saas_4xx:"SaaS 驗證失敗(4xx)",unknown:"未知錯誤"},$o={copy_failed:"複製到剪貼簿失敗",paste_failed:"自動貼上失敗"},Eo={check_failed:"檢查更新失敗",available:"發現新版本 {{version}}"},Po={action:"回報錯誤",sending:"回報中…",sent:"已回報",toast_success:"錯誤已回報,感謝你的回饋!",toast_failed:"回報失敗:{{message}}",toast_auth_lost:"登入狀態已失效,請重新登入後再回報",toast_network:"網路異常,無法回報,請稍後再試",toast_timeout:"請求逾時,請檢查網路後重試"},No={go_to_settings:"前往設定",meeting_provider_unsupported:"目前通道不支援會議轉錄",meeting_provider_unsupported_hint:"請到「設定 → 聽寫」切換到「SaaS」或「自訂 → 騰訊」。",meeting_provider_not_configured:"尚未設定聽寫通道",meeting_provider_not_configured_hint:"請到「設定 → 聽寫」選擇「SaaS」或新增「自訂 → 騰訊」供應商。",network_exit:"連線已中斷",network_exit_hint:"即時語音辨識連線被中斷,請檢查網路後重試。",idle_timeout:"長時間無聲音而被中斷",idle_timeout_hint:"供應商在長時間靜音後關閉了會話,點選「繼續」可重新連線。",start_failed:"無法開始會議",pause_failed:"無法暫停",resume_failed:"無法繼續",history_save_failed:"儲存會議記錄失敗",history_open_failed:"開啟會議記錄失敗",history_delete_failed:"刪除會議記錄失敗",unauthenticated_byok:"自訂供應商驗證失敗",unauthenticated_byok_hint:"騰訊回傳了驗證失敗。請到「設定 → 聽寫」確認當前自訂供應商的 AppID / SecretId / SecretKey 是否正確。",insufficient_funds:"供應商餘額不足",insufficient_funds_hint:"請為騰訊語音辨識帳戶儲值,或切換到其他供應商。",engine_not_authorized:"騰訊帳號未開通 16k_zh_en_speaker 引擎",engine_not_authorized_hint:"「即時說話人分離」是騰訊獨立 SKU,「即時語音辨識大模型」資源包並不涵蓋。請到騰訊雲語音辨識控制台開通該引擎,或提工單確認:",open_tencent_console:"開啟",unauthenticated_saas:"SaaS 登入已失效",unauthenticated_saas_hint:"請重新登入 OpenSpeech 後再開始會議。",insufficient_funds_saas:"SaaS 積分不足",insufficient_funds_saas_hint:"請前往個人中心儲值積分,或切換到「自訂 → 騰訊」。",not_authenticated:"尚未登入",not_authenticated_hint:"SaaS 通道需要先登入 OpenSpeech。請登入後再開始會議,或切換到「自訂 → 騰訊」。"},xr={hotkey_blocked:To,auth:Ao,network:Ro,recording:Co,phase:Io,stt:Lo,clipboard:$o,update:Eo,report:Po,meetings:No},Or=Object.freeze(Object.defineProperty({__proto__:null,auth:Ao,clipboard:$o,default:xr,hotkey_blocked:To,meetings:No,network:Ro,phase:Io,recording:Co,report:Po,stt:Lo,update:Eo},Symbol.toStringTag,{value:"Module"})),Mo="意見回饋",jo="意見回饋",Do="把使用過程中的問題或想法告訴我們,我們會閱讀每一條回饋。",Ko="回饋類型",Fo={bug:"Bug 問題",feature:"功能建議",ui:"介面/互動",performance:"效能/卡頓",chat:"AI 對話",other:"其他"},zo="內容",Bo="描述一下你遇到的情況、重現步驟或想要的功能…",Uo="聯絡信箱(選填)",Wo="you@example.com",Ho="留下信箱方便我們在處理後回覆你;不留也能匿名提交。",Vo="附帶最近日誌",qo="勾選後會把最近的應用日誌一起傳給我們,幫助定位問題。Bug 類回饋預設勾選。",Go="讀取日誌失敗,將不附帶日誌送出。",Yo="送出回饋",Jo="送出中…",Qo="取消",Xo={content_required:"請填寫回饋內容(至少一句話)",email_invalid:"信箱格式看起來不正確"},Zo={success:"回饋已送出,謝謝你的回饋!",auth_lost:"登入狀態已失效,請重新登入後再送出",network:"網路異常,請稍後再試",timeout:"請求逾時,請檢查網路後重試",generic:"送出失敗:{{message}}"},Tr={menu_label:Mo,dialog_title:jo,dialog_description:Do,type_label:Ko,type:Fo,content_label:zo,content_placeholder:Bo,email_label:Uo,email_placeholder:Wo,email_hint:Ho,attach_logs_label:Vo,attach_logs_hint:qo,attach_logs_failed:Go,submit:Yo,submit_loading:Jo,cancel:Qo,validation:Xo,toast:Zo},Ar=Object.freeze(Object.defineProperty({__proto__:null,attach_logs_failed:Go,attach_logs_hint:qo,attach_logs_label:Vo,cancel:Qo,content_label:zo,content_placeholder:Bo,default:Tr,dialog_description:Do,dialog_title:jo,email_hint:Ho,email_label:Uo,email_placeholder:Wo,menu_label:Mo,submit:Yo,submit_loading:Jo,toast:Zo,type:Fo,type_label:Ko,validation:Xo},Symbol.toStringTag,{value:"Module"})),ea={dictate_ptt:"聽寫",translate:"翻譯聽寫",show_main_window:"開啟主視窗",open_toolbox:"開啟 AI 工具",edit_last_record:"優化上一條"},ta={dictate_ptt:"按下開始錄音,放開後轉寫並寫入游標處",translate:"按下開始錄音,放開後翻譯並寫入游標處",show_main_window:"在任意應用中喚起 OpenSpeech 主視窗",open_toolbox:"在任意應用中跳到 AI 工具頁",edit_last_record:"彈出快捷面板優化最近一條辨識結果,不打擾主視窗"},ia={unbound:"未綁定",double_tap:"2× {{mod}}",left:"左",right:"右"},na={needs_main_key:"需要搭配主鍵使用",special_keys_locked:"Esc / Enter / 方向鍵等特殊鍵需在進階設定開啟後使用",typing_key_needs_modifier:"字母 / 數字 / 空格 / 標點等輸入鍵單按會攔截正常打字,必須搭配修飾鍵",fn_macos_only:"Fn 鍵僅在 macOS 可靠可用;請改用 Alt + Win 或 Right Alt",modifier_only_no_main:"modifier-only 綁定不能包含主鍵",modifier_only_min:"至少需要一個修飾鍵",combo_disallowed_main:"Tab / Backspace / Delete / CapsLock / NumLock / ScrollLock 不可作為主鍵,誤觸代價過高",combo_no_fn:"Fn 鍵不能與主鍵組合,系統層無法註冊",double_tap_no_main:"雙擊綁定不能包含主鍵",double_tap_single_mod:"雙擊只支援單一修飾鍵",double_tap_fn_macos:"macOS 雙擊 Fn 是系統聽寫預設快捷鍵,會被系統先吞"},oa={system_shortcut:"該組合可能與系統常用快捷鍵衝突",f_key_bare:"F1-F12 在多數 Mac 預設是亮度 / 音量等系統功能鍵",modifier_only_single_macos:"單一修飾鍵會吞掉它的所有原生組合(如 ⌘+空格、⌥+方向鍵、⌃+空格)",modifier_only_single_windows:"單一修飾鍵會吞掉它的所有原生組合(如 Alt+Tab、Win+E、Ctrl+C)",modifier_only_single_linux:"單一修飾鍵會吞掉它的所有原生組合(如 Alt+Tab、Super+空格、Ctrl+C)"},Rr={binding:ea,binding_hint:ta,format:ia,validation:na,warning:oa},Cr=Object.freeze(Object.defineProperty({__proto__:null,binding:ea,binding_hint:ta,default:Rr,format:ia,validation:na,warning:oa},Symbol.toStringTag,{value:"Module"})),aa={subtitle:"// first run setup"},sa={tag:"// welcome to",headline_part1:"說出來。",headline_part2:"就成文。",subhead:"按一下快速鍵開始說話,再按一下結束——文字立即出現在你正在使用的任何 App 裡。"},ra={section_tag:"// step 01 / permissions · {{platform}}",title_macos:"授權 麥克風 與 輔助使用",title_windows:"授權 麥克風",title_linux:"選擇麥克風與注入工具",recheck_all:"重新偵測",recheck_all_title:"重新偵測全部權限",recheck_one_title:"重新偵測",summary_macos:"macOS 需要三項系統權限:「麥克風」(錄音)、「輔助使用」(把轉寫的文字寫到目前 App)、「輸入監控」(監聽全域快速鍵)。系統的權限快取與行程繫結——若已在系統設定勾選但仍顯示未授權,點擊右上角「重新啟動 OpenSpeech」讓新權限生效。",summary_windows:"Windows 需要授權「麥克風」(用於錄音)。若你常用的目標程式以系統管理員身分執行,OpenSpeech 也需相同權限才能注入文字。",summary_linux:"Linux 不需要授權彈窗:選擇一個 PipeWire / PulseAudio 輸入裝置,並確保安裝了 ydotool / wtype(Wayland)或 xdotool(X11)即可。",badge_required:"必需",badge_recommended:"推薦",status_checking:"偵測中",status_granted:"已授權",primary_acknowledged:"我已知曉",primary_open_settings:"前往系統設定",primary_request:"請求授權",primary_grant:"授權",tcc_hint:"已勾選但仍提示未授權?在系統設定該權限清單裡移除 OpenSpeech 後重新加入,再點「重新啟動 OpenSpeech」。",footer_next:"下一步",footer_relaunch:"重新啟動 OpenSpeech",footer_hint_ok:"接下來 2 步:登入 → 試用",footer_hint_relaunch:"授權後請重新啟動 · 重啟後將自動進入下一步",mic:{title:"麥克風",title_linux:"麥克風裝置",rationale:"用於錄製你的語音並送到辨識引擎。",rationale_linux:"Linux 不需要授權彈窗;從 PipeWire / PulseAudio 選一個輸入裝置即可。",hint_macos:"授權位置:系統設定 → 隱私權與安全性 → 麥克風",hint_windows:"授權位置:Windows 設定 → 隱私 → 麥克風"},accessibility:{title:"輔助使用",rationale:"用於把辨識出的文字模擬鍵盤輸入到目前焦點的輸入框。",hint_macos:"授權位置:系統設定 → 隱私權與安全性 → 輔助使用"},input_monitoring:{title:"輸入監控",rationale:"用於在你正在使用其它 App 時,監聽全域快速鍵(如 Fn / Alt+Win)觸發錄音。",hint_macos:"授權位置:系統設定 → 隱私權與安全性 → 輸入監控"},inject_tools:{title_windows:"目標程式權限提示",rationale_windows:"若你常用的程式以系統管理員身分執行(如 cmd),OpenSpeech 也需要相同權限才能注入文字。",title_linux:"偵測注入工具",rationale_linux:"Wayland 下需要 ydotool / wtype,X11 下需要 xdotool。OpenSpeech 會自動偵測。"}},la={section_tag:"// step 02 / account",title:"登入 OpenLoaf 帳號",subtitle_openloaf:"OpenSpeech 屬於 OpenLoaf 產品線,所有 OpenLoaf 產品共用同一個帳號與點數。",bonus_main:"新使用者立即到帳 200 點數",bonus_minutes_prefix:"· 約",bonus_minutes_value:"30 分鐘",bonus_minutes_suffix:"語音",method_wechat_label:"微信登入",method_wechat_sub:"掃碼即可登入",method_google_label:"Google 登入",method_google_sub:"瀏覽器跳轉登入",status_success:"登入成功,正在進入下一步…",status_opening:"正在開啟瀏覽器…",status_polling:"等待在瀏覽器完成授權…",cancel:"取消",advanced_collapse:"↑ 收起",advanced_expand:"↓ 我有自己的 STT 端點",advanced_desc:"設定自訂 REST STT 端點(OpenAI / Groq / Deepgram / 自架)。此選項僅推薦給開發者;一般使用者請用上方帳號登入。",advanced_cta:"略過登入,去設定自訂端點",error_default:"登入失敗,請重試",error_reset:"登入伺服器連線被重設,請重試",error_timeout:"登入逾時,請重試",error_network:"無法連線到登入伺服器,請檢查網路後重試"},ca={section_tag:"// step 03 / try it",title:"試一次。",subhead:"按一下下方快速鍵開始 · 說一句話 · 再按一下結束",checklist_tag:"// CHECKLIST",checklist:{step1:"按一下聽寫快速鍵開始",step2:"對著麥克風說一句話",step3:"再按一下結束",step4:"看到文字寫入下方"},mock_slices:["今","今天","今天天氣","今天天氣真好","今天天氣真好,","今天天氣真好,我打開","今天天氣真好,我打開了 OpenSpeech","今天天氣真好,我打開了 OpenSpeech 試試看。"],hotkey_title:"你的聽寫快速鍵",hotkey_hint:"按一下開始 · 再按一次結束",samples_label:"AUDIO · {{count}} SAMPLES",live_transcript_tag:"// LIVE TRANSCRIPT",transcript_chars:"{{count}} CHARS",transcript_placeholder:"即時轉寫文字將出現在這裡…",completed_title:"設定完成,可以開始使用了",completed_desc:"正式使用時游標在哪個 App,文字就寫到哪個 App。",reset:"重設",mock_running:"示範中…",mock_run:"▶ 模擬一次",finish:"完成引導",skip_finish:"略過並完成",status:{ready_tag:"// READY",ready_primary:"開始說話…",ready_secondary:"Esc 取消",listening_tag:"// LISTENING",listening_primary:"再按一次快速鍵 結束並轉寫",listening_secondary:"Esc 取消本次錄音",transcribing_tag:"// TRANSCRIBING",transcribing_primary:"正在轉寫…",transcribing_secondary:"Esc 放棄這次結果",injecting_tag:"// INJECTING",injecting_primary:"正在寫入輸入框…",error_tag:"// ERROR",error_primary:"出錯了,檢查紀錄或重試",idle_tag:"// IDLE"}},Ir={header:aa,welcome:sa,permissions:ra,login:la,try_it:ca},Lr=Object.freeze(Object.defineProperty({__proto__:null,default:Ir,header:aa,login:la,permissions:ra,try_it:ca,welcome:sa},Symbol.toStringTag,{value:"Module"})),da={cancel:"取消",confirm:"確定",close_result:"關閉結果"},_a={target:"翻譯目標語言:{{lang}}",mode_label:"翻譯模式",lang:{en:"英文",zh:"中文","zh-TW":"繁體中文",ja:"日文",ko:"韓文",fr:"法文",de:"德文",es:"西班牙文"}},ua={to_translate:"切換為翻譯模式",to_dictation:"切換為聽寫模式",tap_again_to_output:"再按 {{hotkey}} 輸出"},pa={error_fallback:"錯誤",transcribing:"正在思考中…",injecting:"正在輸出中…",translating:"正在翻譯中…"},ha={tag:{ready:"// READY",listening:"// LISTENING",transcribing:"// TRANSCRIBING",injecting:"// INJECTING",error:"// ERROR",idle:"// IDLE",processing:"// PROCESSING"},primary:{ready:"開始說話…",listening:"再按一次快捷鍵 結束並轉寫",transcribing:"轉寫中…",injecting:"寫入輸入框中…",error:"發生錯誤,請檢查日誌或重試",result:"已寫入輸入框 · 按快捷鍵開始下一次"},secondary:{ready:"Esc 取消",listening:"Esc 取消這次錄音",transcribing:"Esc 放棄這次結果",result:"或點擊 ✕ 關閉"},placeholder:"即時轉寫文字將出現在這裡…",utterance_timer_label:"整句模式",result_label:{original:"原文",translation:"譯文",polished:"潤稿版"},result_stats:{recording:"錄音",response:"回應"},dictate_status:{ai_on:"AI 優化已啟用",ai_off:"AI 優化未啟用"},mode_action:{dictate:"聽寫",translate:"翻譯"},mode_segment:{utterance:"整句",realtime:"即時"},action:{stop:"結束並轉寫",stop_translate:"結束並翻譯",cancel:"取消本次錄音",retry_hint:"按快捷鍵重試",kbd_esc:"Esc",copy:"複製",copied:"已複製",edit:"修改",refine:"潤稿",refining:"潤稿中…",translate:"翻譯",translating:"翻譯中…"},coming_soon:"即將上線",coming_soon_tag:"// SOON",refine_scenario:{menu_aria:"選擇潤稿情境",helper:"選情境,提升潤稿精度",count:"{{count}} 個情境",limit_hint:"最多選 3 個"},translate_lang:{menu_aria:"選擇翻譯目標語言"},meter:{live:"LIVE",chars:"{{count}} CHARS",samples:"AUDIO · {{count}} SAMPLES"}},fa={stt_start_failed:{title:"即時轉寫未啟動",description:"{{reason}} · 本次僅本機錄音"},recording_start_failed:{title:"錄音啟動失敗"},transcribe_failed:{title:"轉寫失敗",no_transcript:"未辨識到內容,可在歷史裡點重試"},byok_switch_to_saas:{action:"切到雲端",switched_title:"已切換為 OpenLoaf 雲端",switched_description:"請按快捷鍵重新錄音"},recording_save_failed:{title:"錄音儲存失敗"},clipboard_failed:{title:"複製到剪貼簿失敗"},paste_failed:{title:"自動貼上失敗",description:"文字已複製,請手動按 Cmd/Ctrl+V"},not_logged_in:{title:"尚未登入 OpenSpeech",description:"請登入後再使用語音輸入",action:"登入"},dictation_fallback:{title:"已切換為 OpenLoaf SaaS",description:"自訂供應商尚未設定,本次轉寫已改用雲端服務"},ai_refine_auto_fallback:{title:"AI 改寫已切換為 OpenLoaf SaaS",description:"自訂 AI 供應商尚未設定完成,已改用雲端服務"},ai_refine_custom_failed:{title:"AI 改寫失敗(自訂供應商)",description_missing_key:"找不到自訂供應商的 ApiKey,可點擊按鈕切回雲端服務",description_runtime:`自訂供應商無法存取:{{error}}
|
|
4
|
-
可點擊按鈕切回雲端服務`,action:"切換為 SaaS"},asr_error:{title:"轉寫異常",unknown:"未知錯誤"},worker_dead:{title:"語音通道異常中斷",description:"已停止本次錄音,請重新開始",error_message:"語音通道異常中斷,已停止錄音"},insufficient_credits:{title:"餘額不足",description:"已取消本次轉寫,請前往帳戶頁儲值",error_message:"餘額不足,已取消本次轉寫"},session_timeout:{title:"工作階段逾時",description:"達到 2 小時伺服器上限"},preflight_failed:{title:"無法開始錄音"},aborted_saved:{title:"已取消,未轉寫",description:"錄音已儲存到歷史"},silent_recording:{title:"未偵測到語音"},realtime_degraded:{title:"即時辨識異常",description:"正在用錄音重轉,請稍候",realtime_mode:"已保留前半段,可在歷史裡重試整段"}},ga={placeholder:"(未能取得轉寫結果)",aborted_placeholder:"(已取消,未轉寫)"},ma={title:"未自動輸入",copy:"複製",copied:"已複製"},ya={stt_not_authenticated:"尚未登入 OpenLoaf",stt_5xx:"SaaS 伺服器錯誤(5xx)",stt_4xx:"SaaS 驗證失敗(4xx)",stt_mic_not_ready:"麥克風尚未就緒",stt_network:"網路不可達",sync_hotkey_failed:"同步快捷鍵到 Rust 失敗:{{error}}",preflight_permission_denied:"未授予麥克風權限",preflight_no_device:"未找到可用麥克風",byok_not_implemented:"自訂 BYOK 通道開發中,將在下個版本啟用",byok_missing_credentials:"自訂供應商憑證缺失,請到設定 → 聽寫 → 自訂供應商設定",byok_keyring_error:"無法從系統密鑰鏈讀取自訂供應商憑證",file_too_large_for_tencent_byok:"單個檔案超過騰訊 BYOK 檔案轉寫上限(約 5 分鐘),請改用 REALTIME 模式或縮短錄音",tencent_task_failed:"騰訊任務執行失敗:{{msg}}",tencent_task_timeout:"騰訊任務超時(>24 分鐘未返回結果)",transcribe_timeout:"轉寫請求逾時(伺服器無回應,已自動結束等待)",tencent_unauthenticated:"騰訊 BYOK 驗證失敗 —— 請檢查設定中的 SecretId / SecretKey",tencent_rate_limited:"騰訊 BYOK 觸發限流,請稍候再試",tencent_cos_unauthenticated:"騰訊 COS 驗證失敗 —— 請檢查 SecretId / SecretKey 與儲存桶權限",tencent_cos_forbidden:"騰訊 COS 拒絕上傳 —— 請確認 Bucket 名稱、Region 與存取政策",tencent_cos_network:"騰訊 COS 網路異常 —— 請檢查網路後重試",tencent_cos_unknown:"騰訊 COS 上傳失敗(未知錯誤)",unauthenticated_byok:"自訂憑證驗證失敗:請檢查 SecretId / SecretKey",insufficient_funds:"騰訊雲帳戶餘額不足或服務未開通",idle_timeout:"長時間無音訊,已自動斷開",rate_limited:"供應商觸發限流,請稍候再試",aliyun_invalid_audio_format:"音訊格式不被阿里 DashScope 支援,請檢查取樣率與位元深度",aliyun_quota_exceeded:"阿里 DashScope 配額已用盡",aliyun_unauthenticated:"阿里 DashScope 驗證失敗 —— 請檢查設定中的 ApiKey",aliyun_rate_limited:"阿里 DashScope 觸發限流,請稍候再試",aliyun_upload_failed:"阿里 DashScope OSS 上傳失敗:{{msg}}",aliyun_filetrans_failed:"阿里 DashScope 任務執行失敗:{{msg}}",aliyun_filetrans_timeout:"阿里 DashScope 任務逾時(>24 分鐘未返回結果)",aliyun_file_too_large:"檔案大小超過阿里 DashScope BYOK 單檔上限(預設 100MB)"},ba={aria:{dismiss:"不再顯示該提示"},recordingControls:{text:"鬆開結束 · ESC 取消"},resultActions:{text:"⌘C 複製 · 編輯 · 潤色 · 翻譯"},firstResultConfirm:{text:"已輸入 · 修正",action_correct:"正確",action_revise:"修正"}},$r={aria:da,translate:_a,mode_switch:ua,status:pa,panel:ha,toast:fa,transcript:ga,result:ma,error:ya,hints:ba},Er=Object.freeze(Object.defineProperty({__proto__:null,aria:da,default:$r,error:ya,hints:ba,mode_switch:ua,panel:ha,result:ma,status:pa,toast:fa,transcript:ga,translate:_a},Symbol.toStringTag,{value:"Module"})),va={too_long_for_utterance:"單次錄音超過 5 分鐘,UTTERANCE 模式不支援,請切換至 REALTIME 模式",aliyun_oss_upload_failed:"阿里雲 OSS 上傳失敗,憑證可能已過期或網路不穩定",aliyun_filetrans_failed:"阿里雲檔案轉寫任務失敗,請稍後重試",aliyun_file_too_large:"檔案超過 100 MB,已達阿里雲 OSS 單檔上限",tencent_cos_upload_failed:"騰訊雲 COS 上傳失敗,請檢查憑證與網路",tencent_cos_bucket_required:"需要先在聽寫設定中填寫騰訊 COS 儲存桶才能轉寫(舊憑證可能沒填)"},Sa={hero:{title_line1:"說出來。",title_line2:"就成文。",description:"按一下快捷鍵,開口說話,再按一下結束——文字即刻出現在任意應用程式中。不綁定編輯器,錄音只留本機,無任何遙測。",feature_push_to_talk:"// PUSH-TO-TALK 按鍵聽寫",feature_cross_platform:"// 跨平台 WIN · MAC · LINUX"},hotkey_hint:"按一下快捷鍵開始錄音,再按一下結束並把文字寫入目前輸入框。按 <esc>Esc</esc> 取消;焦點必須在可編輯區域。",translate_hint:"按一下翻譯快捷鍵開始錄音,再按一下結束。系統會先轉寫再翻譯為目標語言,並寫入目前輸入框。",translate_bilingual:"雙語輸出",translate_bilingual_aria:"雙語輸出(原文 + 譯文)",edit_hotkey:"編輯快捷鍵",edit_hotkey_dialog_title:"編輯快捷鍵",edit_hotkey_dialog_description:"錄入或修改目前快捷鍵綁定。",quick_dict:{button_aria:"新增詞條",title:"我的詞典",empty:"// 尚無任何詞條 //",domains_label:"// 常用領域"},hotkey_tab:{dictate:"聽寫",translate:"翻譯"},hotkey_title:{dictate:"聽寫 / PUSH-TO-TALK",translate:"翻譯 / TRANSLATE"},stats:{section_title:"今日 / 本次工作階段",section_title_today:"今日工作階段統計",section_title_all:"累計工作階段統計",tab_today:"今日",tab_all:"累計",live_metrics:"// LIVE METRICS",duration_label:"口述時長",duration_unit:"HH:MM",words_label:"口述字數",words_unit:"總計",wpm_label:"平均速度",wpm_unit:"字/分鐘",saved_label:"節省時間",saved_unit:"HH:MM",open_dialog_aria:"查看 {{label}} 詳細統計"},stats_dialog:{title:"數據統計",subtitle:"含聽寫 / 問 AI / 翻譯 · 資料僅本機",close:"關閉",range:{today:"今日","7d":"近 7 天","30d":"近 30 天","90d":"近 90 天",all:"全部"},metric_switcher_label:"聚焦",kpi:{duration:"時長",words:"字數",wpm:"WPM",saved:"節省",sessions:"次數"},main:{duration:{title:"時長走勢",hint:"每日累計錄音時長(HH:MM)"},words:{title:"字數累計",hint:"隨時間累積的總產出字數"},wpm:{title:"WPM 走勢",hint:"每日平均口述速度"},saved:{title:"節省累計",hint:"相對 {{baseline}} WPM 打字基線累計省下的時間"},sessions:{title:"次數走勢",hint:"每日聽寫工作階段數"}},facet:{heatmap:{title:"活躍時段",hint:"週一–週日 × 0–23 時;色越深用得越多",weekdays:"一,二,三,四,五,六,日"},top_apps:{title:"Top 目標應用程式",hint:"你最常在哪些應用程式裡寫字",unknown:"未知應用程式"},wpm_by_mode:{title:"WPM × 分段模式",hint:"REALTIME 與 UTTERANCE 的速度對比"},saved_equivalent:{title:"等價換算",hint:"把節省的時間換算成更直觀的單位",items:{typing_hours:"≈ 打字 {{value}}",podcasts:"≈ 聽 {{value}} 集 podcast",coffees:"≈ 喝 {{value}} 杯咖啡",books_pages:"≈ 看 {{value}} 頁書"}},session_dist:{title:"單次字數分布",hint:"短句、中段、長稿各占多少",buckets:{short:"短句 ≤ 20 字",medium:"中段 21–100 字",long:"長稿 > 100 字"}},duration_dist:{title:"單次時長分布",hint:"按一次錄音的長度分桶,看你說短句多還是說長稿多",buckets:{lt10s:"< 10 秒",s10_30:"10–30 秒",s30_60:"30–60 秒",s60_120:"1–2 分鐘",gt120s:"> 2 分鐘"}},type_mix:{title:"類型分布",hint:"你都用 OpenSpeech 做什麼——聽寫、問 AI 還是翻譯",buckets:{dictation:"聽寫",ask:"問 AI",translate:"翻譯"}},provider_dist:{title:"通道分布",hint:"不同 ASR 通道的次數與平均速度",unknown:"未知通道"},ai_refine_rate:{title:"AI 優化使用率",hint:"多少次工作階段用了 AI 整理;以及平均整理耗時",used_label:"已使用",avg_label:"平均耗時"},status_mix:{title:"成功率",hint:"成功 / 失敗 / 取消 三態占比",buckets:{success:"成功",failed:"失敗",cancelled:"已取消"}},asr_source_dist:{title:"ASR 通道分布",hint:"即時 / 檔案轉寫 / 自訂端點 各占多少",buckets:{"saas-realtime":"即時","saas-rest":"檔案轉寫",byo:"自訂",unknown:"未知"}}},empty:"// 尚無聽寫記錄,去主畫面試試 //"}},ka={title:"歷史記錄",subtitle:"歷史記錄保存在本裝置。",search_placeholder:"搜尋歷史...",more:"更多",stats:"統計",refresh:"重新整理",retention:{label:"保留時長",title:"本機歷史記錄保留多久",options:{forever:"永遠","90d":"90 天","30d":"30 天","7d":"7 天",off:"不保存"}},open_folder:"開啟錄音資料夾",open_folder_failed:"開啟錄音資料夾失敗",delete_all:"刪除全部歷史",filters:{all:"全部",dictation:"聽寫",ask:"隨便問",translate:"翻譯"},buckets:{today:"今天",yesterday:"昨天",this_week:"本週",earlier:"更早"},empty:"// 暫無記錄 //",loading_more:"// 載入更多 //",list_end:"// 已到底 · 共 {{count}} 筆 //",status:{success:"成功",failed:"失敗",cancelled:"已取消",retrying:"重新產生中"},player:{play:"播放",pause:"暫停"},row:{play:"播放原始錄音",pause:"暫停",copy:"複製到剪貼簿",copied:"已複製",reinject:"重新注入",export:"匯出音訊",delete:"刪除",retry:"重新產生",transcribe:"轉入",retrying_label:"重新產生中",retrying_placeholder:"正在重新產生轉錄…",retry_no_audio:"無可用音訊,無法重新產生",retry_too_long:"超過 5 分鐘的錄音暫不支援重新產生",retry_in_progress:"重新產生中…",retry_tooltip:"重新產生轉錄",failed_placeholder:"您的轉錄被中斷。可以重新產生一次。",cancelled_placeholder:"{{duration}} 錄音已取消,未轉寫 · 可重新轉寫",view_refined:"AI 優化",view_translation:"譯文",view_raw:"原始文字",view_details:"查看詳情",copy_debug:"複製除錯資訊"},detail:{title:"記錄詳情",description:"查看歷史記錄完整內容並執行操作",meta:{duration:"時長",target:"目標應用",error:"錯誤",warn:"備註",asr:"語音辨識",ai:"AI 優化",segment_mode:"模式",provider_kind:"通道"},asr:{"saas-realtime":"OpenLoaf SaaS · 即時辨識","saas-rest":"OpenLoaf SaaS · REST 轉寫",byo:"自訂 STT 端點"},ai:{none:"未啟用"},segment_mode:{REALTIME:"即時",UTTERANCE:"整句"},provider_kind:{"saas-realtime":"OpenLoaf 即時","saas-file":"OpenLoaf 檔案","tencent-realtime":"騰訊即時","tencent-file":"騰訊檔案","aliyun-realtime":"阿里即時","aliyun-file":"阿里檔案"},unknown:"—",empty_text:"(無文字內容)"},toast:{copy_success:"已複製到剪貼簿",copy_failed:"複製失敗",copy_debug_success:"除錯資訊已複製",copy_debug_failed:"複製除錯資訊失敗",copy_debug_missing:"該紀錄未擷取到請求快照(可能為正式版錄入或呼叫前已失敗)",retry_success:"重新產生成功",retry_failed:"重新產生失敗",delete_failed:"刪除失敗",export_success:"音訊已匯出",export_failed:"匯出失敗",refresh_failed:"重新整理失敗"},edit:{title:"修改紀錄",description:"修改這筆歷史紀錄的最終文字",edit_button:"修改",edit_tooltip:"把辨識錯的地方改對,下次更準",original_label:"原始內容(AI 給的最終版)",diff_label:"修改對比(紅色=刪除,綠色=新增)",edited_label:"你的修改",hint:"改完儲存即可,系統會非同步學習",placeholder:"在這裡修改文字…",save:"儲存",revert:"撤銷修改",revert_tooltip:"丟棄這筆紀錄的修改,回到 AI 原版",edited_chip:"已修改",edited_tooltip:"你修改過這筆紀錄的文字",toast:{save_success:"已儲存修改",save_failed:"儲存失敗",revert_success:"已恢復原版",dict_added:"已加入詞典:{{term}}",dict_updated:"已更新詞典:{{term}}",dict_removed:"已移除詞典:{{term}}",dict_hint:"AI 根據你的修改自動學習"}},confirm_clear:{title:"刪除全部歷史",description:"清空本機歷史記錄",body:"將刪除本機的 <count>{{count}}</count> 筆歷史記錄,操作不可復原。",tip:"// 建議先匯出備份",confirm:"確認刪除"}},wa={title:"詞典",subtitle:"自訂詞彙 · 最多 2,000 條",new_word:"+ 新詞",search_placeholder:"搜尋詞條...",filters:{all:"全部",domains:"常見領域",manual:"手動新增"},empty:"// 暫無詞條 //",count_total:"// 共 {{count}} 條 //",divider_label:"自訂詞條",card:{domain_tooltip:"常用領域",manual_tooltip:"手動新增",edit:"編輯",delete:"刪除"},domains:{helper:"勾選你常聊的領域,AI 會優先依這些場景調整術語與措辭",limit_hint:"最多選 {{limit}} 個",counter:"已選 {{count}} / {{limit}}",items:{programming:"軟體開發",ai_ml:"AI / 機器學習",medicine:"醫學健康",law:"法律",finance:"金融投資",academic:"學術科研",engineering:"工程製造",marketing:"行銷增長",psychology:"心理學",design:"設計創意",film_production:"影視製作",cybersecurity:"網路安全",photography:"攝影",tcm:"中醫",automotive:"汽車"}},new_dialog:{title:"新詞",description:"新增自訂詞典條目",term_label:"term",term_placeholder:"例如 OpenSpeech",error_empty:"term 不能為空",error_duplicate:"該詞條已存在",submitting:"新增中…",submit:"新增"}},xa={nav:{home:"首頁",toolbox:"翻譯 / 潤色",meetings:"會議錄製",history:"歷史",dictionary:"詞典"},account_fallback:"帳戶",login:"登入",credits:"Credits",time_left:"LEFT",time_minutes:"{{minutes}} MIN",settings:"設定",tray:{update_found_title:"發現新版本",update_none:"目前已是最新版本",update_check_failed:"檢查更新失敗"}},Oa={placeholder:"搜尋...",clear:"清空搜尋",open:"搜尋"},Ta={title:"翻譯 / 潤色",subtitle:"隨手輸入或開口說話,再潤色、翻譯、朗讀。",flow_hint:"上方給輸入 · 下方挑工具 · 即刻拿到處理後的結果",input:{section_label:"// 01 · 輸入",tabs:{text:"文字",voice:"語音",history:"歷史",file:"音訊檔案"},text_placeholder:"在這裡輸入或貼上文字…",dictate_hint:"按下快捷鍵 · 直接開口聽寫",dictate_unbound:"未綁定聽寫快捷鍵",voice_hint:"按住按鈕說話,鬆開自動轉寫。",voice_button_idle:"按住說話",voice_button_recording:"正在聆聽…",voice_recorded:"已錄製 · 0:08",history_hint:"從歷史記錄裡挑一條。",history_empty:"尚無歷史記錄。",file_hint:"拖入或選擇音訊檔案(mp3 / wav / m4a)。",file_button:"選擇音訊檔案",file_loaded:"demo.mp3 · 12s · 1.2 MB",char_count:"{{count}} 字",right_label:"文字",right_hint_voice:"來自語音轉寫",right_hint_history:"來自歷史記錄",right_hint_file:"來自音訊轉寫",right_empty:"請先在左側給一個輸入。",use_sample:"用範例文字",replaced_hint:"已替換為上一步輸出",restore_original:"還原原文",paste:"貼上",history:"歷史",clear:"清空",clipboard_detected:"偵測到剪貼簿內容",clipboard_translate:"貼上並翻譯",clipboard_fill_only:"僅貼上"},tools:{section_label:"// 02 · 工具",tabs:{polish:"潤色",translate:"翻譯",tts:"朗讀"},tutorial:{polish:{title:"潤色",headline:"按場景把口語稿改寫成成稿——郵件、微信、匯報隨你挑。"},translate:{title:"翻譯",headline:"把文字翻成另一種語言,盡量保留語氣。"},tts:{title:"朗讀",headline:"把文字合成自然的語音。"}},polish:{scenario_label:"場景",scenarios_empty:"尚未設定場景",add_scenario:"+ 新增",examples:{email:"郵件",wechat:"微信",report:"工作匯報",meeting_notes:"會議紀要",social_post:"朋友圈"}},translate:{target_label:"譯為",languages:{en:"英文",zh:"簡體中文","zh-TW":"繁體中文",ja:"日文",ko:"韓文",fr:"法文",de:"德文",es:"西班牙文"}},tts:{voice_label:"聲音",speed_label:"語速",voices:{natural_f:"自然·女聲",natural_m:"自然·男聲",calm_f:"舒緩·女聲"},audio_placeholder:"▶ ━━━━━━━━━━━━━━━━━━━━ 0:08 / 0:12"},run:"運行",run_hint:"配置好上方參數後點擊運行",ready_to_run:"就緒 · 待運行",running:"運行中…",error_title:"運行失敗",error:"失敗 · {{message}}",rerun:"重跑",copy:"複製",save_history:"保存",use_as_input:"用作輸入",download:"下載",elapsed:"{{seconds}}s",idle:"等待輸入",output_empty:"在上方填入或選擇一段輸入"},output:{idle_label:"等待執行",ready:"READY",waiting_input:"等待輸入完成…",generating:"生成中…",meta_chars:"{{count}} 字",meta_elapsed:"耗時 {{seconds}}s"},footer:{ui_only_notice:"// UI 預覽 — 業務尚未接入"}},Aa={title:"會議錄製",subtitle:"長時間錄音 · 自動分人 · 時間軸回看",idle:{hint:"點擊開始記錄",recent:"最近會議",items:"項",empty:"尚無會議記錄",empty_transcript:"(無內容)",loading:"載入中…",starting:"正在連線供應商…",language_support:"// 目前僅支援 中文 / 英語 / 粵語 / 多種方言(川、陝、豫、滬、湘、鄂、皖)"},live:{recording:"錄音中",paused:"已暫停",pause:"暫停",resume:"繼續",stop:"結束",listening:"正在聆聽...",reconnecting:"網路異常,正在重連… ({{attempt}}/{{max}})",reconnect_gave_up:"重連失敗,會議已斷開"},speaker:{label:"用戶 {{letter}}",pending:"用戶 …"},review:{back:"返回",speakers:"位說話人",delete:"刪除",delete_confirm:"確認刪除這條會議記錄?",summary:"紀要",transcript:"逐字稿",summary_topic:"會議主題",summary_speakers:"發言人",summary_abstract:"會議摘要",summary_section:"討論要點",summary_loading:"正在載入紀要…",summary_generate:"生成紀要",summary_regenerate:"重新生成",summary_failed:"紀要生成失敗",summary_idle_hint:"點上方「生成紀要」按鈕,按目前 AI 通道生成 Markdown 紀要(設定 → AI → 提示詞 → 會議紀要 可改預設提示)。",summary_empty_transcript:"本次會議沒有可總結的內容。",export:"匯出",export_default_name:"會議-{{date}}-{{shortId}}",export_md_filter:"Markdown",export_doc_title:"會議記錄",export_meta_created:"時間",export_meta_duration:"時長",export_meta_speakers:"說話人數",export_meta_segments:"段數",export_success:"已匯出至 {{path}}",export_failed:"匯出失敗"}},Pr={transcribe:va,home:Sa,history:ka,dictionary:wa,layout:xa,search_box:Oa,toolbox:Ta,meetings:Aa},Nr=Object.freeze(Object.defineProperty({__proto__:null,default:Pr,dictionary:wa,history:ka,home:Sa,layout:xa,meetings:Aa,search_box:Oa,toolbox:Ta,transcribe:va},Symbol.toStringTag,{value:"Module"})),Ra={title:"優化",empty:"暫無可優化的辨識結果",cancel:"取消",save:"優化並複製",saving:"優化中…",learn_hint:"AI 會從這次優化中學習,下次辨識更懂你",close_aria:"關閉"},Ca={saved_title:"已儲存優化",saved_description:"新文字已複製到剪貼簿,回到原輸入框貼上即可",save_failed_title:"儲存失敗"},Mr={edit_last_record:Ra,toast:Ca},jr=Object.freeze(Object.defineProperty({__proto__:null,default:Mr,edit_last_record:Ra,toast:Ca},Symbol.toStringTag,{value:"Module"})),Ia={section_index:"[04] 系統",title:"設定",subtitle:"設定聽寫、模型端點與應用程式行為。變更即時生效,無需儲存。",dialog_title:"設定",dialog_sr:"OpenSpeech 設定"},La={title:"已回退至 OpenLoaf SaaS",description:"{{which}}的自訂供應商未通過測試,已切換為雲端服務",dictation:"聽寫",ai:"AI 改寫",both:"聽寫與 AI 改寫",confirm_title:"自訂供應商未通過測試",confirm_description:"{{which}}所選的自訂供應商還沒有通過測試,無法在此模式下套用。繼續關閉設定會自動回退至 OpenLoaf SaaS 雲端服務。",confirm_back_to_test:"返回測試",confirm_proceed:"回退至 SaaS 並關閉"},$a={general:"一般",hotkeys:"快速鍵",dictation:"聽寫",model:"模型",ai:"AI",about:"關於",dev_hints:"提示偵錯"},Ea={reset_all:"重置全部",reset_all_confirm:"確定將所有快速鍵恢復為預設值?",reset_all_done:"已恢復預設快速鍵"},Pa={shortcuts:"鍵盤快速鍵",language:"語言",audio:"音訊",asr_segment:"聽寫模式",text_injection:"文字注入",behavior:"行為",model_rest:"大型模型(REST)",build:"建置",output:"輸出方式"},Na={interface_lang:"介面語言",translate_target_lang:"翻譯目標語言",translate_target_lang_hint:"翻譯聽寫快速鍵命中後,轉寫文字會被翻譯成此語言再注入到目前焦點。",translate_output_mode:"翻譯輸出形態",translate_output_mode_hint:"「雙語」保留原文並追加譯文;「僅目標語言」只輸出譯文,速度更快。",input_device:"輸入裝置",input_level:"輸入音量",input_level_hint_listening:"即時音量 · 正在監聽:{{name}}",input_level_hint:"即時麥克風音量",cue_sound:"開始/結束提示音",restore_clipboard:"貼上後還原剪貼簿",restore_clipboard_hint:"建議保持開啟",launch_startup:"開機自動啟動",close_to_tray:"關閉時最小化至系統列",close_to_tray_hint:"開啟後關閉主視窗會直接隱藏至系統列;關閉時每次都會跳出確認對話框",update_policy:"自動更新",update_policy_hint:"選擇背景發現新版本時的處理方式",update_policy_options:{prompt:"提示我安裝",auto:"閒置時自動安裝",disabled:"關閉"},loading:"// loading settings…",dictation_output_lang:"聽寫輸出語言",dictation_output_lang_hint:"聽寫轉寫出來的文字使用哪種語言。「自動」時由 ASR 自行判定,並以介面語言作為預設對照。",translate_conflict_warning:"目標語言與聽寫輸出語言相同,翻譯將無意義。"},Ma={system_default:"跟隨系統",system_default_with_current:"跟隨系統(目前:{{name}})",is_default_suffix:"{{name}} · 系統預設",disconnected_with_fallback:"{{name}} · 已中斷,暫用系統預設({{fallback}})",disconnected:"{{name}} · 已中斷"},ja={realtime_label:"即時轉換",realtime_hint:"伺服器端依停頓自動切句,錄音過程中即時回填;適合長時間會議字幕、直播轉寫等無人值守情境。",utterance_label:"整句聽寫",utterance_hint:"整段錄音視為一次完整對話,放開按鍵後再回傳轉寫結果;模型擁有完整上下文,更準確且不易被停頓誤切。",ai_refine_toggle:{label:"啟用 AI 優化",hint:"在「整句聽寫」基礎上呼叫大型模型整理:去口頭禪、消重、識別自我修正;同語言不翻譯。",disabled_in_realtime:"即時轉換模式下不可用"}},Da={streaming_inject:{label:"文字逐字輸出",hint:"預設開啟:模型邊產出,文字邊鍵入到游標位置。關閉後改為整段一次貼上,可繞過微信輸入法 / 部分全拼輸入法的逐字攔截(首字被吞、雙逗號等異常)。"},clipboard_copy:{label:"自動複製到剪貼簿",hint:"預設關閉:注入完成後會還原你原本的剪貼簿內容,不污染複製佇列。開啟後整段文字保留在剪貼簿,方便再次手動貼上。"}},Ka={byo_unavailable_tag:"// BYO-MODEL · 尚未實作",byo_unavailable_body:"自訂 STT REST 端點(端點 URL/API Key/模型名稱/測試連線)尚未接入,目前所有聽寫均走 OpenLoaf SaaS。此入口開發中,下一版本將啟用。",endpoint:"端點 URL",api_key:"API Key",api_key_hint:"儲存於系統金鑰圈;失去焦點時自動儲存",model_name:"模型名稱",timeout_seconds:"請求逾時(秒)",audio_format:"音訊格式",test_connection_disabled:"測試連線(尚未實作)",show_key:"顯示 API Key",hide_key:"隱藏 API Key",key_saved_toast:"API Key 已儲存至系統金鑰圈",key_save_failed_toast:"API Key 儲存失敗: {{error}}"},Fa={section_mode:"AI 通道",mode_saas_label:"雲端(推薦)",mode_saas_hint:"使用 OpenLoaf 已登入帳號的快速 chat 模型,依積分計費。",mode_custom_label:"自訂供應商",mode_custom_hint:"OpenAI 相容協定;自帶 API Key,可加入多個供應商但同時間僅能啟用一個。",section_providers:"自訂供應商",providers_empty:"尚未新增自訂供應商",provider_name:"名稱",provider_base_url:"Base URL",provider_model:"模型",provider_api_key:"API Key",provider_api_key_hint:"儲存於系統金鑰圈;失去焦點時自動儲存",provider_active:"目前啟用",provider_set_active:"設為啟用",provider_remove:"刪除",provider_test:"測試",provider_test_running:"測試中…",provider_test_pass:"測試通過",provider_test_fail:"測試失敗:{{message}}",provider_test_missing_fields:"Base URL 或模型未填寫",provider_test_empty_reply:"模型未回傳內容",provider_add:"新增供應商",provider_default_name:"新供應商",provider_default_base_url:"https://api.openai.com/v1",provider_default_model:"gpt-4o-mini",section_prompts:"系統提示詞",prompts_hint:"預設跟隨目前介面語言;一旦修改即視為自訂,對所有語言生效。",prompt_tab_refine:"聽寫優化",prompt_tab_translate:"翻譯",prompt_tab_polish:"潤飾",prompt_tab_meeting:"會議紀要",prompt_edit:"修改",prompt_status_custom:"已自訂",prompt_status_default:"預設",prompt_desc_refine:"鬆開聽寫按鍵後,AI 會把語音轉寫整理為更通順的書面文字(錯字、口頭禪、斷句),再注入目前的應用程式。",prompt_desc_translate:"透過「翻譯」快捷鍵觸發,把聽寫文字翻譯為上方設定的目標語言。",prompt_desc_polish:"AI 工具箱「潤飾」頁面使用,可搭配下方場景列表(電子郵件、微信等)依需切換語氣。",prompt_desc_meeting:"「會議」頁面將整段會議錄音轉寫後,依本提示詞整理為結構化紀要。",prompt_dialog_title_refine:"聽寫優化提示詞",prompt_dialog_title_translate:"翻譯提示詞",prompt_dialog_title_meeting:"會議紀要提示詞",prompt_dialog_textarea_label:"系統提示詞",polish_dialog_title:"潤飾設定",polish_dialog_subtitle:"調整潤飾用的系統提示詞,並維護 AI 工具箱中出現的場景列表。",polish_dialog_tab_prompt:"提示詞",polish_dialog_tab_scenarios:"場景",polish_dialog_prompt_label:"潤飾提示詞",polish_scenarios_title:"潤飾場景",polish_scenarios_hint:"AI 工具箱「潤飾」頁底部 chip 列表的來源;執行時會把所選場景的指示拼接到潤飾系統提示詞之後。",polish_scenarios_empty:"尚未新增潤飾場景",polish_scenario_default_name:"新場景",polish_scenario_remove:"刪除",polish_scenario_add:"新增場景",polish_scenario_instruction_placeholder:"例如:目標場景是商務郵件,語氣正式,依問候 / 正文 / 結尾分段。",refine_dialog_tab_prompt:"提示詞",refine_dialog_tab_examples:"案例",refine_dialog_tab_overrides:"依應用覆寫",refine_examples_builtin_title:"內建案例",refine_examples_builtin_hint:"{{count}} 條預設案例 · 點擊展開 · 可複製為自訂後修改",refine_example_clone:"複製",refine_rules_builtin_title:"內建規則",refine_rules_builtin_hint:"{{count}} 條預設核心規則 · 點擊展開 · 可複製為自訂後修改",refine_rules_title:"自訂規則",refine_rules_hint:"未自訂時使用內建規則;點「新增規則」或複製任一內建規則進入自訂模式。自訂模式下,執行時只送你這裡寫的規則到模型。",refine_rules_using_default:"目前使用內建規則。點下方「新增規則」或上方「複製」開始自訂。",refine_rules_empty:"已進入自訂模式但尚未新增規則——執行時將只送空 core_rules 段。",refine_rules_count:"{{current}} / {{max}}",refine_rule_add:"新增規則",refine_rule_remove:"刪除",refine_rule_clone:"複製",refine_rule_body_placeholder:"規則正文(多段以空行分隔)",refine_rule_why_placeholder:"Why —— 該規則的 rationale(可選)",refine_examples_title:"自訂案例",refine_examples_hint:"以「差的轉寫 → 期望整理」成對餵給模型;執行時依序追加在內建案例之後,越靠前優先級越高。",refine_examples_empty:"尚未新增案例",refine_examples_count:"{{current}} / {{max}}",refine_example_add:"新增案例",refine_example_remove:"刪除",refine_example_target_placeholder:"target(如 *、chat)",refine_example_focus_placeholder:"focus —— 本條重點(可選)",refine_example_input_placeholder:"input —— 原始 / 有問題的轉寫",refine_example_output_placeholder:"output —— 期望整理後的文字",app_overrides_title:"依應用覆寫",app_overrides_hint:"為特定應用單獨設定規則與案例:命中時優先使用此處規則,案例拼接在全域之前。僅匹配跑過 refine 並留下 appId 的應用。",app_overrides_empty:"尚未新增覆寫",app_overrides_count:"{{current}} / {{max}}",app_override_add:"新增覆寫",app_override_remove:"刪除",app_override_enabled:"啟用",app_override_expand:"展開",app_override_collapse:"收合",app_override_core_rules_label:"覆寫核心規則(留空沿用全域)",app_override_core_rules_clear:"清空",app_override_core_rules_placeholder:"為此應用客製的 <core_rules>...</core_rules>;留空表示沿用全域核心規則。",app_override_picker_title:"選擇要覆寫的應用",app_override_no_history:"尚無可覆寫的應用——先在該應用裡跑一次聽寫優化,讓它出現在歷史中。",prompt_reset:"恢復預設",section_history:"上下文",include_history:"把最近的歷史一同送出",include_history_hint:"把最近的 transcript 作為參考上下文,協助模型沿用一致的語氣與術語。",recent_history_count:"攜帶筆數",recent_history_count_hint:"AI 上下文最多攜帶最近多少筆歷史;筆數越多偏置越強,但 token 消耗也越多。",minutes_ago:"分鐘前",history_truncated:"省略 {{count}} 字"},za={en:"English",zh:"简体中文","zh-TW":"繁體中文",ja:"日本語",ko:"한국어",fr:"Français",de:"Deutsch",es:"Español"},Ba={target_only:"僅目標語言",bilingual:"雙語(原文 + 譯文)"},Ua={label:"聽寫語言",hint:"選擇你說話使用的語言;選「自動」讓上游 ASR 自偵測,遇歧義以介面語言對照。",follow_interface:"跟隨介面語言",auto:"自動",zh:"中文",en:"English",ja:"日本語",ko:"한국어",yue:"粵語"},Wa={section_mode:"聽寫通道",mode_saas_label:"OpenLoaf 雲端(預設)",mode_saas_hint:"使用已登入帳號走 OpenLoaf 託管的語音辨識,按點數計費。聽寫與會議轉錄共用同一通道。",mode_custom_label:"自訂供應商",mode_custom_hint:"用自己的騰訊雲 / 阿里雲金鑰直連廠商 API,不經 SaaS。會議轉錄需選擇「騰訊雲」(內建說話人分離)。",section_providers:"自訂供應商",providers_empty:"尚未新增任何自訂供應商",add_tencent:"新增騰訊雲",add_aliyun:"新增阿里雲",vendor_tencent:"騰訊雲",vendor_aliyun:"阿里雲 DashScope",active_label:"目前啟用 · {{vendor}}",set_active:"設為啟用",remove:"刪除",name_label:"名稱",tencent_default_name:"騰訊雲語音辨識",tencent_app_id:"AppID",tencent_region:"區域(Region)",tencent_secret_id:"Secret ID",tencent_secret_key:"Secret Key",tencent_credentials_hint:"憑證儲存於系統金鑰鏈;失去焦點時自動儲存。可至騰訊雲主控台 → API 金鑰管理取得。",tencent_cos_bucket_label:"COS 儲存桶",tencent_cos_bucket_placeholder:"myaudio-1234567890",tencent_cos_bucket_hint:"必填:錄音先上傳 COS 再轉寫,單檔 ≤512MB。不填則受騰訊檔案介面 base64 5MB 限制,超過後無法轉寫。",aliyun_default_name:"阿里雲 DashScope",aliyun_api_key:"ApiKey",aliyun_api_key_hint:"儲存於系統金鑰鏈;失去焦點時自動儲存。可至 DashScope 主控台取得。",test:"測試",test_running:"測試中…",test_pass:"測試通過:憑證有效",test_fail:"測試失敗:{{message}}",test_missing_fields:"必填欄位未填",verified_badge:"已驗證",unverified_badge:"未驗證",test_code:{ok:"測試通過",unauthenticated:"驗證失敗:請檢查 Secret/ApiKey 是否正確",service_not_enabled:"憑證有效,但語音辨識服務尚未在此帳號下開通",missing_fields:"必填欄位未填",network:"網路不可達,請檢查連線與防火牆",timeout:"請求逾時,請稍後重試",rate_limited:"呼叫過於頻繁",cos_unauthorized:"ASR 憑證有效,但目前 SecretId 無權存取此 COS 儲存桶",cos_not_found:"ASR 憑證有效,但 COS 儲存桶不存在或地域不符",oss_policy_failed:"ApiKey 有效,但取得 OSS 上傳憑證失敗:帳號可能未開通百煉錄音檔資源",unknown:"未知錯誤"}},Ha={version:"版本",platform:"平台",license:"授權",source:"原始碼",check_update:"檢查更新",dev_build:"目前是開發版",rerun_onboarding:"重新執行首次導覽",install_now:"立即安裝",skip_version:"略過此版本",install_in_progress:"正在下載並安裝更新…",install_progress:"{{version}} · {{percent}}% · {{downloaded}} / {{total}}",install_starting:"{{version}} · 已下載 {{downloaded}}",install_finalizing:"下載完成,正在安裝…",install_failed:"更新安裝失敗",update_channel:"更新通道",update_channel_stable:"正式版",update_channel_beta:"Beta(搶先體驗)",update_channel_hint:"Beta 通道更早收到新功能,但可能不穩定。關閉 Beta 後只會接收到版本號高於當前 Beta 的正式版。",open_log_dir:"開啟日誌目錄",saas_sdk_version:"SaaS SDK 版本"},Va={title:"互動提示偵錯",subtitle:"僅 dev 構建可見 · 用於回歸 hint 行為",global_switch:"全域顯示提示",reset_all:"全部重置",col_id:"ID",col_category:"類別",col_threshold:"閾值",col_success:"成功次數",col_dismissed:"已關閉",col_should:"應顯示",col_actions:"操作",yes:"是",no:"否",dismiss:"關閉",reset:"重置",force:"強制顯示",forcing:"強制中",note:"新增 hint 步驟:① settings.ts 加 HintId ② lib/hints.ts 註冊 HINT_REGISTRY ③ overlay.json 加文案 ④ 呼叫端掛 useHintBubble。完成後此表會自動出現。"},Dr={page:Ia,provider_rollback:La,tabs:$a,hotkeys:Ea,section:Pa,general:Na,device:Ma,asr_segment:ja,output:Da,model:Ka,ai:Fa,translate_target_lang:za,translate_output_mode:Ba,dictation_lang:Ua,dictation_provider:Wa,about:Ha,dev_hints:Va},Kr=Object.freeze(Object.defineProperty({__proto__:null,about:Ha,ai:Fa,asr_segment:ja,default:Dr,dev_hints:Va,device:Ma,dictation_lang:Ua,dictation_provider:Wa,general:Na,hotkeys:Ea,model:Ka,output:Da,page:Ia,provider_rollback:La,section:Pa,tabs:$a,translate_output_mode:Ba,translate_target_lang:za},Symbol.toStringTag,{value:"Module"})),qa="意見回饋",Ga="開啟首頁",Ya="AI 工具",Ja="歷史紀錄",Qa="設定…",Xa="選擇麥克風",Za="Auto-detect",es="Auto-detect ({{name}})",ts="字典",is="檢查更新",ns="結束 OpenSpeech",Fr={feedback:qa,open_home:Ga,open_toolbox:Ya,open_history:Ja,open_settings:Qa,mic_submenu:Xa,auto_detect:Za,auto_detect_with_name:es,open_dictionary:ts,check_update:is,quit:ns},zr=Object.freeze(Object.defineProperty({__proto__:null,auto_detect:Za,auto_detect_with_name:es,check_update:is,default:Fr,feedback:qa,mic_submenu:Xa,open_dictionary:ts,open_history:Ja,open_home:Ga,open_settings:Qa,open_toolbox:Ya,quit:ns},Symbol.toStringTag,{value:"Module"})),Br=/&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34|nbsp|#160|copy|#169|reg|#174|hellip|#8230|#x2F|#47);/g,Ur={"&":"&","&":"&","<":"<","<":"<",">":">",">":">","'":"'","'":"'",""":'"',""":'"'," ":" "," ":" ","©":"©","©":"©","®":"®","®":"®","…":"…","…":"…","/":"/","/":"/"},Wr=o=>Ur[o],Hr=o=>o.replace(Br,Wr);let ae={bindI18n:"languageChanged",bindI18nStore:"",transEmptyNodeValue:"",transSupportBasicHtmlNodes:!0,transWrapTextNodes:"",transKeepBasicHtmlNodesFor:["br","strong","i","p"],useSuspense:!0,unescape:Hr,transDefaultProps:void 0};const Vr=(o={})=>{ae={...ae,...o}},xl=()=>ae;let os;const qr=o=>{os=o},Ol=()=>os,Gr={type:"3rdParty",init(o){Vr(o.options.react),qr(o)}},Tl=["zh-CN","zh-TW","en"],Yr=Object.assign({"./locales/en/common.json":Ls,"./locales/en/dialogs.json":Es,"./locales/en/errors.json":Ns,"./locales/en/feedback.json":js,"./locales/en/hotkey.json":Ks,"./locales/en/onboarding.json":zs,"./locales/en/overlay.json":Us,"./locales/en/pages.json":Hs,"./locales/en/quickPanel.json":qs,"./locales/en/settings.json":Ys,"./locales/en/tray.json":Qs,"./locales/zh-CN/common.json":Zs,"./locales/zh-CN/dialogs.json":tr,"./locales/zh-CN/errors.json":nr,"./locales/zh-CN/feedback.json":ar,"./locales/zh-CN/hotkey.json":rr,"./locales/zh-CN/onboarding.json":cr,"./locales/zh-CN/overlay.json":_r,"./locales/zh-CN/pages.json":pr,"./locales/zh-CN/quickPanel.json":fr,"./locales/zh-CN/settings.json":mr,"./locales/zh-CN/tray.json":br,"./locales/zh-TW/common.json":Sr,"./locales/zh-TW/dialogs.json":wr,"./locales/zh-TW/errors.json":Or,"./locales/zh-TW/feedback.json":Ar,"./locales/zh-TW/hotkey.json":Cr,"./locales/zh-TW/onboarding.json":Lr,"./locales/zh-TW/overlay.json":Er,"./locales/zh-TW/pages.json":Nr,"./locales/zh-TW/quickPanel.json":jr,"./locales/zh-TW/settings.json":Kr,"./locales/zh-TW/tray.json":zr}),se={"zh-CN":{},"zh-TW":{},en:{}},as=new Set;for(const[o,e]of Object.entries(Yr)){const t=o.match(/\.\/locales\/([^/]+)\/([^/]+)\.json$/);if(!t)continue;const i=t[1],n=t[2];i in se&&(se[i][n]=e.default,as.add(n))}function ss(){const o=typeof navigator<"u"&&navigator.language||"en";return o.toLowerCase().startsWith("zh")?/-(tw|hk|mo)$/i.test(o)||/hant/i.test(o)?"zh-TW":"zh-CN":"en"}function Al(o){return o==="system"?ss():o}const Jr=ss();g.use(Gr).init({resources:se,lng:Jr,fallbackLng:"en",ns:Array.from(as),defaultNS:"common",interpolation:{escapeValue:!1},returnNull:!1});let D=null;function Qr(){if(D)return D;const o=typeof navigator<"u"?navigator.userAgent.toLowerCase():"";return o.includes("mac")?D="macos":o.includes("win")?D="windows":D="linux",D}const Oe=["fn","ctrl","alt","shift","meta"],N=["dictate_ptt","translate","show_main_window","open_toolbox","edit_last_record"];function Xr(o){let e,t;return o==="macos"?(e={kind:"modifierOnly",mods:["fn","ctrl"],code:"",modSides:{ctrl:"left"}},t={kind:"modifierOnly",mods:["fn","shift"],code:"",modSides:{shift:"left"}}):o==="windows"?(e={kind:"modifierOnly",mods:["alt","meta"],code:"",modSides:{alt:"left",meta:"left"}},t={kind:"modifierOnly",mods:["ctrl"],code:"",modSides:{ctrl:"right"}}):(e={kind:"modifierOnly",mods:["ctrl","meta"],code:"",modSides:{ctrl:"left",meta:"left"}},t={kind:"modifierOnly",mods:["alt","meta"],code:"",modSides:{alt:"left",meta:"left"}}),{dictate_ptt:e,translate:t,show_main_window:{kind:"combo",mods:["shift","meta"],code:"KeyO",modSides:{shift:"left",meta:"left"}},open_toolbox:{kind:"combo",mods:["shift","meta"],code:"KeyT",modSides:{shift:"left",meta:"left"}},edit_last_record:o==="macos"?{kind:"combo",mods:["shift","meta"],code:"KeyE",modSides:{shift:"left",meta:"left"}}:{kind:"combo",mods:["ctrl","shift"],code:"KeyE",modSides:{ctrl:"left",shift:"left"}}}}new Proxy({},{get(o,e){return Xr(Qr())[e]},has(o,e){return N.includes(e)},ownKeys(){return[...N]},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}}});const Zr=new Proxy({},{get(o,e){if(N.includes(e))return g.t(`hotkey:binding.${e}`)},has(o,e){return N.includes(e)},ownKeys(){return[...N]},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}}});function Rl(o){return[...new Set(o)].sort((e,t)=>Oe.indexOf(e)-Oe.indexOf(t))}const le={ControlLeft:{mod:"ctrl",side:"left"},ControlRight:{mod:"ctrl",side:"right"},AltLeft:{mod:"alt",side:"left"},AltRight:{mod:"alt",side:"right"},ShiftLeft:{mod:"shift",side:"left"},ShiftRight:{mod:"shift",side:"right"},MetaLeft:{mod:"meta",side:"left"},MetaRight:{mod:"meta",side:"right"},OSLeft:{mod:"meta",side:"left"},OSRight:{mod:"meta",side:"right"},Fn:{mod:"fn",side:null}};function el(o){return le[o]?.mod??null}function tl(o){return le[o]?.side??null}function il(o){return o in le}function re(o,e){return e==="fn"?null:o.modSides?.[e]??"left"}const nl=["Tab","Backspace","Delete","CapsLock","NumLock","ScrollLock"],ol=["Escape","Enter","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"];function al(o,e,t=!1){return il(o)?{ok:!1,reason:g.t("hotkey:validation.needs_main_key")}:nl.includes(o)?{ok:!1,reason:g.t("hotkey:validation.combo_disallowed_main")}:!t&&ol.includes(o)?{ok:!1,reason:g.t("hotkey:validation.special_keys_locked")}:e.length===0&&cl(o)?{ok:!1,reason:g.t("hotkey:validation.typing_key_needs_modifier")}:{ok:!0}}function sl(o,e,t=!1){return o.mods.includes("fn")&&e!=="macos"?{ok:!1,reason:g.t("hotkey:validation.fn_macos_only")}:o.kind==="modifierOnly"?o.code!==""?{ok:!1,reason:g.t("hotkey:validation.modifier_only_no_main")}:o.mods.length<1?{ok:!1,reason:g.t("hotkey:validation.modifier_only_min")}:{ok:!0}:o.kind==="doubleTap"?o.code!==""?{ok:!1,reason:g.t("hotkey:validation.double_tap_no_main")}:o.mods.length!==1?{ok:!1,reason:g.t("hotkey:validation.double_tap_single_mod")}:e==="macos"&&o.mods[0]==="fn"?{ok:!1,reason:g.t("hotkey:validation.double_tap_fn_macos")}:{ok:!0}:o.mods.includes("fn")?{ok:!1,reason:g.t("hotkey:validation.combo_no_fn")}:al(o.code,o.mods,t)}function rl(o,e){return e?`${o}:${e}`:o}function Te(o){const e=new Set;for(const t of o.mods)e.add(rl(t,re(o,t)));return e}function U(o,e){if(o.size>=e.size)return!1;for(const t of o)if(!e.has(t))return!1;return!0}function ll(o,e,t){const i=Te(e),n=new Set(e.mods);for(const a of N){if(a===t)continue;const s=o[a];if(!s)continue;if(hl(s,e))return{kind:"equal",with:a};const r=Te(s);if(e.kind==="modifierOnly"&&s.kind==="modifierOnly"&&(U(i,r)||U(r,i)))return{kind:"subset_modifier_only",with:a};if(e.kind==="modifierOnly"&&s.kind==="combo"&&(U(i,r)||i.size===r.size)&&U(i,r))return{kind:"subset_combo",with:a};if(e.kind==="combo"&&s.kind==="modifierOnly"&&U(r,i))return{kind:"subset_combo",with:a};if(e.kind==="doubleTap"&&s.kind==="modifierOnly"){const l=e.mods[0];if(l&&s.mods.includes(l))return{kind:"double_tap_overlap_modifier",with:a}}if(e.kind==="modifierOnly"&&s.kind==="doubleTap"){const l=s.mods[0];if(l&&n.has(l))return{kind:"double_tap_overlap_modifier",with:a}}}return null}function Cl(o,e,t){const i=[],n=new Set;for(const a of N){const s=o[a];if(!s)continue;const r=sl(s,e,t);if(!r.ok){i.push({id:a,error:r.reason??""}),n.add(a);continue}const l=ll(o,s,a);if(l&&!n.has(a)){const c=g.t(`dialogs:hotkey_field.conflict_reason.${l.kind}`,{name:Zr[l.with]});i.push({id:a,error:c}),n.add(a)}}return i}function Il(o,e){const t=[];return e==="macos"&&o.kind==="combo"&&o.mods.length===0&&/^F([1-9]|1[0-2])$/.test(o.code)&&t.push("hotkey:warning.f_key_bare"),o.kind==="modifierOnly"&&o.mods.length===1&&t.push(`hotkey:warning.modifier_only_single_${e}`),o.kind==="combo"&&dl(o,e)&&t.push("hotkey:warning.system_shortcut"),t}function cl(o){return/^Key[A-Z]$/.test(o)||/^Digit\d$/.test(o)||/^Numpad\d$/.test(o)||o==="Space"?!0:["Backquote","Minus","Equal","BracketLeft","BracketRight","Backslash","Semicolon","Quote","Comma","Period","Slash","IntlBackslash","IntlRo","IntlYen","NumpadAdd","NumpadSubtract","NumpadMultiply","NumpadDivide","NumpadDecimal"].includes(o)}function dl(o,e){const t=new Set(o.mods),i=(...n)=>t.size===n.length&&n.every(a=>t.has(a));return e==="macos"?!!(i("meta")&&["KeyQ","KeyW","KeyH","KeyM","Tab","Space"].includes(o.code)||i("meta","shift")&&["Digit3","Digit4","Digit5"].includes(o.code)||i("ctrl","meta")&&o.code==="KeyQ"||i("meta","alt")&&o.code==="Escape"):e==="windows"?!!(i("meta")&&["KeyL","KeyD","KeyE","KeyR","Tab","KeyH","KeyI","KeyS"].includes(o.code)||i("alt")&&o.code==="F4"||i("alt")&&o.code==="Tab"||i("ctrl","alt")&&o.code==="Delete"):!1}const _l={ctrl:"Ctrl",alt:"Option",shift:"Shift",meta:"Cmd",fn:"fn"},ul={ctrl:"Ctrl",alt:"Alt",shift:"Shift",meta:"Win",fn:"Fn"},pl={ctrl:"Ctrl",alt:"Alt",shift:"Shift",meta:"Super",fn:"Fn"};function Y(o,e){return e==="macos"?_l[o]:e==="windows"?ul[o]:pl[o]}const Ae={Space:"Space",Enter:"Enter",Escape:"Esc",Tab:"Tab",Backspace:"⌫",Delete:"Del",ArrowUp:"↑",ArrowDown:"↓",ArrowLeft:"←",ArrowRight:"→",Backquote:"`",Minus:"-",Equal:"=",BracketLeft:"[",BracketRight:"]",Backslash:"\\",Semicolon:";",Quote:"'",Comma:",",Period:".",Slash:"/",IntlBackslash:"\\",IntlRo:"\\",IntlYen:"¥"};function rs(o){return Ae[o]?Ae[o]:/^Key([A-Z])$/.test(o)?o.slice(3):/^Digit(\d)$/.test(o)?o.slice(5):/^Numpad(.+)$/.test(o)?`Num${o.slice(6)}`:o}function Ll(o,e){if(!o)return g.t("hotkey:format.unbound");const t=e==="macos"?" ":" + ";return o.kind==="modifierOnly"?o.mods.map(n=>Y(n,e)).join(t):o.kind==="doubleTap"?g.t("hotkey:format.double_tap",{mod:Y(o.mods[0],e)}):[...o.mods.map(n=>Y(n,e)),rs(o.code)].join(t)}function hl(o,e){if(o===null&&e===null)return!0;if(o===null||e===null||o.kind!==e.kind||o.code!==e.code||o.mods.length!==e.mods.length||!o.mods.every((t,i)=>t===e.mods[i]))return!1;for(const t of o.mods)if(re(o,t)!==re(e,t))return!1;return!0}const fl=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],$l=Z("check",fl);const gl=[["path",{d:"M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3",key:"11bfej"}]],ml=Z("command",gl);const yl=[["path",{d:"M2.7 10.3a2.41 2.41 0 0 0 0 3.41l7.59 7.59a2.41 2.41 0 0 0 3.41 0l7.59-7.59a2.41 2.41 0 0 0 0-3.41l-7.59-7.59a2.41 2.41 0 0 0-3.41 0Z",key:"1f1r0c"}]],bl=Z("diamond",yl);const vl=[["path",{d:"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72",key:"ul74o6"}],["path",{d:"m14 7 3 3",key:"1r5n42"}],["path",{d:"M5 6v4",key:"ilb8ba"}],["path",{d:"M19 14v4",key:"blhpug"}],["path",{d:"M10 2v2",key:"7u0qdc"}],["path",{d:"M7 8H3",key:"zfb6yr"}],["path",{d:"M21 16h-4",key:"1cnmox"}],["path",{d:"M11 3H9",key:"1obp7u"}]],El=Z("wand-sparkles",vl);function ls(o,e){return!(o==="fn"||o==="meta"&&e==="windows")}function Pl(o,e,t){return t&&ls(o,e)?t:null}function Sl({size:o=14}){return $.jsxs("svg",{width:o,height:o,viewBox:"0 0 16 16",fill:"currentColor",xmlns:"http://www.w3.org/2000/svg","aria-hidden":!0,children:[$.jsx("path",{d:"M1 3.5l5.5-.75v5.5H1V3.5z"}),$.jsx("path",{d:"M7.5 2.5L15 1v7H7.5V2.5z"}),$.jsx("path",{d:"M1 9h5.5v5.5L1 13.5V9z"}),$.jsx("path",{d:"M7.5 9H15v7l-7.5-1.5V9z"})]})}function Nl(o,e,t=14){return o==="fn"?null:e==="macos"?o==="ctrl"?"⌃":o==="shift"?"⇧":o==="alt"?"⌥":o==="meta"?$.jsx(ml,{size:t,strokeWidth:2.5}):null:o==="meta"?e==="windows"?$.jsx(Sl,{size:t}):$.jsx(bl,{size:Math.max(t-2,8),strokeWidth:2.5}):null}const kl={Enter:"↵",Escape:"⎋",Tab:"⇥",Delete:"⌦",Space:"␣"};function Ml(o){return kl[o]??null}const Re={Space:"Space",Enter:"Enter",Escape:"Esc",Tab:"Tab",Backspace:"Backspace",Delete:"Del",CapsLock:"Caps",ArrowUp:"↑",ArrowDown:"↓",ArrowLeft:"←",ArrowRight:"→"};function jl(o,e){const t=el(o);if(t){const i=Y(t,e),n=tl(o);return n&&ls(t,e)?`${n==="left"?"Left":"Right"} ${i}`:i}return Re[o]?Re[o]:rs(o)}export{Sl as A,N as B,$l as C,bl as D,kl as M,Tl as S,El as W,Ol as a,Xr as b,il as c,Qr as d,el as e,Ll as f,xl as g,tl as h,g as i,al as j,K as k,sl as l,ll as m,Rl as n,Il as o,Zr as p,Pl as q,Al as r,Y as s,re as t,Hr as u,rs as v,Nl as w,Ml as x,jl as y,Cl as z};
|