bill 2 ay önce
ebeveyn
işleme
2c63c41011

+ 6 - 4
package.json

@@ -9,7 +9,7 @@
     "build": "vite build",
     "build-offline": " vite build ./ offline",
     "preview": "vite preview",
-    "translate": "node translate.js"
+    "translate": "node ./scripts/fetch-langs.mjs"
   },
   "dependencies": {
     "@ant-design/icons-vue": "^7.0.1",
@@ -18,25 +18,27 @@
     "axios": "^0.27.2",
     "body-parser": "^1.20.3",
     "coordtransform": "^2.1.2",
+    "dayjs": "^1.11.13",
     "express": "^4.21.2",
     "i18n": "^0.15.1",
-    "dayjs": "^1.11.13",
     "js-base64": "^3.7.8",
     "konva": "^9.3.18",
     "less": "^4.1.3",
     "mitt": "^3.0.0",
+    "node-fetch": "^3.3.2",
     "simaqcore": "^1.2.0",
     "swiper": "^11.1.15",
     "three": "^0.169.0",
+    "unzipper": "^0.12.3",
     "uuid": "^11.0.2",
     "vite-plugin-mkcert": "^1.10.1",
     "vue": "3.2.47",
     "vue-cropper": "1.0.2",
     "vue-i18n": "^11.1.1",
+    "vue-konva": "3.2.0",
     "vue-router": "^4.1.3",
     "vuedraggable": "^4.1.0",
-    "xlsx": "^0.18.5",
-    "vue-konva": "3.2.0"
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@types/node": "^18.6.5",

+ 220 - 2
pnpm-lock.yaml

@@ -35,6 +35,12 @@ importers:
       i18n:
         specifier: ^0.15.1
         version: 0.15.1
+      i18next:
+        specifier: ^25.6.0
+        version: 25.6.0(typescript@4.9.5)
+      i18next-http-backend:
+        specifier: ^3.0.2
+        version: 3.0.2
       js-base64:
         specifier: ^3.7.8
         version: 3.7.8
@@ -47,6 +53,9 @@ importers:
       mitt:
         specifier: ^3.0.0
         version: 3.0.1
+      node-fetch:
+        specifier: ^3.3.2
+        version: 3.3.2
       simaqcore:
         specifier: ^1.2.0
         version: 1.2.0
@@ -56,6 +65,9 @@ importers:
       three:
         specifier: ^0.169.0
         version: 0.169.0
+      unzipper:
+        specifier: ^0.12.3
+        version: 0.12.3
       uuid:
         specifier: ^11.0.2
         version: 11.1.0
@@ -404,6 +416,9 @@ packages:
   axios@1.12.2:
     resolution: {integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==}
 
+  bluebird@3.7.2:
+    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+
   body-parser@1.20.3:
     resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -467,17 +482,27 @@ packages:
   core-js@3.45.1:
     resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
 
+  core-util-is@1.0.3:
+    resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+
   crc-32@1.2.2:
     resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
     engines: {node: '>=0.8'}
     hasBin: true
 
+  cross-fetch@4.0.0:
+    resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
+
   csstype@2.6.21:
     resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
 
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
+  data-uri-to-buffer@4.0.1:
+    resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
+    engines: {node: '>= 12'}
+
   dayjs@1.11.18:
     resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==}
 
@@ -525,6 +550,9 @@ packages:
     resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
     engines: {node: '>= 0.4'}
 
+  duplexer2@0.1.4:
+    resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==}
+
   ee-first@1.1.1:
     resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
 
@@ -706,6 +734,10 @@ packages:
     resolution: {integrity: sha512-GwTgG9O4FVIdShhbVF3JxOgSBY2+ePGsu2V/UONgoCPzF9VY6ZdBMKsHKCYQHZwNk3qNouUolRDsgVxcVA5G1w==}
     engines: {node: '>=10.0'}
 
+  fetch-blob@3.2.0:
+    resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
+    engines: {node: ^12.20 || >= 14.13}
+
   fflate@0.8.2:
     resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
 
@@ -730,6 +762,10 @@ packages:
     resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
     engines: {node: '>= 6'}
 
+  formdata-polyfill@4.0.10:
+    resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
+    engines: {node: '>=12.20.0'}
+
   forwarded@0.2.0:
     resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
     engines: {node: '>= 0.6'}
@@ -742,6 +778,10 @@ packages:
     resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
     engines: {node: '>= 0.6'}
 
+  fs-extra@11.3.2:
+    resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
+    engines: {node: '>=14.14'}
+
   fsevents@2.3.3:
     resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
     engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -785,6 +825,17 @@ packages:
     resolution: {integrity: sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA==}
     engines: {node: '>=10'}
 
+  i18next-http-backend@3.0.2:
+    resolution: {integrity: sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==}
+
+  i18next@25.6.0:
+    resolution: {integrity: sha512-tTn8fLrwBYtnclpL5aPXK/tAYBLWVvoHM1zdfXoRNLcI+RvtMsoZRV98ePlaW3khHYKuNh/Q65W/+NVFUeIwVw==}
+    peerDependencies:
+      typescript: ^5
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
   iconv-lite@0.4.24:
     resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
     engines: {node: '>=0.10.0'}
@@ -831,12 +882,18 @@ packages:
   is-what@3.14.1:
     resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
 
+  isarray@1.0.0:
+    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+
   js-base64@3.7.8:
     resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==}
 
   js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
+  jsonfile@6.2.0:
+    resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
+
   konva@9.3.22:
     resolution: {integrity: sha512-yQI5d1bmELlD/fowuyfOp9ff+oamg26WOCkyqUyc+nczD/lhRa3EvD2MZOoc4c1293TAubW9n34fSQLgSeEgSw==}
 
@@ -943,6 +1000,27 @@ packages:
   node-addon-api@7.1.1:
     resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
 
+  node-domexception@1.0.0:
+    resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+    engines: {node: '>=10.5.0'}
+    deprecated: Use your platform's native DOMException instead
+
+  node-fetch@2.7.0:
+    resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+    engines: {node: 4.x || >=6.0.0}
+    peerDependencies:
+      encoding: ^0.1.0
+    peerDependenciesMeta:
+      encoding:
+        optional: true
+
+  node-fetch@3.3.2:
+    resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+  node-int64@0.4.0:
+    resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
+
   object-inspect@1.13.4:
     resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
     engines: {node: '>= 0.4'}
@@ -980,6 +1058,9 @@ packages:
     resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
     engines: {node: ^10 || ^12 || >=14}
 
+  process-nextick-args@2.0.1:
+    resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+
   proxy-addr@2.0.7:
     resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
     engines: {node: '>= 0.10'}
@@ -1002,6 +1083,9 @@ packages:
     resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
     engines: {node: '>= 0.8'}
 
+  readable-stream@2.3.8:
+    resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
+
   readdirp@4.1.2:
     resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
     engines: {node: '>= 14.18.0'}
@@ -1022,6 +1106,9 @@ packages:
   rxjs@7.5.7:
     resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==}
 
+  safe-buffer@5.1.2:
+    resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+
   safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
 
@@ -1102,6 +1189,9 @@ packages:
     resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
     engines: {node: '>= 0.8'}
 
+  string_decoder@1.1.1:
+    resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+
   stylis@4.3.6:
     resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
 
@@ -1128,6 +1218,9 @@ packages:
     resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
     engines: {node: '>=0.6'}
 
+  tr46@0.0.3:
+    resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
   tslib@2.8.1:
     resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
 
@@ -1143,10 +1236,20 @@ packages:
   undici-types@5.26.5:
     resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
 
+  universalify@2.0.1:
+    resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
+    engines: {node: '>= 10.0.0'}
+
   unpipe@1.0.0:
     resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
     engines: {node: '>= 0.8'}
 
+  unzipper@0.12.3:
+    resolution: {integrity: sha512-PZ8hTS+AqcGxsaQntl3IRBw65QrBI6lxzqDEL7IAo/XCEqRTKGfOX56Vea5TH9SZczRVxuzk1re04z/YjuYCJA==}
+
+  util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
   utils-merge@1.0.1:
     resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
     engines: {node: '>= 0.4.0'}
@@ -1234,6 +1337,16 @@ packages:
   warning@4.0.3:
     resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
 
+  web-streams-polyfill@3.3.3:
+    resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
+    engines: {node: '>= 8'}
+
+  webidl-conversions@3.0.1:
+    resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+
+  whatwg-url@5.0.0:
+    resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+
   wmf@1.0.2:
     resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
     engines: {node: '>=0.8'}
@@ -1592,6 +1705,8 @@ snapshots:
     transitivePeerDependencies:
       - debug
 
+  bluebird@3.7.2: {}
+
   body-parser@1.20.3:
     dependencies:
       bytes: 3.1.2
@@ -1661,12 +1776,22 @@ snapshots:
 
   core-js@3.45.1: {}
 
+  core-util-is@1.0.3: {}
+
   crc-32@1.2.2: {}
 
+  cross-fetch@4.0.0:
+    dependencies:
+      node-fetch: 2.7.0
+    transitivePeerDependencies:
+      - encoding
+
   csstype@2.6.21: {}
 
   csstype@3.1.3: {}
 
+  data-uri-to-buffer@4.0.1: {}
+
   dayjs@1.11.18: {}
 
   debug@2.6.9:
@@ -1696,6 +1821,10 @@ snapshots:
       es-errors: 1.3.0
       gopd: 1.2.0
 
+  duplexer2@0.1.4:
+    dependencies:
+      readable-stream: 2.3.8
+
   ee-first@1.1.1: {}
 
   encodeurl@1.0.2: {}
@@ -1855,6 +1984,11 @@ snapshots:
 
   fast-printf@1.6.10: {}
 
+  fetch-blob@3.2.0:
+    dependencies:
+      node-domexception: 1.0.0
+      web-streams-polyfill: 3.3.3
+
   fflate@0.8.2: {}
 
   fill-range@7.1.1:
@@ -1886,12 +2020,22 @@ snapshots:
       hasown: 2.0.2
       mime-types: 2.1.35
 
+  formdata-polyfill@4.0.10:
+    dependencies:
+      fetch-blob: 3.2.0
+
   forwarded@0.2.0: {}
 
   frac@1.1.2: {}
 
   fresh@0.5.2: {}
 
+  fs-extra@11.3.2:
+    dependencies:
+      graceful-fs: 4.2.11
+      jsonfile: 6.2.0
+      universalify: 2.0.1
+
   fsevents@2.3.3:
     optional: true
 
@@ -1917,8 +2061,7 @@ snapshots:
 
   gopd@1.2.0: {}
 
-  graceful-fs@4.2.11:
-    optional: true
+  graceful-fs@4.2.11: {}
 
   has-symbols@1.1.0: {}
 
@@ -1949,6 +2092,18 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  i18next-http-backend@3.0.2:
+    dependencies:
+      cross-fetch: 4.0.0
+    transitivePeerDependencies:
+      - encoding
+
+  i18next@25.6.0(typescript@4.9.5):
+    dependencies:
+      '@babel/runtime': 7.28.4
+    optionalDependencies:
+      typescript: 4.9.5
+
   iconv-lite@0.4.24:
     dependencies:
       safer-buffer: 2.1.2
@@ -1986,10 +2141,18 @@ snapshots:
 
   is-what@3.14.1: {}
 
+  isarray@1.0.0: {}
+
   js-base64@3.7.8: {}
 
   js-tokens@4.0.0: {}
 
+  jsonfile@6.2.0:
+    dependencies:
+      universalify: 2.0.1
+    optionalDependencies:
+      graceful-fs: 4.2.11
+
   konva@9.3.22: {}
 
   less@4.4.1:
@@ -2081,6 +2244,20 @@ snapshots:
   node-addon-api@7.1.1:
     optional: true
 
+  node-domexception@1.0.0: {}
+
+  node-fetch@2.7.0:
+    dependencies:
+      whatwg-url: 5.0.0
+
+  node-fetch@3.3.2:
+    dependencies:
+      data-uri-to-buffer: 4.0.1
+      fetch-blob: 3.2.0
+      formdata-polyfill: 4.0.10
+
+  node-int64@0.4.0: {}
+
   object-inspect@1.13.4: {}
 
   on-finished@2.4.1:
@@ -2109,6 +2286,8 @@ snapshots:
       picocolors: 1.1.1
       source-map-js: 1.2.1
 
+  process-nextick-args@2.0.1: {}
+
   proxy-addr@2.0.7:
     dependencies:
       forwarded: 0.2.0
@@ -2132,6 +2311,16 @@ snapshots:
       iconv-lite: 0.4.24
       unpipe: 1.0.0
 
+  readable-stream@2.3.8:
+    dependencies:
+      core-util-is: 1.0.3
+      inherits: 2.0.4
+      isarray: 1.0.0
+      process-nextick-args: 2.0.1
+      safe-buffer: 5.1.2
+      string_decoder: 1.1.1
+      util-deprecate: 1.0.2
+
   readdirp@4.1.2: {}
 
   resize-observer-polyfill@1.5.1: {}
@@ -2150,6 +2339,8 @@ snapshots:
     dependencies:
       tslib: 2.8.1
 
+  safe-buffer@5.1.2: {}
+
   safe-buffer@5.2.1: {}
 
   safe-identifier@0.4.2: {}
@@ -2252,6 +2443,10 @@ snapshots:
 
   statuses@2.0.1: {}
 
+  string_decoder@1.1.1:
+    dependencies:
+      safe-buffer: 5.1.2
+
   stylis@4.3.6: {}
 
   supports-preserve-symlinks-flag@1.0.0: {}
@@ -2269,6 +2464,8 @@ snapshots:
 
   toidentifier@1.0.1: {}
 
+  tr46@0.0.3: {}
+
   tslib@2.8.1: {}
 
   type-is@1.6.18:
@@ -2280,8 +2477,20 @@ snapshots:
 
   undici-types@5.26.5: {}
 
+  universalify@2.0.1: {}
+
   unpipe@1.0.0: {}
 
+  unzipper@0.12.3:
+    dependencies:
+      bluebird: 3.7.2
+      duplexer2: 0.1.4
+      fs-extra: 11.3.2
+      graceful-fs: 4.2.11
+      node-int64: 0.4.0
+
+  util-deprecate@1.0.2: {}
+
   utils-merge@1.0.1: {}
 
   uuid@11.1.0: {}
@@ -2355,6 +2564,15 @@ snapshots:
     dependencies:
       loose-envify: 1.4.0
 
+  web-streams-polyfill@3.3.3: {}
+
+  webidl-conversions@3.0.1: {}
+
+  whatwg-url@5.0.0:
+    dependencies:
+      tr46: 0.0.3
+      webidl-conversions: 3.0.1
+
   wmf@1.0.2: {}
 
   word@0.3.0: {}

+ 53 - 0
scripts/fetch-langs.mjs

@@ -0,0 +1,53 @@
+import fetch from 'node-fetch'
+import fs from 'fs'
+import path from 'path'
+import unzipper from 'unzipper'
+
+import {pipeline} from 'node:stream';
+import {promisify} from 'node:util'
+import {createReadStream,createWriteStream} from "node:fs";
+
+const streamPipeline = promisify(pipeline);
+
+
+/**
+ * 下载并解压离线包
+ * @param {string} url 下载地址
+ * @param {string} destDir 解压目标目录
+ */
+async function downloadAndExtract(url, destDir) {
+    const zipPath = path.join(destDir, 'temp.zip')
+
+
+    console.log(`开始下载语言包: ${url}`)
+
+    const res = await fetch(url, {
+        method: 'GET',
+        headers: {
+            //'X-API-Key':'tgpak_gm2f6ntnor2gy4ztnfuw65twoj2wu2tdovzwwztqoe4ts5q'
+        },
+    })
+
+    if (!res.ok) {
+        throw new Error(`下载语言包失败: ${res.status} ${res.statusText}`)
+    }
+
+    // zip文件保存到本地目录
+    await streamPipeline(res.body, createWriteStream(zipPath));
+
+    console.log('语言包下载完成,开始解压...')
+
+    // 解压到指定目录
+    await streamPipeline(createReadStream(zipPath),unzipper.Extract({ path: destDir }));
+
+    console.log('语言包解压完成!')
+
+    // 删除临时压缩包
+    fs.unlinkSync(zipPath)
+}
+
+// 示例调用
+const url = 'http://192.168.0.211:9012/v2/projects/export?ak=tgpak_gm4f6m3pou4diyzzmiygm33koa2gs3rqha2tonlsgftww2y'
+const dest = './src/lang/locales'
+
+await downloadAndExtract(url, dest)

+ 4 - 4
src/lang/index.ts

@@ -2,10 +2,10 @@ import { createI18n, I18n as BaseI18n } from 'vue-i18n'
 import { App, WritableComputedRef } from 'vue'
 import { localGetFactory, localSetFactory } from '@/utils/store'
 import { paramsToStr, strToParams } from '@/utils/params'
-import zh from './weblate/zh.json'
-import en from './weblate/en.json'
-import ja from './weblate/ja.json'
-import kr from './weblate/kr.json'
+import zh from './locales/zh.json'
+import en from './locales/en.json'
+import ja from './locales/ja.json'
+import kr from './locales/ko.json'
 // 语言支持
 export enum langNameEum {
   zh = 'zh',

+ 376 - 0
src/lang/locales/en.json

@@ -0,0 +1,376 @@
+{
+  "case": {
+    "cols": {
+      "caseAddress": "Incident location",
+      "caseCategory": "Case category",
+      "caseNum": "Case number",
+      "caseRegion": "Incident area",
+      "caseTitle": "Case name",
+      "crimeTime": "Incident time",
+      "criminalCase": "Is it a criminal case?",
+      "homicideCase": "Is it a homicide case?",
+      "latAndLong": "Latitude and Longitude"
+    },
+    "name": "Case information",
+    "nv": "No",
+    "sn": "Case name",
+    "summary": "Case summary",
+    "tmCols": {
+      "alarmName": "Reporter",
+      "alarmTime": "Report Time",
+      "assignDept": "Assigned/Reporting Unit",
+      "assignType": "Assignment Method",
+      "commandTime": "Command Center Phone Hours",
+      "inquestAddress": "Inspection location",
+      "inquestDept": "On-site inspection unit",
+      "times": "Inspection time"
+    },
+    "tmName": "Inspection information",
+    "yv": "Yes"
+  },
+  "common": {
+    "NoFilesSelected": "No file selected"
+  },
+  "coord": {
+    "zoomLevel": "Zoom Level"
+  },
+  "floder": {
+    "extractList": "Extraction List",
+    "name": "Case file",
+    "photo": "Photo roll",
+    "record": "Inspection Record"
+  },
+  "fuse": {
+    "dataQue": "Data source",
+    "dataSize": "Data size",
+    "dataTime": "Capture Time",
+    "def": "Restore default",
+    "defConfirm": "Are you sure you want to restore to default? This action cannot be undone.",
+    "flip": "Rotate",
+    "hre": "Please adjust the vertical position within the current window.",
+    "join": "Stitching",
+    "label": "Merge scene",
+    "len": "Length",
+    "model": "3D model",
+    "move": "Move",
+    "name": "Multi-convergence",
+    "opacity": "Model opacity",
+    "opacity1": "Transparency",
+    "pano": "Panorama",
+    "reSelect": "Reselect points",
+    "registration": "Registration",
+    "repScale": "Uniform scaling",
+    "selectTip": "Please select two points to mark a known length, and enter the actual length",
+    "setScale": "Set scale",
+    "sync": "Simultaneous screen inspection",
+    "syncErr": "Property viewing is only supported for {types} types of scenes. Please add this type of scene.",
+    "unModel": "Model does not exist!",
+    "vre": "Please adjust the horizontal position within the current window."
+  },
+  "guide": {
+    "defTitle": "Path {num}",
+    "guide": {
+      "add": "Add viewpoint",
+      "clear": "Clear the view",
+      "clearConfirm": "Are you sure you want to clear the view?",
+      "delConfirm": "Are you sure you want to delete this view?",
+      "name": "tour",
+      "time": "Video duration",
+      "unItems": "Unable to save empty path guide tour!",
+      "undata": "No navigation available"
+    },
+    "guideName": "Tour ({count})",
+    "modelErr": "The model where the path is located has been deleted and cannot be played.",
+    "name": "Path",
+    "nameErr": "Path name cannot be empty",
+    "pErr": "The number of path points cannot be fewer than two.",
+    "path": {
+      "applyConfirm": "Are you sure you want to apply this attribute to all locations?",
+      "fontSize": "Font size",
+      "globalVisibility": "All range visible",
+      "lineColor": "Path color",
+      "lineWidth": "Path thickness",
+      "name": "Route",
+      "pointDesc": "Description",
+      "pointTitle": "Edit point",
+      "preview": "Preview path",
+      "reverseDirection": "Reverse arrow",
+      "showDirection": "Path arrow",
+      "stop": "Stop",
+      "title": "Path name",
+      "visibilityRange": "Visible range"
+    },
+    "pathName": "Rout({count})"
+  },
+  "material": {
+    "name": "Media Library",
+    "search": "Search by name",
+    "selectCount": "Selected data",
+    "selectErr": "A maximum of {count} items can be selected",
+    "tabs": {
+      "action": "Operation",
+      "format": "Format",
+      "group": "Group",
+      "name": "Name",
+      "size": "Size",
+      "status": "Status"
+    },
+    "up": "Upload from Media Library",
+    "uploadErr": "Upload failed",
+    "uploadIng": "Uploading...",
+    "uploadSuccess": "Upload successful"
+  },
+  "measure": {
+    "area": {
+      "desc": "Area",
+      "unit": "Area"
+    },
+    "free": {
+      "desc": "Free",
+      "unit": "Length"
+    },
+    "list": "Measurement list",
+    "name": "Measurement",
+    "nameErr": "Measurement name cannot be empty",
+    "vertical": {
+      "desc": "Vertical",
+      "unit": "Length"
+    }
+  },
+  "mediaLibrary": {
+    "file": "file",
+    "setGrouping": "Modify Grouping",
+    "tips": {
+      "osgbtips": "Upload osgb: You need to use a zip package to upload. Contains Data folders and xml files. The package must not contain folders, and the file name must not use Chinese. As shown in the figure:",
+      "uplooadSize": "Uploaded files cannot exceed 2G!"
+    }
+  },
+  "program": {
+    "case": {
+      "add_case": "New Case",
+      "create": "Create case file",
+      "empty": "No projects available",
+      "status_1": "Calculation failed",
+      "status_3": "Archive",
+      "status_5": "Pause",
+      "status_6": " In queue",
+      "status_7": "Copying..."
+    },
+    "errMsg": {
+      "repeatGen": "There is a calculation task, please wait until the calculation is completed before downloading the offline package. Avoid packaging failure."
+    },
+    "kankan": "Minion",
+    "lang": "Multilingual",
+    "laser": "Mega",
+    "menu": {
+      "library": "Media Library"
+    },
+    "path_no_exist": "The path does not exist.",
+    "scene": {
+      "calcDone": "Calculation Completion Time"
+    },
+    "sceneDetail": {
+      "exportingOut": "Exporting...",
+      "firstPacking": "Packaging",
+      "import": "Import",
+      "isCopyExist": "The scene already exists. Do you want to save it as a copy?",
+      "migrageS_title": "Migrate scene",
+      "reFirstPacking": "Repackaged",
+      "stoping": "Pause",
+      "updateAt": "Updating at"
+    },
+    "sceneDown": {
+      "coverStatus": {
+        "un": "To be calculated"
+      },
+      "msgStatus": {
+        "ing": "Pause",
+        "lineup": "Continue calculating"
+      }
+    },
+    "shenguang": "Meta"
+  },
+  "record": {
+    "backHandler": "The backend is processing.",
+    "con": "Continue recording",
+    "defName": "Tutorial video{num}",
+    "delConfirm": "Are you sure you want to delete this video?",
+    "list": "All videos",
+    "merge": "Merge videos",
+    "name": "Screen recording",
+    "nameErr": "Video name cannot be empty",
+    "sizeErr": "The size limit has been exceeded, and recording cannot continue. You can save and resume recording!",
+    "start": "Start recording",
+    "tag": "Tag",
+    "vName": "Screen recording"
+  },
+  "resCode": {
+    "0": "Request successful",
+    "4008": "token has expired",
+    "4010": "You do not have access permission"
+  },
+  "scene": {
+    "add": "Add scene",
+    "list": "Scene list",
+    "manage": "Scene management",
+    "tabs": {
+      "createTime": "Capture/Creation Time",
+      "name": "Name",
+      "type": "Type"
+    },
+    "typeRaws": {
+      "0": "Mesh Scene",
+      "1": "Mesh Scene",
+      "2": "Point cloud scene",
+      "4": "Mesh Scene",
+      "5": "Point cloud scene",
+      "6": "Mesh Scene",
+      "7": "Mesh Scene"
+    },
+    "types": {
+      "0": "4DKanKan Pro/Mesh",
+      "1": "4DKanKan Minion/Mesh",
+      "2": "4DKanKan Mega/Point cloud",
+      "3": "Media Library",
+      "4": "4DKanKan Mega/Mesh",
+      "5": "4DKanKan Meta/Point cloud",
+      "6": "4DKanKan Meta/Mesh",
+      "7": "π/Mesh"
+    }
+  },
+  "sceneHome": {
+    "nameSearch": "Search by name",
+    "searchData": "Search Results",
+    "selectAdd": "Select Address",
+    "yctips": "Unable to remove. The scene has been added to the multi-fusion. Please delete the scene from the multi-fusion before trying again.",
+    "yctipsErr": "Unable to remove. The scene has been added to the multi-fusion. Please delete the scene from the multi-fusion before trying again."
+  },
+  "security": {
+    "name": "Security"
+  },
+  "setting": {
+    "back": "Set sky",
+    "backs[0]": "N/A",
+    "backs[1]": "Map",
+    "backs[2]": "Blue sky and white clouds",
+    "backs[3]": "Cloudy",
+    "backs[4]": "Nighty sky",
+    "backs[5]": "Evening",
+    "initView": "Initial Screen",
+    "name": "Setting"
+  },
+  "sys": {
+    "404Page": "The resource does not exist or has been deleted",
+    "add": "Add",
+    "addData": "Add data",
+    "all": "All",
+    "cancel": "Cancel",
+    "create": "Create",
+    "crop": "Crop",
+    "cropIng": "Cropping in progress",
+    "del": "Delete",
+    "delConfrm": "Are you sure you want to delete this data?",
+    "download": "Download",
+    "edit": "Edit",
+    "enter": "Confirm",
+    "errPage": "Error page",
+    "expand": "Expand",
+    "imgLoadErr": "Failed to load image",
+    "jsError": "Insufficient memory. Please avoid opening multiple pages or applications simultaneously. Try restarting your browser and reopening the content.",
+    "list": "Data list",
+    "ok": "I understand",
+    "other": "Other",
+    "placPWD": "Please enter the password!",
+    "placeInput": "Please enter",
+    "placeSelect": "Please select",
+    "pwdErr": "Incorrect password, please try again.",
+    "quit": "Exit",
+    "rename": "Rename",
+    "retract": "Collapse",
+    "save": "Save",
+    "search": "Search",
+    "serviceErr": "An error occurred with the service. Please try again later.",
+    "tip": "Prompt",
+    "tranCropImg": "Please upload the cropped image.",
+    "unSaveMsg": "You have unsaved changes. Are you sure you want to exit?",
+    "unSearch": "No results found",
+    "unSearchData": "No search results found",
+    "unSelect": "No options available",
+    "undata": "No results",
+    "upload": {
+      "accErr": "Format error",
+      "accSuperErr": "Only supports file in {accept} format.",
+      "accept": "Supports {accept} formats,",
+      "conAdd": "Continue adding",
+      "lenErr": "Only a maximum of {maxLen} files are supported!",
+      "maxLen": "The number should not exceed {maxLen}",
+      "maxSize": "Maximum size {sizeStr}.",
+      "normalizeScale": "Width-to-height ratio {scale}",
+      "place1": "Upload file",
+      "previewErr": "Preview loading failed!",
+      "rep": "Replace",
+      "scaleErr": "The scaled part of {name} is not {scale}",
+      "sizeErr": "The size of {name} exceeds {sizeStr}"
+    },
+    "viewPWD": "Access password"
+  },
+  "tagging": {
+    "apply": "Apply to all",
+    "applyConfirm": "Are you sure you want to apply this attribute to all locations?",
+    "list": "Tag list",
+    "media": "Image/Video",
+    "mic": "Music",
+    "micPlc": "Supports mp3/wav formats, ≤ 30MB",
+    "name": "Tag",
+    "plcMedia1": "Supports JPG, PNG, MP4, and other formats, with a single file size not exceeding 100MB, and a maximum of 10 files allowed for upload.",
+    "plcMethod": "Extraction method:",
+    "plcPart": "Residual area:",
+    "plcPos": "Placement location",
+    "plcPrincipal": "Extractor:",
+    "plcTitle": "Please enter the tag title",
+    "plcType": "Description:",
+    "plcType1": "Feature description:",
+    "pleMedia": "Upload image/video",
+    "pos": "Place",
+    "posErr": "Unable to add current location",
+    "posName": "Location",
+    "posTabs": {
+      "fontSize": "Font size",
+      "globalVisibility": "All range visible",
+      "lineHeight": "Wire height",
+      "rotation": "Rotate icon",
+      "scale": "Icon size",
+      "type": "Icon placement method",
+      "typeVal[0]": "Hover",
+      "typeVal[1]": "Attach",
+      "visibilityRange": "Visible range"
+    },
+    "posTip": "Click on the model to select the tag position.",
+    "style": "Icon style",
+    "styleErr": "Please select an icon style!",
+    "tabs": {
+      "method": "Extraction Method",
+      "part": "Residual area",
+      "principal": "Extractor",
+      "typeId": "Feature description"
+    },
+    "titleErr": "Tag title is required!",
+    "titleFex": "Title pinned",
+    "type": {
+      "1": "Trace",
+      "2": "Handprint",
+      "3": "Footprint",
+      "4": "Bloodstain ",
+      "5": "Body",
+      "6": "Other",
+      "7": "Evidence"
+    }
+  },
+  "view": {
+    "all": "All views",
+    "defName": "View{num}",
+    "name": "Extraction",
+    "nameErr": "View name cannot be empty",
+    "vName": "View"
+  }
+}

+ 373 - 0
src/lang/locales/ja.json

@@ -0,0 +1,373 @@
+{
+  "case": {
+    "cols": {
+      "caseAddress": "発生場所",
+      "caseCategory": "事件カテゴリ",
+      "caseNum": "登録番号",
+      "caseRegion": "発生地域",
+      "caseTitle": "事件名",
+      "crimeTime": "発生時刻",
+      "criminalCase": "刑事事件か",
+      "homicideCase": "殺人事件か",
+      "latAndLong": "緯度経度"
+    },
+    "name": "事件情報",
+    "nv": "いいえ",
+    "sn": "事件名",
+    "summary": "事件概要",
+    "tmCols": {
+      "alarmName": "通報者",
+      "alarmTime": "通報時刻",
+      "assignDept": "指定/報告部署",
+      "assignType": "指定方法",
+      "commandTime": "指令センター通話時刻",
+      "inquestAddress": "検証場所",
+      "inquestDept": "現場検証部署",
+      "times": "検証時間"
+    },
+    "tmName": "検証情報",
+    "yv": "はい"
+  },
+  "common": {
+    "NoFilesSelected": "ファイルを選択してください。"
+  },
+  "coord": {
+    "zoomLevel": "ズームレベル"
+  },
+  "floder": {
+    "extractList": "抽出リスト",
+    "name": "ファイル",
+    "photo": "写真製本",
+    "record": "検証記録"
+  },
+  "fuse": {
+    "dataQue": "データソース",
+    "dataSize": "データサイズ",
+    "dataTime": "撮影時関",
+    "def": "デフォルトに戻す",
+    "defConfirm": "デフォルトに戻しますか?この操作は取り消せません",
+    "flip": "回転",
+    "hre": "垂直方向の位置を調整してください",
+    "join": "結合",
+    "label": "融合シーン",
+    "len": "長さ",
+    "model": "3Dモデル",
+    "move": "移動",
+    "name": "マルチ融合",
+    "opacity": "モデルの不透明度",
+    "opacity1": "不透明度",
+    "pano": "パノラマ画像",
+    "reSelect": "ポイント再選択",
+    "registration": "位置合わせ",
+    "repScale": "等倍スケーリング",
+    "selectTip": "2点を選択して実際の長さを入力してください",
+    "setScale": "スケール設定",
+    "sync": "同期検証",
+    "syncErr": "同期表示は{types}タイプのシーンのみサポートされます",
+    "unModel": "モデルが存在しません!",
+    "vre": "水平方向の位置を調整してください"
+  },
+  "guide": {
+    "defTitle": "ガイド{num}",
+    "guide": {
+      "add": "視点を追加",
+      "clear": "画面をクリア",
+      "clearConfirm": "画面をクリアしますか?",
+      "delConfirm": "この画面を削除しますか?",
+      "name": "ツアー",
+      "time": "動画の長さ",
+      "unItems": "空のガイドは保存できません!",
+      "undata": "ツアーがありません"
+    },
+    "guideName": "ツアー({count})",
+    "modelErr": "ガイドのモデルが削除されました。再生できません",
+    "name": "ガイド",
+    "nameErr": "ガイド名は必須です",
+    "pErr": "ポイントは2つ以上必要です",
+    "path": {
+      "applyConfirm": "この設定を全ての位置に適用しますか?",
+      "fontSize": "文字サイズ",
+      "globalVisibility": "全範囲で表示",
+      "lineColor": "ルートの色",
+      "lineWidth": "ルートの太さ",
+      "name": "ルート",
+      "pointDesc": "説明",
+      "pointTitle": "ポイント編集",
+      "preview": "ルートをプレビュー",
+      "reverseDirection": "矢印の向きを反転",
+      "showDirection": "ルートの矢印",
+      "stop": "停止",
+      "title": "ルート名",
+      "visibilityRange": "表示範囲"
+    },
+    "pathName": "ルート({count})"
+  },
+  "material": {
+    "name": "メディアライブラリ",
+    "search": "名前で検索",
+    "selectCount": "選択済みデータ",
+    "selectErr": "最大{count}件まで選択可能",
+    "tabs": {
+      "action": "操作",
+      "format": "形式",
+      "group": "グループ",
+      "name": "名前",
+      "size": "サイズ",
+      "status": "状態"
+    },
+    "up": "+メディアライブラリからアップロード",
+    "uploadErr": "アップロード失敗",
+    "uploadIng": "アップロード中",
+    "uploadSuccess": "アップロード成功"
+  },
+  "measure": {
+    "area": {
+      "desc": "面積",
+      "unit": "面積"
+    },
+    "free": {
+      "desc": "自由",
+      "unit": "長さ"
+    },
+    "list": "測定リスト",
+    "name": "測定",
+    "nameErr": "測定名は必須です",
+    "vertical": {
+      "desc": "垂直",
+      "unit": "長さ"
+    }
+  },
+  "mediaLibrary": {
+    "file": "ファイル",
+    "setGrouping": "グループを調整",
+    "tips": {
+      "uplooadSize": "アップロードするファイルは 2G以内です。"
+    }
+  },
+  "program": {
+    "case": {
+      "add_case": "新しい案件を追加",
+      "create": "案件を作成",
+      "empty": "現在、案件はありません",
+      "status_1": "計算に失敗しました",
+      "status_3": "アーカイブ",
+      "status_5": "ていし",
+      "status_6": " 待ち行列中",
+      "status_7": "コピー中"
+    },
+    "errMsg": {
+      "repeatGen": "シーンは計算中です。ダウンロード失敗を避けるよう、計算の完了を待ってください。"
+    },
+    "exit-msg": "ページを閉じた後も、プログラムはバックグラウンドで実行されます。プログラムを終了する必要がある場合は、システムトレイから終了してください。",
+    "lang": "言語",
+    "menu": {
+      "library": "メディアライブラリ"
+    },
+    "path_no_exist": "指定されたパスは存在しません",
+    "scene": {
+      "calcDone": "計算完了時間"
+    },
+    "sceneDetail": {
+      "exportingOut": "エクスポート中",
+      "firstPacking": "ファイル圧縮",
+      "import": "インポート",
+      "isCopyExist": "シーンは既に存在します。コピーとして保存しますか?",
+      "migrageS_title": "シーンを移動",
+      "reFirstPacking": "再パッケージ",
+      "stoping": "ていし",
+      "updateAt": "更新日時:"
+    },
+    "sceneDown": {
+      "coverStatus": {
+        "un": "待計算"
+      },
+      "msgStatus": {
+        "ing": "中止",
+        "lineup": "中止"
+      }
+    }
+  },
+  "record": {
+    "backHandler": "バックグラウンド処理中",
+    "con": "録画を続ける",
+    "defName": "解説動画{num}",
+    "delConfirm": "動画を削除しますか?",
+    "list": "全ての動画",
+    "merge": "動画を結合",
+    "name": "画面録画",
+    "nameErr": "動画名は必須です",
+    "sizeErr": "制限サイズを超えました。保存後に続行してください!",
+    "start": "録画開始",
+    "tag": "タグ",
+    "vName": "録画"
+  },
+  "resCode": {
+    "0": "リクエスト成功",
+    "4008": "トークンが失効しました",
+    "4010": "アクセス権限がありません"
+  },
+  "scene": {
+    "add": "シーン追加",
+    "list": "シーンリスト",
+    "manage": "シーン管理",
+    "tabs": {
+      "createTime": "撮影/作成時刻",
+      "name": "名前",
+      "type": "タイプ"
+    },
+    "typeRaws": {
+      "0": "Meshシーン",
+      "1": "Meshシーン",
+      "2": "点群シーン",
+      "4": "Meshシーン",
+      "5": "点群シーン",
+      "6": "Meshシーン",
+      "7": "Meshシーン"
+    },
+    "types": {
+      "0": "4DKanKan Minion/Mesh",
+      "1": "4DKanKan Minion/Mesh",
+      "2": "4DKanKan Mega/点群",
+      "3": "メディアライブラリ",
+      "4": "4DKanKan Mega/Mesh",
+      "5": "4DKanKan Meta/点群",
+      "6": "4DKanKan Meta/Mesh",
+      "7": "円周率/Mesh"
+    }
+  },
+  "sceneHome": {
+    "nameSearch": "名前を入力して検索",
+    "searchData": "検索結果",
+    "selectAdd": "住所を選択",
+    "yctips": "削除できません。シーンはすでにマルチフュージョンに追加されています。マルチフュージョンに移動してシーンを削除してから、もう一度お試しください。",
+    "yctipsErr": "削除できません。シーンはすでにマルチフュージョンに追加されています。マルチフュージョンに移動してシーンを削除してから、もう一度お試しください。"
+  },
+  "security": {
+    "name": "セキュリティ"
+  },
+  "setting": {
+    "back": "背景設定",
+    "backs[0]": "なし",
+    "backs[1]": "地図",
+    "backs[2]": "青空と白雲",
+    "backs[3]": "曇天",
+    "backs[4]": "夜空",
+    "backs[5]": "夕暮れ",
+    "initView": "初期画面",
+    "name": "設定"
+  },
+  "sys": {
+    "404Page": "リソースが存在しないか削除されました",
+    "add": "追加",
+    "addData": "データ追加",
+    "all": "全て",
+    "cancel": "キャンセル",
+    "create": "作成",
+    "crop": "トリミング",
+    "cropIng": "トリミング中",
+    "del": "削除",
+    "delConfrm": "このデータを削除しますか?",
+    "download": "ダウンロード",
+    "edit": "編集",
+    "enter": "確定",
+    "errPage": "エラーページ",
+    "expand": "開く",
+    "imgLoadErr": "画像の読み込みに失敗しました",
+    "jsError": "メモリ不足です。複数のページやアプリを同時に開かないでください。ブラウザを再起動して再度開いてください。",
+    "list": "データ一覧",
+    "ok": "了解しました",
+    "other": "その他",
+    "placPWD": "パスワードを入力してください!",
+    "placeInput": "入力してください",
+    "placeSelect": "選択してください",
+    "pwdErr": "パスワードが間違っています。再入力してください。",
+    "quit": "終了",
+    "rename": "名前変更",
+    "retract": "折りたたむ",
+    "save": "保存",
+    "search": "検索",
+    "serviceErr": "サービスに異常が発生しました。しばらくしてから再試行してください",
+    "tip": "ヒント",
+    "tranCropImg": "トリミング画像を入力してください",
+    "unSaveMsg": "保存されていない操作があります。終了しますか?",
+    "unSearch": "検索結果なし",
+    "unSearchData": "検索結果がありません",
+    "unSelect": "選択肢がありません",
+    "undata": "結果がありません",
+    "upload": {
+      "accErr": "形式エラー",
+      "accSuperErr": "{accept}形式のみサポート",
+      "accept": "{accept}などの形式をサポート",
+      "conAdd": "続けて追加",
+      "lenErr": "最大{maxLen}個までアップロード可能です!",
+      "maxLen": "最大{maxLen}個まで",
+      "maxSize": "サイズは{sizeStr}以下",
+      "normalizeScale": "幅*高さの比率 {scale}",
+      "place1": "ファイルをアップロード",
+      "previewErr": "プレビューの読み込みに失敗しました!",
+      "rep": "置換",
+      "scaleErr": "{name}の比率が{scale}ではありません",
+      "sizeErr": "{name}のサイズが{sizeStr}を超えています"
+    },
+    "viewPWD": "アクセスパスワード"
+  },
+  "tagging": {
+    "apply": "全てに適用",
+    "applyConfirm": "この設定を全ての位置に適用しますか?",
+    "list": "タグリスト",
+    "media": "画像/動画",
+    "mic": "音声",
+    "micPlc": "mp3/wav形式、30MB以下",
+    "name": "タグ",
+    "plcMedia1": "JPG、PNG、MP4形式、100MB以下、最大10ファイル",
+    "plcMethod": "抽出方法:",
+    "plcPart": "残留部位:",
+    "plcPos": "配置位置",
+    "plcPrincipal": "抽出者:",
+    "plcTitle": "タグタイトルを入力してください",
+    "plcType": "説明:",
+    "plcType1": "特徴の説明:",
+    "pleMedia": "画像/動画をアップロード",
+    "pos": "配置",
+    "posErr": "この位置には追加できません",
+    "posName": "位置",
+    "posTabs": {
+      "fontSize": "文字サイズ",
+      "globalVisibility": "全範囲で表示",
+      "lineHeight": "ガイド線の高さ",
+      "rotation": "アイコン回転",
+      "scale": "アイコンサイズ",
+      "type": "アイコン配置方法",
+      "typeVal[0]": "浮遊",
+      "typeVal[1]": "地面/壁面",
+      "visibilityRange": "表示範囲"
+    },
+    "posTip": "モデル上をクリックしてタグ位置を選択してください",
+    "style": "アイコンスタイル",
+    "styleErr": "アイコンスタイルを選択してください!",
+    "tabs": {
+      "method": "抽出方法",
+      "part": "残留部位",
+      "principal": "抽出者",
+      "typeId": "特徴の説明"
+    },
+    "titleErr": "タグタイトルは必須です!",
+    "titleFex": "タイトル固定表示",
+    "type": {
+      "1": "痕跡",
+      "2": "手形",
+      "3": "足跡",
+      "4": "血液 ",
+      "5": "死体",
+      "6": "その他",
+      "7": "物的証拠"
+    }
+  },
+  "view": {
+    "all": "全てのビュー",
+    "defName": "ビュー{num}",
+    "name": "ビュー抽出",
+    "nameErr": "ビュー名は必須です",
+    "vName": "ビュー"
+  }
+}

+ 373 - 0
src/lang/locales/ko.json

@@ -0,0 +1,373 @@
+{
+  "case": {
+    "cols": {
+      "caseAddress": "사건 발생 장소",
+      "caseCategory": "사건 유형",
+      "caseNum": "입안 번호",
+      "caseRegion": "사건 발생 지역",
+      "caseTitle": "사건 명칭",
+      "crimeTime": "사건 발생 시간",
+      "criminalCase": "형사 사건인지 아닌지",
+      "homicideCase": "살인 사건인지 아닌지",
+      "latAndLong": "경위도"
+    },
+    "name": "사건 정보",
+    "nv": "거절",
+    "sn": "사건 명칭",
+    "summary": "사건 개요",
+    "tmCols": {
+      "alarmName": "경보 신고자",
+      "alarmTime": "경보 신고 시간",
+      "assignDept": "지정/보고 단위",
+      "assignType": "지정 방식",
+      "commandTime": "지휘 센터 전화 시간",
+      "inquestAddress": "감문 장소",
+      "inquestDept": "현장 감안 단위",
+      "times": "감문 시간"
+    },
+    "tmName": "감문 정보",
+    "yv": "예"
+  },
+  "common": {
+    "NoFilesSelected": "아무 파일도 선택되지 않았습니다."
+  },
+  "coord": {
+    "zoomLevel": "줌 레벨"
+  },
+  "floder": {
+    "extractList": "추출 목록",
+    "name": "접수된 서류",
+    "photo": "사진을 권으로 만드는 작업",
+    "record": "감문 비록"
+  },
+  "fuse": {
+    "dataQue": "데이터 소스",
+    "dataSize": "데이터 크기",
+    "dataTime": "촬영 시간",
+    "def": "기본값으로 복원하다",
+    "defConfirm": "기본 설정으로 복구하시겠습니까? 이 작업은 철회할 수 없습니다",
+    "flip": "회전하다",
+    "hre": "현재 창에서 수직 방향 위치를 조정해 주세요",
+    "join": "잇다",
+    "label": "융합 시나리오",
+    "len": "길이",
+    "model": "3차원 모델",
+    "move": "이동",
+    "name": "다원 융합",
+    "opacity": "모델 불투명도",
+    "opacity1": "투명도",
+    "pano": "전경도",
+    "reSelect": "다시 지점을 선택하다",
+    "registration": "정합하다",
+    "repScale": "등비 스케일링",
+    "selectTip": "두 지점을 선택하여 알려진 길이를 표시하고, 실제 길이를 입력해 주세요",
+    "setScale": "비율을 설정하다",
+    "sync": "동시 화면 감문",
+    "syncErr": "방문 보기는 {types} 유형의 장면만 지원합니다. 이 유형의 장면을 추가해 주세요.",
+    "unModel": "모델이 존재하지 않습니다!",
+    "vre": "현재 창에서 수평 방향 위치를 조정해 주세요"
+  },
+  "guide": {
+    "defTitle": "경로{num}",
+    "guide": {
+      "add": "시각 추가",
+      "clear": "화면 지우기",
+      "clearConfirm": "화면을 정말로 비우시겠습니까?",
+      "delConfirm": "이 화면을 정말로 삭제하시겠습니까?",
+      "name": "가이드",
+      "time": "동영상 길이",
+      "unItems": "빈 경로 가이드를 저장할 수 없습니다!",
+      "undata": "아직 안내가 없습니다"
+    },
+    "guideName": "가이드({count})",
+    "modelErr": "경로가 있는 모델이 삭제되어 재생할 수 없습니다",
+    "name": "경로",
+    "nameErr": "경로 이름은 비어 있을 수 없습니다",
+    "pErr": "경로 지점은 두 개 미만이 될 수 없습니다",
+    "path": {
+      "applyConfirm": "이 속성을 모든 위치에 적용하시겠습니까?",
+      "fontSize": "글자 크기",
+      "globalVisibility": "전체 범위가 시야에 들어옵니다",
+      "lineColor": "경로 색상",
+      "lineWidth": "경로 두께",
+      "name": "노선",
+      "pointDesc": "설명하다",
+      "pointTitle": "편집하다",
+      "preview": "미리보기 경로",
+      "reverseDirection": "화살표 방향을 반대로 하다",
+      "showDirection": "경로 화살표",
+      "stop": "정지",
+      "title": "경로 이름",
+      "visibilityRange": "시야 범위"
+    },
+    "pathName": "노선({count})"
+  },
+  "material": {
+    "name": "미디어 라이브러리",
+    "search": "이름을 입력하여 검색하세요",
+    "selectCount": "이미 선택된 데이터입니다",
+    "selectErr": "최대 {count}항목을 선택하세요",
+    "tabs": {
+      "action": "조작하다",
+      "format": "서식",
+      "group": "분류하다",
+      "name": "명칭",
+      "size": "크기",
+      "status": "상태"
+    },
+    "up": "+미디어 라이브러리에서 업로드",
+    "uploadErr": "업로드 실패",
+    "uploadIng": "업로드 중입니다",
+    "uploadSuccess": "업로드 성공"
+  },
+  "measure": {
+    "area": {
+      "desc": "면적",
+      "unit": "면적"
+    },
+    "free": {
+      "desc": "자유",
+      "unit": "길이"
+    },
+    "list": "측정 목록",
+    "name": "측정하다",
+    "nameErr": "측정 명칭은 공란이 될 수 없습니다",
+    "vertical": {
+      "desc": "수직",
+      "unit": "길이"
+    }
+  },
+  "mediaLibrary": {
+    "file": "공문서. 서류. 문건.",
+    "setGrouping": "그룹 수정",
+    "tips": {
+      "osgbtips": "OSGB 업로드: 반드시 zip 파일로 업로드해야 합니다. zip 파일에는 Data 폴더와 xml 파일이 포함되어야 하며, 추가적인 폴더를 포함할 수 없습니다. 또한, 파일명에는 한글이나 특수 문자를 사용할 수 없습니다. 아래 예시를 참고해 주세요:",
+      "uplooadSize": "업로드 파일은 2GB를 초과할 수 없습니다!"
+    }
+  },
+  "program": {
+    "case": {
+      "add_case": "새로운 케이스 추가",
+      "create": "케이스 생성",
+      "empty": "프로젝트가 없습니다",
+      "status_1": "계산 실패",
+      "status_3": "봉인",
+      "status_5": "컴퓨터 시스템, 중지",
+      "status_6": " 컴퓨터 시스템, 대기 중",
+      "status_7": "복사 중"
+    },
+    "errMsg": {
+      "repeatGen": "계산 작업이 진행 중입니다. 계산 완료 후 오프라인 패키지를 다운로드해 주세요. 패키지 실패를 방지할 수 있습니다."
+    },
+    "lang": "언어",
+    "menu": {
+      "library": "미디어 저장소"
+    },
+    "path_no_exist": "해당 경로가 존재하지 않습니다.",
+    "scene": {
+      "calcDone": "계산이 완료되는 시간"
+    },
+    "sceneDetail": {
+      "exportingOut": "내보내기 진행 중",
+      "firstPacking": "압축",
+      "import": "가져오기",
+      "isCopyExist": "장면이 이미 존재합니다. 복사본으로 저장하시겠습니까?",
+      "migrageS_title": "장면 이전",
+      "reFirstPacking": "다시 패키징",
+      "stoping": "중지",
+      "updateAt": "{시간}에 업데이트됨"
+    },
+    "sceneDown": {
+      "coverStatus": {
+        "un": "계산 대기 중"
+      },
+      "msgStatus": {
+        "ing": "일시 정지",
+        "lineup": "일시 정지"
+      }
+    }
+  },
+  "record": {
+    "backHandler": "백그라운드에서 처리 중입니다",
+    "con": "녹화를 계속하다",
+    "defName": "설명 동영상 {num}",
+    "delConfirm": "비디오를 정말로 삭제하시겠습니까?",
+    "list": "전체 영상",
+    "merge": "비디오 합치기",
+    "name": "화면 녹화",
+    "nameErr": "동영상 이름은 비어 있을 수 없습니다",
+    "sizeErr": "제한 크기를 이미 초과하여 계속 녹화할 수 없습니다. 저장한 후에 다시 녹화할 수 있습니다!",
+    "start": "녹화를 시작합니다",
+    "tag": "태그",
+    "vName": "화면 녹화하다"
+  },
+  "resCode": {
+    "0": "요청이 성공했습니다",
+    "4008": "token만료되었습니다",
+    "4010": "당신은 접근 권한이 없습니다"
+  },
+  "scene": {
+    "add": "시나리오 추가 或 장면 추가",
+    "list": "장면 목록",
+    "manage": "장면 관리",
+    "tabs": {
+      "createTime": "촬영/생성 시간",
+      "name": "명칭",
+      "type": "유형"
+    },
+    "typeRaws": {
+      "0": "Mesh장면",
+      "1": "Mesh장면",
+      "2": "점운 시나리오",
+      "4": "Mesh장면",
+      "5": "점운 시나리오",
+      "6": "Mesh장면",
+      "7": "Mesh장면"
+    },
+    "types": {
+      "0": "4D KANKAN PRO/Mesh",
+      "1": "4D KANKAN MINION/Mesh",
+      "2": "4D KANKAN MEGA/점 클라우드",
+      "3": "미디어 라이브러리",
+      "4": "4D KANKAN MEGA/Mesh",
+      "5": "4D KANKAN META/점 클라우드",
+      "6": "4D KANKAN META/Mesh",
+      "7": "원주율/Mesh"
+    }
+  },
+  "sceneHome": {
+    "nameSearch": "이름 입력 후 검색",
+    "searchData": "검색 결과",
+    "selectAdd": "주소 선택",
+    "yctips": "제거할 수 없습니다. 장면이 다원 융합에 포함되어 있습니다. 다원 융합에 들어가 장면을 삭제한 후 다시 시도하세요.",
+    "yctipsErr": "제거할 수 없습니다. 장면이 다원 융합에 포함되어 있습니다. 다원 융합에 들어가 장면을 삭제한 후 다시 시도하세요."
+  },
+  "security": {
+    "name": "안전 방범"
+  },
+  "setting": {
+    "back": "하늘을 설정하다",
+    "backs[0]": "없다",
+    "backs[1]": "지도",
+    "backs[2]": "푸른 하늘과 흰 구름",
+    "backs[3]": "흑운이 몰려 있다",
+    "backs[4]": "밤하늘",
+    "backs[5]": "저녁",
+    "initView": "초기 화면",
+    "name": "설정하다"
+  },
+  "sys": {
+    "404Page": "자원이 존재하지 않거나 이미 삭제되었습니다",
+    "add": "새로 추가하다",
+    "addData": "데이터 추가",
+    "all": "전부",
+    "cancel": "취소하다",
+    "create": "만들다",
+    "crop": "자르다",
+    "cropIng": "자르고 있습니다",
+    "del": "삭제하다",
+    "delConfrm": "이 데이터를 정말로 삭제하시겠습니까?",
+    "download": "다운로드",
+    "edit": "편집하다",
+    "enter": "확정하다",
+    "errPage": "에러 페이지",
+    "expand": "펼치기",
+    "imgLoadErr": "이미지 로딩에 실패했습니다",
+    "jsError": "메모리가 부족합니다. 여러 페이지나 애플리케이션을 동시에 열지 마시고, 브라우저를 재시작한 후 다시 열어보십시오.",
+    "list": "데이터 목록",
+    "ok": "알겠습니다",
+    "other": "기타",
+    "placPWD": "비밀번호를 입력해 주세요",
+    "placeInput": "입력해 주세요",
+    "placeSelect": "선택해 주세요",
+    "pwdErr": "비밀번호가 틀렸습니다. 다시 입력해 주세요.",
+    "quit": "나가다",
+    "rename": "다시 명명하다",
+    "retract": "접기",
+    "save": "저장",
+    "search": "수색하다",
+    "serviceErr": "서비스에 이상이 발생했습니다. 잠시 후에 다시 시도해 주세요",
+    "tip": "힌트",
+    "tranCropImg": "잘라낸 사진을 전송해 주세요",
+    "unSaveMsg": "저장하지 않은 작업이 있습니다. 정말로 나가시겠습니까?",
+    "unSearch": "검색 결과가 없다",
+    "unSearchData": "검색 결과가 아직 없습니다",
+    "unSelect": "아직 옵션이 없습니다",
+    "undata": "아직 결과가 없습니다",
+    "upload": {
+      "accErr": "서식 오",
+      "accSuperErr": "{accept} 형식의 파일만 지원합니다",
+      "accept": "{accept} 등의 형식을 지원합니다",
+      "conAdd": "계속 추가하다",
+      "lenErr": "최대 {maxLen}개의 파일만 지원됩니다!",
+      "maxLen": "개수는 {maxLen}개를 초과하지 않습니다",
+      "maxSize": "크기는 {sizeStr}을(를) 초과하지 않습니다,",
+      "normalizeScale": "가로세로 비율 {scale}입니다,",
+      "place1": "파일 업로드",
+      "previewErr": "미리보기 로딩에 실패했습니다!",
+      "rep": "바꾸다",
+      "scaleErr": "{name}의 비율 부위는 {scale}이 아닙니다",
+      "sizeErr": "{name}의 크기가 {sizeStr}를 초과했습니다"
+    },
+    "viewPWD": "액세스 비밀번호"
+  },
+  "tagging": {
+    "apply": "전체에 적용하다",
+    "applyConfirm": "이 속성을 모든 위치에 적용하시겠습니까?",
+    "list": "태그 목록",
+    "media": "이미지/비디오",
+    "mic": "음악",
+    "micPlc": "mp3/wav 형식을 지원하며, 30MB 이하입니다",
+    "name": "태그",
+    "plcMedia1": "JPG, PNG, MP4 등의 형식을 지원하며, 개별 파일 크기는 100MB를 넘을 수 없으며, 최대 10장까지 업로드할 수 있습니다.",
+    "plcMethod": "추출 방법:",
+    "plcPart": "유적 부분:",
+    "plcPos": "놓는 위치",
+    "plcPrincipal": "추출자:",
+    "plcTitle": "라벨 제목을 입력해 주세요",
+    "plcType": "묘사:",
+    "plcType1": "특징 기술:",
+    "pleMedia": "사진/비디오 업로드",
+    "pos": "놓다",
+    "posErr": "현재 위치에서는 추가할 수 없습니다",
+    "posName": "위치",
+    "posTabs": {
+      "fontSize": "글자 크기",
+      "globalVisibility": "전체 범위가 시야에 들어옵니다",
+      "lineHeight": "리드 높이",
+      "rotation": "회전 아이콘",
+      "scale": "아이콘 크기",
+      "type": "아이콘 배치 방법",
+      "typeVal[0]": "부유하다",
+      "typeVal[1]": "땅/벽에 붙이다",
+      "visibilityRange": "시야 범위"
+    },
+    "posTip": "모델 위에서 클릭하여 라벨 위치를 선택해 주세요",
+    "style": "아이콘 스타일",
+    "styleErr": "아이콘 스타일을 선택해 주세요",
+    "tabs": {
+      "method": "추출 방법",
+      "part": "유적 부분",
+      "principal": "추출자",
+      "typeId": "특징 기술"
+    },
+    "titleErr": "태그 제목은 필수로 기입해야 합니다!",
+    "titleFex": "제목이 상주됩니다",
+    "type": {
+      "1": "흔적",
+      "2": "손인장",
+      "3": "발자국",
+      "4": "피 흔적 ",
+      "5": "시체",
+      "6": "기타",
+      "7": "물증"
+    }
+  },
+  "view": {
+    "all": "전체 뷰",
+    "defName": "뷰 {num}",
+    "name": "뷰 추출",
+    "nameErr": "뷰 이름은 비어 있을 수 없습니다",
+    "vName": "뷰"
+  }
+}

+ 310 - 0
src/lang/locales/zh.json

@@ -0,0 +1,310 @@
+{
+  "case": {
+    "cols": {
+      "caseAddress": "案发地点",
+      "caseCategory": "案件类别",
+      "caseNum": "立案编号",
+      "caseRegion": "案发区域",
+      "caseTitle": "案件名称",
+      "crimeTime": "案发时间",
+      "criminalCase": "是否刑案",
+      "homicideCase": "是否命案",
+      "latAndLong": "经纬度"
+    },
+    "name": "案件信息",
+    "nv": "否",
+    "sn": "案件名称",
+    "summary": "案件概要",
+    "tmCols": {
+      "alarmName": "报警人",
+      "alarmTime": "报警时间",
+      "assignDept": "指派/报告单位",
+      "assignType": "指派方式",
+      "commandTime": "指挥中心电话时间",
+      "inquestAddress": "勘验地点",
+      "inquestDept": "现场勘验单位",
+      "times": "勘验时间"
+    },
+    "tmName": "勘验信息",
+    "yv": "是"
+  },
+  "floder": {
+    "extractList": "提取清单",
+    "name": "卷宗",
+    "photo": "照片制卷",
+    "record": "勘验笔录"
+  },
+  "fuse": {
+    "dataQue": "数据来源",
+    "dataSize": "数据大小",
+    "dataTime": "拍摄时间",
+    "def": "恢复默认",
+    "defConfirm": "确定恢复默认?此操作无法撤销",
+    "flip": "旋转",
+    "hre": "请在当前窗口调整垂直方向位置",
+    "join": "拼接",
+    "label": "融合场景",
+    "len": "长度",
+    "model": "三维模型",
+    "move": "移动",
+    "name": "多元融合",
+    "opacity": "模型不透明度",
+    "opacity1": "透明度",
+    "pano": "全景图",
+    "reSelect": "重新选点",
+    "registration": "配准",
+    "repScale": "等比缩放",
+    "selectTip": "请选择两点标记一段已知长度,并输入真实长度",
+    "setScale": "设置比例",
+    "sync": "同屏勘验",
+    "syncErr": "带看仅支持{types}类型场景,请添加此类型场景。",
+    "unModel": "模型不存在!",
+    "vre": "请在当前窗口调整水平方向位置"
+  },
+  "guide": {
+    "defTitle": "路径{num}",
+    "guide": {
+      "add": "添加视角",
+      "clear": "清空画面",
+      "clearConfirm": "确定要清空画面吗?",
+      "delConfirm": "确定要删除此画面吗?",
+      "name": "导览",
+      "time": "视频时长",
+      "unItems": "无法保存空路径导览!",
+      "undata": "暂无导览"
+    },
+    "guideName": "导览({count})",
+    "modelErr": "路径所在模型被删除,无法播放",
+    "name": "路径",
+    "nameErr": "路径名称不可为空",
+    "pErr": "路径点不可少于两个",
+    "path": {
+      "applyConfirm": "确定要将此属性应用到所有位置?",
+      "fontSize": "文字大小",
+      "globalVisibility": "全部范围可视",
+      "lineColor": "路径颜色",
+      "lineWidth": "路径粗细",
+      "name": "路线",
+      "pointDesc": "描述",
+      "pointTitle": "编辑点",
+      "preview": "预览路径",
+      "reverseDirection": "箭头反向",
+      "showDirection": "路径箭头",
+      "stop": "停止",
+      "title": "路径名称",
+      "visibilityRange": "可见范围"
+    },
+    "pathName": "路线({count})"
+  },
+  "material": {
+    "name": "媒体库",
+    "search": "输入名称搜索",
+    "selectCount": "已选择数据",
+    "selectErr": "最多选择{count}项",
+    "tabs": {
+      "action": "操作",
+      "format": "格式",
+      "group": "分组",
+      "name": "名称",
+      "size": "大小",
+      "status": "状态"
+    },
+    "up": "+从媒体库上传",
+    "uploadErr": "上传失败",
+    "uploadIng": "上传中",
+    "uploadSuccess": "上传成功"
+  },
+  "measure": {
+    "area": {
+      "desc": "面积",
+      "unit": "面积"
+    },
+    "free": {
+      "desc": "自由",
+      "unit": "长度"
+    },
+    "list": "测量列表",
+    "name": "测量",
+    "nameErr": "测量名称不可为空",
+    "vertical": {
+      "desc": "垂直",
+      "unit": "长度"
+    }
+  },
+  "record": {
+    "backHandler": "后台正在处理",
+    "con": "继续录制",
+    "defName": "讲解视频{num}",
+    "delConfirm": "确定要删除视频吗?",
+    "list": "全部视频",
+    "merge": "合并视频",
+    "name": "屏幕录制",
+    "nameErr": "视频名称不可为空",
+    "sizeErr": "已超出限制大小无法继续录制,可保存后继续录制!",
+    "start": "开始录制",
+    "tag": "标签",
+    "vName": "录屏"
+  },
+  "resCode": {
+    "0": "请求成功",
+    "4008": "token已失效",
+    "4010": "您没有访问权限",
+    "40110": "您没有编辑权限",
+    "40111": "您没有访问权限"
+  },
+  "scene": {
+    "add": "添加场景",
+    "list": "场景列表",
+    "manage": "场景管理",
+    "tabs": {
+      "createTime": "拍摄/创建时间",
+      "name": "名称",
+      "type": "类型"
+    },
+    "typeRaws": {
+      "0": "Mesh场景",
+      "1": "Mesh场景",
+      "2": "点云场景",
+      "4": "Mesh场景",
+      "5": "点云场景",
+      "6": "Mesh场景",
+      "7": "Mesh场景"
+    },
+    "types": {
+      "0": "四维看看/Mesh",
+      "1": "四维看见/Mesh",
+      "2": "四维深时/点云",
+      "3": "媒体库",
+      "4": "四维深时/Mesh",
+      "5": "四维深光/点云",
+      "6": "四维深光/Mesh",
+      "7": "圆周率/Mesh"
+    }
+  },
+  "security": {
+    "name": "安防"
+  },
+  "setting": {
+    "back": "设置天空",
+    "backs[0]": "无",
+    "backs[1]": "地图",
+    "backs[2]": "蓝天白云",
+    "backs[3]": "乌云密布",
+    "backs[4]": "夜空",
+    "backs[5]": "傍晚",
+    "initView": "初始画面",
+    "name": "设置"
+  },
+  "sys": {
+    "404Page": "资源不存在或已删除",
+    "add": "新增",
+    "addData": "添加数据",
+    "all": "全部",
+    "cancel": "取消",
+    "create": "创建",
+    "crop": "裁剪",
+    "cropIng": "正在裁剪",
+    "del": "删除",
+    "delConfrm": "确定要删除此数据吗?",
+    "download": "下载",
+    "edit": "编辑",
+    "enter": "确定",
+    "errPage": "错误页面",
+    "imgLoadErr": "图片加载失败",
+    "jsError": "内存不足,请勿同时打开多个页面或应用程序,尝试重启浏览器后重新打开。",
+    "list": "数据列表",
+    "ok": "我知道了",
+    "other": "其他",
+    "placPWD": "请输入密码!",
+    "placeInput": "请输入",
+    "placeSelect": "请选择",
+    "pwdErr": "密码错误,请重新输入。",
+    "quit": "退出",
+    "rename": "重命名",
+    "save": "保存",
+    "search": "搜索",
+    "serviceErr": "服务出现异常,请稍后再试",
+    "tip": "提示",
+    "tranCropImg": "请传入裁剪图片",
+    "unSaveMsg": "您有操作未保存,确定要退出吗?",
+    "unSearch": "无搜索结果",
+    "unSearchData": "暂无搜索结果",
+    "unSelect": "暂无选项",
+    "undata": "暂无结果",
+    "upload": {
+      "accErr": "格式错误",
+      "accSuperErr": "仅支持{accept}格式文件",
+      "accept": "支持 {accept} 等格式,",
+      "conAdd": "继续添加",
+      "lenErr": "最多仅支持{maxLen}个文件!",
+      "maxLen": "个数不超过 {maxLen}个",
+      "maxSize": "大小不超过 {sizeStr},",
+      "normalizeScale": "宽*高比例 {scale},",
+      "place1": "上传文件",
+      "previewErr": "预览加载失败!",
+      "rep": "替换",
+      "scaleErr": "{name}的比例部位不为{scale}",
+      "sizeErr": "{name}的大小超过{sizeStr}"
+    },
+    "viewPWD": "访问密码"
+  },
+  "tagging": {
+    "apply": "应用到全部",
+    "applyConfirm": "确定要将此属性应用到所有位置?",
+    "list": "标签列表",
+    "media": "图片/视频",
+    "mic": "音乐",
+    "micPlc": "支持 mp3/wav 格式,≤30MB",
+    "name": "标签",
+    "plcMedia1": "支持JPG、PNG、MP4等格式,单个不超过100MB,最多支持上传10张。",
+    "plcMethod": "提取方法:",
+    "plcPart": "遗留部位:",
+    "plcPos": "放置位置",
+    "plcPrincipal": "提取人:",
+    "plcTitle": "请输入标签标题",
+    "plcType": "描述:",
+    "plcType1": "特征描述:",
+    "pleMedia": "上传图片/视频",
+    "pos": "放置",
+    "posErr": "当前位置无法添加",
+    "posName": "位置",
+    "posTabs": {
+      "fontSize": "文字大小",
+      "globalVisibility": "全部范围可视",
+      "lineHeight": "引线高度",
+      "rotation": "旋转图标",
+      "scale": "图标大小",
+      "type": "图标放置方式",
+      "typeVal[0]": "悬浮",
+      "typeVal[1]": "贴地/墙",
+      "visibilityRange": "可见范围"
+    },
+    "posTip": "请在模型上单击选择标签位置",
+    "style": "图标样式",
+    "styleErr": "请选择图标样式!",
+    "tabs": {
+      "method": "提取方法",
+      "part": "遗留部位",
+      "principal": "提取人",
+      "typeId": "特征描述"
+    },
+    "titleErr": "标签标题必须填写!",
+    "titleFex": "标题常驻",
+    "type": {
+      "1": "痕迹",
+      "2": "手印",
+      "3": "足迹",
+      "4": "血迹 ",
+      "5": "尸体",
+      "6": "其他",
+      "7": "物证"
+    }
+  },
+  "view": {
+    "all": "全部视图",
+    "defName": "视图 {num}",
+    "name": "视图提取",
+    "nameErr": "视图名称不可为空",
+    "vName": "视图"
+  }
+}

+ 0 - 45
translate.js

@@ -1,45 +0,0 @@
-// const http = require('http')
-// const fs = require('fs')
-import http from 'http'
-import fs from 'fs'
-
-function checkIfPhishing(urlToPrint, path, lang = 'zh') {
-  fs.mkdirSync(path, { recursive: true })
-  const file = fs.createWriteStream(`${path}/${lang}.json`)
-  const request = http.get(urlToPrint, function (response) {
-    response
-      .on('finish', function () {
-        console.log('done')
-        // console.log(fs.readFileSync(`${lang}.json`, { encoding: "utf8" }));
-      })
-      .pipe(file)
-  })
-}
-//  zh
-checkIfPhishing(
-  'http://192.168.0.163:8080/download/4kankan/fuse-code/zh_Hans/',
-  'src/lang/weblate',
-  'zh'
-)
-//  en
-checkIfPhishing(
-  'http://192.168.0.163:8080/download/4kankan/fuse-code/en/',
-  'src/lang/weblate',
-  'en'
-)
-//  ja
-checkIfPhishing(
-  'http://192.168.0.163:8080/download/4kankan/fuse-code/ja/',
-  'src/lang/weblate',
-  'ja'
-)
-
-//  ja
-checkIfPhishing(
-  'http://192.168.0.163:8080/download/4kankan/fuse-code/ko/',
-  'src/lang/weblate',
-  'kr'
-)
-
-
-