directus-extension-translation
Version:
A powerful Directus extension module for managing translations with Excel-like inline editing, instant search, and multi-language support. Features include server-side pagination, batch saving, and a modern UI optimized for translation workflows.
2 lines (1 loc) • 21.9 kB
JavaScript
import{useApi as a,defineModule as e}from"@directus/extensions-sdk";import{defineComponent as n,ref as t,watch as l,computed as d,resolveComponent as o,createBlock as r,openBlock as i,withCtx as s,createVNode as u,createElementVNode as c,createCommentVNode as v,createElementBlock as b,Fragment as g,renderList as p,createTextVNode as h,onMounted as m,toDisplayString as f,withKeys as y,normalizeClass as k}from"vue";const x={class:"header-content"},w={class:"form-section"},V={class:"form-section"},_={class:"translations-grid"};var T=n({__name:"AddKeyDialog",props:{modelValue:{type:Boolean},languages:{}},emits:["update:modelValue","add-key"],setup(a,{emit:e}){const n=a,m=e,f=t(!1),y=t({key:"",translations:{}});l(()=>n.languages,a=>{y.value.translations={},a.forEach(a=>{y.value.translations[a]=""})},{immediate:!0});const k=d(()=>{if(!y.value.key)return"Key is required";return new RegExp("^[a-z][a-z0-9_]*$").test(y.value.key)?null:"Key must start with lowercase letter and contain only lowercase letters, numbers, and underscores"}),T=d(()=>y.value.key&&!k.value&&Object.values(y.value.translations).some(a=>a.trim())),C=a=>({"vi-VN":"Tiếng Việt","en-US":"English (US)","ko-KR":"Korean","zh-CN":"Chinese (Simplified)"}[a]||a),K=async()=>{if(T.value){f.value=!0;try{m("add-key",{key:y.value.key,translations:y.value.translations}),y.value.key="",y.value.translations={},m("update:modelValue",!1)}catch(a){console.error("Failed to add key:",a)}finally{f.value=!1}}};return(a,e)=>{const n=o("v-icon"),t=o("v-button"),l=o("v-card-title"),d=o("v-input"),m=o("v-textarea"),S=o("v-form"),E=o("v-card-text"),U=o("v-card-actions"),j=o("v-card"),F=o("v-dialog");return i(),r(F,{"model-value":a.modelValue,"onUpdate:modelValue":e[3]||(e[3]=e=>a.$emit("update:modelValue",e)),persistent:"","max-width":"600"},{default:s(()=>[u(j,{class:"add-key-dialog"},{default:s(()=>[u(l,{class:"dialog-header"},{default:s(()=>[c("div",x,[u(n,{name:"add",size:"large",class:"header-icon"}),e[4]||(e[4]=c("span",{class:"header-title"},"Add New Translation Key",-1))]),u(t,{icon:"close",onClick:e[0]||(e[0]=e=>a.$emit("update:modelValue",!1)),class:"close-btn",variant:"text"})]),_:1}),u(E,{class:"dialog-content"},{default:s(()=>[u(S,{onSubmit:K,class:"add-key-form"},{default:s(()=>[v(" Key Input "),c("div",w,[u(d,{modelValue:y.value.key,"onUpdate:modelValue":e[1]||(e[1]=a=>y.value.key=a),label:"Translation Key",placeholder:"Enter translation key (e.g., 'new_feature')",validation:k.value,required:"",class:"key-input"},null,8,["modelValue","validation"]),e[5]||(e[5]=c("div",{class:"input-hint"}," Use lowercase with underscores (e.g., 'my_new_feature') ",-1))]),v(" Language Translations "),c("div",V,[e[6]||(e[6]=c("h3",{class:"section-title"},"Translation Values",-1)),c("div",_,[(i(!0),b(g,null,p(a.languages,a=>(i(),b("div",{key:a,class:"translation-field"},[u(m,{modelValue:y.value.translations[a],"onUpdate:modelValue":e=>y.value.translations[a]=e,label:C(a),placeholder:`Enter ${C(a)} translation`,rows:"3",class:"translation-textarea"},null,8,["modelValue","onUpdate:modelValue","label","placeholder"])]))),128))])])]),_:1})]),_:1}),u(U,{class:"dialog-actions"},{default:s(()=>[u(t,{onClick:e[2]||(e[2]=e=>a.$emit("update:modelValue",!1)),variant:"outlined",class:"cancel-btn"},{default:s(()=>e[7]||(e[7]=[h(" Cancel ",-1)])),_:1,__:[7]}),u(t,{onClick:K,loading:f.value,disabled:!T.value,class:"save-btn"},{default:s(()=>[u(n,{name:"save"}),e[8]||(e[8]=h(" Save Translations ",-1))]),_:1,__:[8]},8,["loading","disabled"])]),_:1})]),_:1})]),_:1},8,["model-value"])}}}),C=[],K=[];function S(a,e){if(a&&"undefined"!=typeof document){var n,t=!0===e.prepend?"prepend":"append",l=!0===e.singleTag,d="string"==typeof e.container?document.querySelector(e.container):document.getElementsByTagName("head")[0];if(l){var o=C.indexOf(d);-1===o&&(o=C.push(d)-1,K[o]={}),n=K[o]&&K[o][t]?K[o][t]:K[o][t]=r()}else n=r();65279===a.charCodeAt(0)&&(a=a.substring(1)),n.styleSheet?n.styleSheet.cssText+=a:n.appendChild(document.createTextNode(a))}function r(){var a=document.createElement("style");if(a.setAttribute("type","text/css"),e.attributes)for(var n=Object.keys(e.attributes),l=0;l<n.length;l++)a.setAttribute(n[l],e.attributes[n[l]]);var o="prepend"===t?"afterbegin":"beforeend";return d.insertAdjacentElement(o,a),a}}S(".add-key-dialog[data-v-88e2638c] {\n border-radius: 12px;\n overflow: hidden;\n}\n\n.dialog-header[data-v-88e2638c] {\n background: linear-gradient(135deg, var(--theme--primary) 0%, var(--theme--primary-dark) 100%);\n color: white;\n padding: 20px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.dialog-header .header-content[data-v-88e2638c] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n.dialog-header .header-content .header-icon[data-v-88e2638c] {\n color: white;\n}\n.dialog-header .header-content .header-title[data-v-88e2638c] {\n font-size: 18px;\n font-weight: 600;\n}\n.dialog-header .close-btn[data-v-88e2638c] {\n color: white;\n}\n.dialog-header .close-btn[data-v-88e2638c]:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.dialog-content[data-v-88e2638c] {\n padding: 24px;\n max-height: 70vh;\n overflow-y: auto;\n}\n\n.add-key-form .form-section[data-v-88e2638c] {\n margin-bottom: 24px;\n}\n.add-key-form .form-section .section-title[data-v-88e2638c] {\n font-size: 16px;\n font-weight: 600;\n color: var(--theme--foreground);\n margin-bottom: 16px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--theme--border);\n}\n.add-key-form .form-section .key-input[data-v-88e2638c] {\n margin-bottom: 8px;\n}\n.add-key-form .form-section .input-hint[data-v-88e2638c] {\n font-size: 12px;\n color: var(--theme--foreground-subdued);\n margin-top: 4px;\n}\n.add-key-form .form-section .translations-grid[data-v-88e2638c] {\n display: grid;\n gap: 16px;\n}\n.add-key-form .form-section .translations-grid .translation-field .translation-textarea [data-v-88e2638c] .v-textarea__input {\n min-height: 80px;\n}\n\n.dialog-actions[data-v-88e2638c] {\n padding: 16px 24px;\n background: var(--theme--background-subdued);\n border-top: 1px solid var(--theme--border);\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n}\n.dialog-actions .cancel-btn[data-v-88e2638c] {\n min-width: 100px;\n}\n.dialog-actions .save-btn[data-v-88e2638c] {\n min-width: 140px;\n background: var(--theme--primary);\n color: white;\n}\n.dialog-actions .save-btn[data-v-88e2638c]:hover {\n background: var(--theme--primary-dark);\n}\n.dialog-actions .save-btn[data-v-88e2638c]:disabled {\n opacity: 0.6;\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n .dialog-content[data-v-88e2638c] {\n padding: 16px;\n }\n .dialog-actions[data-v-88e2638c] {\n padding: 12px 16px;\n flex-direction: column;\n }\n .dialog-actions .cancel-btn[data-v-88e2638c],\n .dialog-actions .save-btn[data-v-88e2638c] {\n width: 100%;\n }\n}",{});var E=(a,e)=>{const n=a.__vccOpts||a;for(const[a,t]of e)n[a]=t;return n},U=E(T,[["__scopeId","data-v-88e2638c"]]);const j={class:"translation-manager"},F={class:"language-selection"},z={class:"language-selection-content"},N={class:"search-language-row"},O={class:"language-checkboxes"},A={key:0,class:"pagination-controls"},B={class:"pagination-info"},L={key:1,class:"translation-table"},$={key:0,class:"empty-row"},D={class:"key-cell"},M=["data-language"],R={class:"key-cell"},q=["data-key"],I=["data-key","data-language"],P={key:2,class:"loading-state"},H={key:3,class:"error-state"},G={key:0,class:"pagination-controls"},J={class:"pagination-info"},Q=50;var W=n({__name:"module",setup(e){const n=a(),x=t(!1),w=t(""),V=t([]),_=t([]),T=t([]),C=t([]),K=t({});t({});const S=t(!1),E=t(!0),W=t(!1),X=t(!1),Y=t(1),Z=t(0),aa=d(()=>Math.ceil(Z.value/Q)),ea=d(()=>V.value),na=t("");let ta=null;const la=()=>{na.value=""},da=d(()=>Object.keys(K.value).length>0),oa=async a=>{x.value=!0,w.value="";try{const e={page:a,limit:Q,sort:["key"]};na.value&&(e.search=na.value);const t=await n.get("/translations",{params:e}),l=t.data.data||t.data,d={};l.forEach(a=>{d[a.key]||(d[a.key]={key:a.key,translations:{}}),d[a.key].translations[a.language]=a.value}),V.value=Object.values(d).sort((a,e)=>a.key.localeCompare(e.key)),_.value=l}catch(a){console.error("Failed to load translations:",a),w.value="Failed to load translations"}finally{x.value=!1}},ra=async()=>{x.value=!0,w.value="";try{const a={aggregate:{countDistinct:"id"}};na.value&&(a.search=na.value);const e=await n.get("/translations",{params:a});Z.value=e.data.data?.[0]?.countDistinct?.id||0,await oa(1)}catch(a){console.error("Failed to load translations:",a),w.value="Failed to load translations"}finally{x.value=!1}},ia=a=>{const e=a.target,n=e.textContent?.trim()||"",t=e.dataset.key||"";n&&n!==t&&(t?pa(t,n):ga(n))},sa=a=>{a.preventDefault();a.target.blur()},ua=a=>{const e=a.target,n=e.dataset.key||"",t=e.dataset.language||"",l=e.textContent?.trim()||"";if(n&&t){const a=va(n,t);l!==a&&ba(n,t,a,l)}},ca=a=>{a.preventDefault();a.target.blur()},va=(a,e)=>{const n=V.value.find(e=>e.key===a);return n?.translations[e]||""},ba=(a,e,n,t)=>{K.value[a]||(K.value[a]={}),K.value[a][e]={oldValue:n,newValue:t}},ga=a=>{const e={key:a,translations:{}};V.value.unshift(e),E.value=!1,setTimeout(()=>{E.value=!0},100)},pa=(a,e)=>{const n=V.value.find(e=>e.key===a);n&&(n.key=e)},ha=async()=>{if(da.value){S.value=!0,w.value="";try{const a=[];for(const[e,t]of Object.entries(K.value))for(const[l,d]of Object.entries(t)){const t=ma(e,l);t?a.push(n.patch(`/translations/${t}`,{value:d.newValue})):a.push(n.post("/translations",{key:e,language:l,value:d.newValue}))}await Promise.all(a),K.value={},await ra()}catch(a){console.error("Failed to save changes:",a),w.value=a?.message||"Failed to save changes"}finally{S.value=!1}}},ma=(a,e)=>{const n=_.value.find(n=>n.key===a&&n.language===e);return n?.id||null},fa=async a=>{W.value=!0;try{for(const[e,t]of Object.entries(a.translations))t.trim()&&await n.post("/translations",{key:a.key,language:e,value:t.trim()});await ra(),X.value=!1}catch(a){console.error("Failed to add key:",a),w.value=a?.message||"Failed to add key"}finally{W.value=!1}};return l(Y,async a=>{a>0&&Z.value>0&&await oa(a)}),l(na,a=>{ta&&clearTimeout(ta),ta=setTimeout(()=>{Y.value=1,ra()},400)}),m(()=>{ra(),(async()=>{try{const a=await n.get("/items/languages"),e=a.data.data||a.data;T.value=e.map(a=>({value:a.code||a.id,text:a.name||a.display_name||a.code||a.id})),C.value=T.value.map(a=>a.value)}catch(a){console.error("Failed to load languages:",a),T.value=[{value:"vi-VN",text:"Tiếng Việt"},{value:"en-US",text:"English (US)"},{value:"ko-KR",text:"ko-KR"},{value:"zh-CN",text:"zh-CN"}],C.value=T.value.map(a=>a.value)}})()}),(a,e)=>{const n=o("v-icon"),t=o("v-button"),l=o("v-input"),d=o("v-checkbox"),m=o("v-pagination"),V=o("v-progress-circular"),_=o("v-notice"),W=o("private-view");return i(),r(W,{title:"Translation Manager"},{actions:s(()=>[x.value?v("v-if",!0):(i(),r(t,{key:0,rounded:"",icon:"",tooltip:da.value?"Save All Changes":"No changes to save",loading:S.value,disabled:!da.value,onClick:ha},{default:s(()=>[u(n,{name:"check"})]),_:1},8,["tooltip","loading","disabled"]))]),default:s(()=>[c("div",j,[v(" Language Selection "),c("div",F,[e[4]||(e[4]=c("h3",null,"Select Languages:",-1)),c("div",z,[c("div",N,[u(l,{modelValue:na.value,"onUpdate:modelValue":e[0]||(e[0]=a=>na.value=a),placeholder:"Search translation key...",clearable:"",onClear:la,class:"search-key-input","prepend-icon":"search"},null,8,["modelValue"])]),c("div",O,[(i(!0),b(g,null,p(T.value,a=>(i(),r(d,{key:a.value,"model-value":C.value.includes(a.value),"onUpdate:modelValue":e=>(a=>{const e=C.value.indexOf(a);e>-1?C.value.splice(e,1):C.value.push(a)})(a.value),label:a.text},null,8,["model-value","onUpdate:modelValue","label"]))),128))])])]),v(" Pagination Controls (Top) "),!x.value&&aa.value>1?(i(),b("div",A,[c("div",B," Showing "+f((Y.value-1)*Q+1)+" - "+f(Math.min(Y.value*Q,Z.value))+" of "+f(Z.value)+" items ",1),u(m,{modelValue:Y.value,"onUpdate:modelValue":e[1]||(e[1]=a=>Y.value=a),length:aa.value,"total-visible":5,"show-first-last":!0},null,8,["modelValue","length"])])):v("v-if",!0),v(" Translation Table "),x.value?v("v-if",!0):(i(),b("div",L,[c("table",null,[c("thead",null,[c("tr",null,[e[5]||(e[5]=c("th",{class:"key-header"},"Translation Key",-1)),(i(!0),b(g,null,p(C.value,a=>(i(),b("th",{key:a,class:"language-header"},f((a=>{const e=T.value.find(e=>e.value===a);return e?e.text:a})(a)),1))),128))])]),c("tbody",null,[v(" Empty row for adding new keys "),E.value?(i(),b("tr",$,[c("td",D,[c("div",{class:"editable-key",contenteditable:"true",onBlur:ia,onKeydown:y(sa,["enter"]),placeholder:"Enter new key..."},null,32)]),(i(!0),b(g,null,p(C.value,a=>(i(),b("td",{key:a,class:"translation-cell"},[c("div",{class:"editable-translation",contenteditable:"true",onBlur:ua,onKeydown:y(ca,["enter"]),"data-key":"","data-language":a,placeholder:"Enter translation..."},null,40,M)]))),128))])):v("v-if",!0),v(" Translation rows "),(i(!0),b(g,null,p(ea.value,a=>(i(),b("tr",{key:a.key,class:"translation-row"},[c("td",R,[c("div",{class:"editable-key",contenteditable:"true",onBlur:ia,onKeydown:y(sa,["enter"]),"data-key":a.key},f(a.key),41,q)]),(i(!0),b(g,null,p(C.value,e=>{return i(),b("td",{key:e,class:"translation-cell"},[c("div",{class:k(["editable-translation",{"has-changes":(n=a.key,t=e,!!K.value[n]?.[t])}]),contenteditable:"true",onBlur:ua,onKeydown:y(ca,["enter"]),"data-key":a.key,"data-language":e},f(a.translations[e]||""),43,I)]);var n,t}),128))]))),128))])])])),v(" Loading State "),x.value?(i(),b("div",P,[u(V,{indeterminate:""}),e[6]||(e[6]=c("p",null,"Loading translations...",-1))])):v("v-if",!0),v(" Error State "),w.value?(i(),b("div",H,[u(_,{type:"danger"},{default:s(()=>[h(f(w.value),1)]),_:1})])):v("v-if",!0)]),u(U,{modelValue:X.value,"onUpdate:modelValue":e[2]||(e[2]=a=>X.value=a),languages:C.value,onAddKey:fa},null,8,["modelValue","languages"]),!x.value&&aa.value>1?(i(),b("div",G,[c("div",J," Showing "+f((Y.value-1)*Q+1)+" - "+f(Math.min(Y.value*Q,Z.value))+" of "+f(Z.value)+" items ",1),u(m,{modelValue:Y.value,"onUpdate:modelValue":e[3]||(e[3]=a=>Y.value=a),length:aa.value,"total-visible":5,"show-first-last":!0},null,8,["modelValue","length"])])):v("v-if",!0)]),_:1})}}});S('/* Hide sidebar */\n[data-v-4b0f8dd0] .module-nav.alt-colors {\n display: none !important;\n}\n\n[data-v-4b0f8dd0] .private-view__sidebar {\n display: none !important;\n}\n\n[data-v-4b0f8dd0] .private-view__content {\n padding-left: 0 !important;\n}\n\n.translation-manager[data-v-4b0f8dd0] {\n padding: 20px;\n max-width: 100%;\n overflow-x: auto;\n}\n\n.language-selection[data-v-4b0f8dd0] {\n margin-bottom: 20px;\n padding: 16px;\n background: var(--theme--background-subdued);\n border-radius: 8px;\n}\n.language-selection h3[data-v-4b0f8dd0] {\n margin-bottom: 12px;\n color: var(--theme--foreground);\n}\n\n.search-language-row[data-v-4b0f8dd0] {\n margin-bottom: 0;\n display: flex;\n align-items: center;\n}\n.search-language-row .search-key-input[data-v-4b0f8dd0] {\n width: 320px;\n max-width: 100%;\n}\n\n.language-checkboxes[data-v-4b0f8dd0] {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n align-items: center;\n}\n\n.language-selection-content[data-v-4b0f8dd0] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.translation-table[data-v-4b0f8dd0] {\n width: 100%;\n overflow-x: auto;\n background: var(--theme--background);\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n /* Fixed column widths */\n /* Key column styling for long text */\n /* Editable content styling */\n}\n.translation-table table[data-v-4b0f8dd0] {\n width: 100%;\n border-collapse: collapse;\n table-layout: fixed;\n}\n.translation-table th[data-v-4b0f8dd0] {\n background: var(--theme--background-subdued);\n font-weight: 600;\n color: var(--theme--foreground);\n padding: 12px 16px;\n text-align: left;\n border-bottom: 2px solid var(--theme--border);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--theme--border);\n}\n.translation-table th[data-v-4b0f8dd0]:last-child {\n border-right: none;\n}\n.translation-table th[data-v-4b0f8dd0]:nth-child(1) {\n width: 300px; /* Key column - wider for long text */\n}\n.translation-table th[data-v-4b0f8dd0]:nth-child(2),\n.translation-table th[data-v-4b0f8dd0]:nth-child(3),\n.translation-table th[data-v-4b0f8dd0]:nth-child(4),\n.translation-table th[data-v-4b0f8dd0]:nth-child(5) {\n width: 200px; /* Translation columns */\n}\n.translation-table td[data-v-4b0f8dd0] {\n padding: 8px 16px;\n border-bottom: 1px solid var(--theme--border);\n border-right: 1px solid var(--theme--border);\n vertical-align: middle;\n min-height: 40px;\n}\n.translation-table td[data-v-4b0f8dd0]:last-child {\n border-right: none;\n}\n.translation-table td[data-v-4b0f8dd0]:first-child {\n word-wrap: break-word;\n word-break: break-all;\n hyphens: auto;\n line-height: 1.4;\n max-width: 300px;\n}\n.translation-table .key-cell[data-v-4b0f8dd0] {\n font-family: "Courier New", monospace;\n font-weight: 600;\n color: var(--theme--primary);\n background: var(--theme--background-subdued);\n}\n.translation-table .key-content[data-v-4b0f8dd0] {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 8px;\n min-height: 40px;\n}\n.translation-table .key-name[data-v-4b0f8dd0] {\n flex: 1;\n word-wrap: break-word;\n word-break: break-all;\n hyphens: auto;\n line-height: 1.4;\n max-width: 250px; /* Leave space for edit button */\n}\n.translation-table .edit-key-btn[data-v-4b0f8dd0] {\n flex-shrink: 0;\n margin-top: 2px;\n}\n.translation-table .translation-cell[data-v-4b0f8dd0] {\n min-height: 40px;\n}\n.translation-table .empty-row[data-v-4b0f8dd0] {\n background: var(--theme--background-subdued);\n}\n.translation-table .empty-row .editable-key[data-v-4b0f8dd0],\n.translation-table .empty-row .editable-translation[data-v-4b0f8dd0] {\n color: var(--theme--foreground-subdued);\n font-style: italic;\n}\n.translation-table .translation-row[data-v-4b0f8dd0]:hover {\n background: var(--theme--background-subdued);\n}\n.translation-table .editable-key[data-v-4b0f8dd0],\n.translation-table .editable-translation[data-v-4b0f8dd0] {\n min-height: 20px;\n outline: none;\n padding: 4px;\n border-radius: 4px;\n transition: background-color 0.2s;\n display: flex;\n align-items: center;\n}\n.translation-table .editable-key[data-v-4b0f8dd0]:focus,\n.translation-table .editable-translation[data-v-4b0f8dd0]:focus {\n background: var(--theme--background-accent);\n box-shadow: 0 0 0 2px var(--theme--primary);\n}\n.translation-table .has-changes[data-v-4b0f8dd0] {\n background: var(--theme--warning-background);\n border: 1px solid var(--theme--warning);\n}\n\n/* Pagination Controls */\n.pagination-controls[data-v-4b0f8dd0] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px;\n background: var(--theme--background);\n border-top: 1px solid var(--theme--border-color-subdued);\n margin-top: 16px;\n}\n\n.pagination-info[data-v-4b0f8dd0] {\n color: var(--theme--foreground-subdued);\n font-size: 14px;\n}\n\n.editable-key[data-v-4b0f8dd0],\n.editable-translation[data-v-4b0f8dd0] {\n min-height: 24px;\n padding: 4px 8px;\n border: 1px solid transparent;\n border-radius: 4px;\n outline: none;\n transition: all 0.2s ease;\n word-break: break-word;\n}\n.editable-key[data-v-4b0f8dd0]:hover,\n.editable-translation[data-v-4b0f8dd0]:hover {\n border-color: var(--theme--border);\n background: var(--theme--background);\n}\n.editable-key[data-v-4b0f8dd0]:focus,\n.editable-translation[data-v-4b0f8dd0]:focus {\n border-color: var(--theme--primary);\n background: var(--theme--background);\n box-shadow: 0 0 0 2px rgba(var(--theme--primary), 0.1);\n}\n.editable-key[data-v-4b0f8dd0]:empty::before,\n.editable-translation[data-v-4b0f8dd0]:empty::before {\n content: attr(placeholder);\n color: var(--theme--foreground-subdued);\n font-style: italic;\n}\n.editable-key.has-changes[data-v-4b0f8dd0],\n.editable-translation.has-changes[data-v-4b0f8dd0] {\n background: rgba(var(--theme--warning), 0.1);\n border-color: var(--theme--warning);\n}\n\n.loading-state[data-v-4b0f8dd0] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n gap: 16px;\n color: var(--theme--foreground-subdued);\n}\n\n.error-state[data-v-4b0f8dd0] {\n margin-top: 20px;\n}\n\n.translation-table table[data-v-4b0f8dd0] {\n border-collapse: separate;\n border-spacing: 0;\n width: 100%;\n background: var(--theme--background);\n}\n\n.translation-table th[data-v-4b0f8dd0],\n.translation-table td[data-v-4b0f8dd0] {\n background-color: var(--v-table-background-color, transparent);\n border-bottom: var(--theme--border-width) solid var(--theme--border-color-subdued);\n border-right: var(--theme--border-width) solid var(--theme--border-color-subdued);\n}\n\n.translation-table th[data-v-4b0f8dd0]:last-child,\n.translation-table td[data-v-4b0f8dd0]:last-child {\n border-right: none;\n}\n\n.translation-table tr:last-child td[data-v-4b0f8dd0] {\n border-bottom: none;\n}\n\n.translation-table th[data-v-4b0f8dd0] {\n color: var(--theme--foreground);\n font-weight: 600;\n background: var(--theme--background-subdued);\n}\n\n.translation-table td[data-v-4b0f8dd0] {\n background: var(--theme--background);\n}',{});const X=[],Y=[],Z=[],aa=[e({id:"translation-manager",name:"Translation Manager",icon:"translate",routes:[{path:"",component:E(W,[["__scopeId","data-v-4b0f8dd0"]])}]})],ea=[],na=[],ta=[];export{Y as displays,X as interfaces,Z as layouts,aa as modules,ta as operations,ea as panels,na as themes};