mirror of
https://github.com/siddharthvaddem/openscreen.git
synced 2026-11-03 06:04:11 +08:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fc85270bc | ||
|
|
42468c13b6 | ||
|
|
dca91b4f86 | ||
|
|
80a3b1e4d3 | ||
|
|
2704c280bd |
Generated
+53
-33
@@ -188,7 +188,6 @@
|
||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.29.0",
|
||||
"@babel/generator": "^7.29.0",
|
||||
@@ -397,7 +396,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -721,7 +719,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
@@ -770,7 +767,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
@@ -1202,6 +1198,7 @@
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cross-dirname": "^0.1.0",
|
||||
"debug": "^4.3.4",
|
||||
@@ -1223,6 +1220,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
@@ -1239,6 +1237,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
@@ -1253,6 +1252,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
@@ -1962,6 +1962,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@pixi/color/-/color-7.4.3.tgz",
|
||||
"integrity": "sha512-a6R+bXKeXMDcRmjYQoBIK+v2EYqxSX49wcjAY579EYM/WrFKS98nSees6lqVUcLKrcQh2DT9srJHX7XMny3voQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@pixi/colord": "^2.9.6"
|
||||
}
|
||||
@@ -1976,7 +1977,8 @@
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-7.4.3.tgz",
|
||||
"integrity": "sha512-QGmwJUNQy/vVEHzL6VGQvnwawLZ1wceZMI8HwJAT4/I2uAzbBeFDdmCS8WsTpSWLZjF/DszDc1D8BFp4pVJ5UQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@pixi/core": {
|
||||
"version": "7.4.3",
|
||||
@@ -2003,7 +2005,8 @@
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@pixi/extensions/-/extensions-7.4.3.tgz",
|
||||
"integrity": "sha512-FhoiYkHQEDYHUE7wXhqfsTRz6KxLXjuMbSiAwnLb9uG1vAgp6q6qd6HEsf4X30YaZbLFY8a4KY6hFZWjF+4Fdw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@pixi/filter-drop-shadow": {
|
||||
"version": "5.2.0",
|
||||
@@ -2030,19 +2033,22 @@
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@pixi/math/-/math-7.4.3.tgz",
|
||||
"integrity": "sha512-/uJOVhR2DOZ+zgdI6Bs/CwcXT4bNRKsS+TqX3ekRIxPCwaLra+Qdm7aDxT5cTToDzdxbKL5+rwiLu3Y1egILDw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@pixi/runner": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-7.4.3.tgz",
|
||||
"integrity": "sha512-TJyfp7y23u5vvRAyYhVSa7ytq0PdKSvPLXu4G3meoFh1oxTLHH6g/RIzLuxUAThPG2z7ftthuW3qWq6dRV+dhw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@pixi/settings": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-7.4.3.tgz",
|
||||
"integrity": "sha512-SmGK8smc0PxRB9nr0UJioEtE9hl4gvj9OedCvZx3bxBwA3omA5BmP3CyhQfN8XJ29+o2OUL01r3zAPVol4l4lA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@pixi/constants": "7.4.3",
|
||||
"@types/css-font-loading-module": "^0.0.12",
|
||||
@@ -2054,6 +2060,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-7.4.3.tgz",
|
||||
"integrity": "sha512-tHsAD0iOUb6QSGGw+c8cyRBvxsq/NlfzIFBZLEHhWZ+Bx4a0MmXup6I/yJDGmyPCYE+ctCcAfY13wKAzdiVFgQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@pixi/extensions": "7.4.3",
|
||||
"@pixi/settings": "7.4.3",
|
||||
@@ -2065,6 +2072,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-7.4.3.tgz",
|
||||
"integrity": "sha512-NO3Y9HAn2UKS1YdxffqsPp+kDpVm8XWvkZcS/E+rBzY9VTLnNOI7cawSRm+dacdET3a8Jad3aDKEDZ0HmAqAFA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@pixi/color": "7.4.3",
|
||||
"@pixi/constants": "7.4.3",
|
||||
@@ -3643,7 +3651,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
@@ -3718,7 +3727,8 @@
|
||||
"version": "0.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.12.tgz",
|
||||
"integrity": "sha512-x2tZZYkSxXqWvTDgveSynfjq/T2HyiZHXb00j/+gy19yp70PHCizM48XFdjBCWH7eHBD0R5i/pw9yMBP/BH5uA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/debug": {
|
||||
"version": "4.1.13",
|
||||
@@ -3756,7 +3766,8 @@
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.4.tgz",
|
||||
"integrity": "sha512-qp3m9PPz4gULB9MhjGID7wpo3gJ4bTGXm7ltNDsmOvsPduTeHp8wSW9YckBj3mljeOh4F0m2z/0JKAALRKbmLQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
@@ -3855,7 +3866,6 @@
|
||||
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
@@ -3867,7 +3877,6 @@
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
@@ -4149,7 +4158,6 @@
|
||||
"integrity": "sha512-CWy0lBQJq97nionyJJdnaU4961IXTl43a7UCu5nHy51IoKxAt6PVIJLo+76rVl7KOOgcWHNkG4kbJu/pW7knvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/browser": "4.1.5",
|
||||
"@vitest/mocker": "4.1.5",
|
||||
@@ -4342,7 +4350,6 @@
|
||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -4868,7 +4875,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.10.12",
|
||||
"caniuse-lite": "^1.0.30001782",
|
||||
@@ -5050,6 +5056,7 @@
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
|
||||
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"get-intrinsic": "^1.3.0"
|
||||
@@ -5400,7 +5407,8 @@
|
||||
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
@@ -5690,7 +5698,6 @@
|
||||
"integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"app-builder-lib": "26.8.1",
|
||||
"builder-util": "26.8.1",
|
||||
@@ -5783,7 +5790,8 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.6.1",
|
||||
@@ -5832,7 +5840,8 @@
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
|
||||
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==",
|
||||
"license": "ISC"
|
||||
"license": "ISC",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/ejs": {
|
||||
"version": "3.1.10",
|
||||
@@ -6015,6 +6024,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.1",
|
||||
"debug": "^4.1.1",
|
||||
@@ -6035,6 +6045,7 @@
|
||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
@@ -6277,7 +6288,8 @@
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/expect-type": {
|
||||
"version": "1.3.0",
|
||||
@@ -7689,6 +7701,7 @@
|
||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
@@ -7908,6 +7921,7 @@
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
@@ -8221,6 +8235,7 @@
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -8429,7 +8444,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.18.1.tgz",
|
||||
"integrity": "sha512-6LUPWYgulZhp/w4kam2XHXB0QedISZIqrJbRdHLLQ3csn5a38uzKxAp6B5j6s89QFYaIJbg95kvgTRcbgpO1ow==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"workspaces": [
|
||||
"examples",
|
||||
"playground"
|
||||
@@ -8475,7 +8489,6 @@
|
||||
"integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"playwright-core": "1.59.1"
|
||||
},
|
||||
@@ -8546,7 +8559,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -8691,6 +8703,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"commander": "^9.4.0"
|
||||
},
|
||||
@@ -8708,6 +8721,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
@@ -8718,6 +8732,7 @@
|
||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
@@ -8733,6 +8748,7 @@
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -8846,6 +8862,7 @@
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
|
||||
"integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
},
|
||||
@@ -8904,7 +8921,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -8917,7 +8933,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -8954,7 +8969,8 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.18.0",
|
||||
@@ -9275,6 +9291,7 @@
|
||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
@@ -9481,6 +9498,7 @@
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3",
|
||||
@@ -9500,6 +9518,7 @@
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
|
||||
"integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.4"
|
||||
@@ -9516,6 +9535,7 @@
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -9534,6 +9554,7 @@
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -9874,7 +9895,6 @@
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
||||
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
@@ -9958,6 +9978,7 @@
|
||||
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mkdirp": "^0.5.1",
|
||||
"rimraf": "~2.6.2"
|
||||
@@ -10358,6 +10379,7 @@
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
|
||||
"integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"punycode": "^1.4.1",
|
||||
"qs": "^6.12.3"
|
||||
@@ -10370,7 +10392,8 @@
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/use-callback-ref": {
|
||||
"version": "1.3.3",
|
||||
@@ -10463,7 +10486,6 @@
|
||||
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -10553,8 +10575,7 @@
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.6.tgz",
|
||||
"integrity": "sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite/node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
@@ -10577,7 +10598,6 @@
|
||||
"integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.5",
|
||||
"@vitest/mocker": "4.1.5",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*
|
||||
* Usage: node scripts/i18n-check.mjs
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { useI18n, useScopedT } from "@/contexts/I18nContext";
|
||||
import { useShortcuts } from "@/contexts/ShortcutsContext";
|
||||
import { useClipboardFeedback } from "@/hooks/useClipboardFeedback";
|
||||
import { INITIAL_EDITOR_STATE, useEditorHistory } from "@/hooks/useEditorHistory";
|
||||
import { type Locale } from "@/i18n/config";
|
||||
import { getAvailableLocales, getLocaleName } from "@/i18n/loader";
|
||||
@@ -58,6 +59,11 @@ import {
|
||||
} from "./projectPersistence";
|
||||
import { SettingsPanel } from "./SettingsPanel";
|
||||
import TimelineEditor from "./timeline/TimelineEditor";
|
||||
import {
|
||||
cloneAnnotationRegion,
|
||||
getPastedAnnotationPosition,
|
||||
spansOverlap,
|
||||
} from "./timelineClipboardUtils";
|
||||
import {
|
||||
type AnnotationRegion,
|
||||
type BlurData,
|
||||
@@ -84,6 +90,13 @@ import {
|
||||
import { UnsavedChangesDialog } from "./UnsavedChangesDialog";
|
||||
import VideoPlayback, { VideoPlaybackRef } from "./VideoPlayback";
|
||||
|
||||
type TimelineClipboardItem =
|
||||
| { kind: "zoom"; region: ZoomRegion }
|
||||
| { kind: "trim"; region: TrimRegion }
|
||||
| { kind: "speed"; region: SpeedRegion }
|
||||
| { kind: "annotation"; region: AnnotationRegion }
|
||||
| { kind: "blur"; region: AnnotationRegion };
|
||||
|
||||
export default function VideoEditor() {
|
||||
const {
|
||||
state: editorState,
|
||||
@@ -154,6 +167,7 @@ export default function VideoEditor() {
|
||||
format: string;
|
||||
} | null>(null);
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
const [timelineClipboard, setTimelineClipboard] = useState<TimelineClipboardItem | null>(null);
|
||||
const [showCloseConfirmDialog, setShowCloseConfirmDialog] = useState(false);
|
||||
|
||||
const playerContainerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -164,6 +178,7 @@ export default function VideoEditor() {
|
||||
const nextSpeedIdRef = useRef(1);
|
||||
|
||||
const { shortcuts, isMac } = useShortcuts();
|
||||
const { notifyCopied, notifyPasted } = useClipboardFeedback();
|
||||
// Off-Mac doesn't have click telemetry, so force `onlyOnClicks` off for
|
||||
// renderers while keeping the persisted value intact for round-tripping.
|
||||
const effectiveCursorHighlight = useMemo(
|
||||
@@ -173,6 +188,7 @@ export default function VideoEditor() {
|
||||
const { locale, setLocale, t: rawT } = useI18n();
|
||||
const t = useScopedT("editor");
|
||||
const ts = useScopedT("settings");
|
||||
const tt = useScopedT("timeline");
|
||||
const availableLocales = getAvailableLocales();
|
||||
|
||||
const nextAnnotationIdRef = useRef(1);
|
||||
@@ -1088,6 +1104,219 @@ export default function VideoEditor() {
|
||||
[pushState],
|
||||
);
|
||||
|
||||
const handleCopySelectedTimelineItem = useCallback(() => {
|
||||
if (selectedAnnotationId) {
|
||||
const region = annotationOnlyRegions.find((item) => item.id === selectedAnnotationId);
|
||||
if (region) {
|
||||
setTimelineClipboard({ kind: "annotation", region: cloneAnnotationRegion(region) });
|
||||
notifyCopied();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedBlurId) {
|
||||
const region = blurRegions.find((item) => item.id === selectedBlurId);
|
||||
if (region) {
|
||||
setTimelineClipboard({ kind: "blur", region: cloneAnnotationRegion(region) });
|
||||
notifyCopied();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedZoomId) {
|
||||
const region = zoomRegions.find((item) => item.id === selectedZoomId);
|
||||
if (region) {
|
||||
setTimelineClipboard({ kind: "zoom", region: { ...region, focus: { ...region.focus } } });
|
||||
notifyCopied();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedTrimId) {
|
||||
const region = trimRegions.find((item) => item.id === selectedTrimId);
|
||||
if (region) {
|
||||
setTimelineClipboard({ kind: "trim", region: { ...region } });
|
||||
notifyCopied();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedSpeedId) {
|
||||
const region = speedRegions.find((item) => item.id === selectedSpeedId);
|
||||
if (region) {
|
||||
setTimelineClipboard({ kind: "speed", region: { ...region } });
|
||||
notifyCopied();
|
||||
}
|
||||
}
|
||||
}, [
|
||||
selectedAnnotationId,
|
||||
selectedBlurId,
|
||||
selectedZoomId,
|
||||
selectedTrimId,
|
||||
selectedSpeedId,
|
||||
annotationOnlyRegions,
|
||||
blurRegions,
|
||||
zoomRegions,
|
||||
trimRegions,
|
||||
speedRegions,
|
||||
notifyCopied,
|
||||
]);
|
||||
|
||||
const handlePasteTimelineItem = useCallback(() => {
|
||||
if (!timelineClipboard) return;
|
||||
|
||||
const totalMs = Math.max(0, Math.round(duration * 1000));
|
||||
if (totalMs <= 0) return;
|
||||
|
||||
const sourceDuration = Math.max(
|
||||
1,
|
||||
timelineClipboard.region.endMs - timelineClipboard.region.startMs,
|
||||
);
|
||||
const pastedDuration = Math.min(sourceDuration, totalMs);
|
||||
const currentTimeMs = Math.max(0, Math.round(currentTime * 1000));
|
||||
const targetStart = Math.min(currentTimeMs, Math.max(0, totalMs - pastedDuration));
|
||||
const targetEnd = Math.min(totalMs, targetStart + pastedDuration);
|
||||
|
||||
function clearTimelineSelection() {
|
||||
setSelectedZoomId(null);
|
||||
setSelectedTrimId(null);
|
||||
setSelectedAnnotationId(null);
|
||||
setSelectedBlurId(null);
|
||||
setSelectedSpeedId(null);
|
||||
}
|
||||
|
||||
function pasteSpanRegion<T extends { id: string; startMs: number; endMs: number }>(config: {
|
||||
existingRegions: T[];
|
||||
createId: () => string;
|
||||
createRegion: (id: string) => T;
|
||||
pushRegion: (region: T) => void;
|
||||
selectRegion: (id: string) => void;
|
||||
errorTitle: string;
|
||||
errorDescription: string;
|
||||
}): void {
|
||||
const hasConflict = config.existingRegions.some((region) =>
|
||||
spansOverlap(region.startMs, region.endMs, targetStart, targetEnd),
|
||||
);
|
||||
if (hasConflict) {
|
||||
toast.error(config.errorTitle, {
|
||||
description: config.errorDescription,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const id = config.createId();
|
||||
config.pushRegion(config.createRegion(id));
|
||||
clearTimelineSelection();
|
||||
config.selectRegion(id);
|
||||
notifyPasted();
|
||||
}
|
||||
|
||||
if (timelineClipboard.kind === "annotation" || timelineClipboard.kind === "blur") {
|
||||
const id = `annotation-${nextAnnotationIdRef.current++}`;
|
||||
const zIndex = nextAnnotationZIndexRef.current++;
|
||||
const source = cloneAnnotationRegion(timelineClipboard.region);
|
||||
const pasted: AnnotationRegion = {
|
||||
...source,
|
||||
id,
|
||||
startMs: targetStart,
|
||||
endMs: targetEnd,
|
||||
zIndex,
|
||||
position: getPastedAnnotationPosition(source.position, source.size),
|
||||
};
|
||||
|
||||
pushState((prev) => ({
|
||||
annotationRegions: [...prev.annotationRegions, pasted],
|
||||
}));
|
||||
|
||||
if (timelineClipboard.kind === "blur") {
|
||||
setSelectedBlurId(id);
|
||||
setSelectedAnnotationId(null);
|
||||
} else {
|
||||
setSelectedAnnotationId(id);
|
||||
setSelectedBlurId(null);
|
||||
}
|
||||
setSelectedZoomId(null);
|
||||
setSelectedTrimId(null);
|
||||
setSelectedSpeedId(null);
|
||||
notifyPasted();
|
||||
return;
|
||||
}
|
||||
|
||||
if (timelineClipboard.kind === "zoom") {
|
||||
pasteSpanRegion({
|
||||
existingRegions: zoomRegions,
|
||||
createId: () => `zoom-${nextZoomIdRef.current++}`,
|
||||
createRegion: (id) => ({
|
||||
...timelineClipboard.region,
|
||||
id,
|
||||
startMs: targetStart,
|
||||
endMs: targetEnd,
|
||||
focus: { ...timelineClipboard.region.focus },
|
||||
}),
|
||||
pushRegion: (region) => {
|
||||
pushState((prev) => ({
|
||||
zoomRegions: [...prev.zoomRegions, region],
|
||||
}));
|
||||
},
|
||||
selectRegion: setSelectedZoomId,
|
||||
errorTitle: tt("errors.cannotPlaceZoom"),
|
||||
errorDescription: tt("errors.zoomExistsAtLocation"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (timelineClipboard.kind === "trim") {
|
||||
pasteSpanRegion({
|
||||
existingRegions: trimRegions,
|
||||
createId: () => `trim-${nextTrimIdRef.current++}`,
|
||||
createRegion: (id) => ({
|
||||
...timelineClipboard.region,
|
||||
id,
|
||||
startMs: targetStart,
|
||||
endMs: targetEnd,
|
||||
}),
|
||||
pushRegion: (region) => {
|
||||
pushState((prev) => ({
|
||||
trimRegions: [...prev.trimRegions, region],
|
||||
}));
|
||||
},
|
||||
selectRegion: setSelectedTrimId,
|
||||
errorTitle: tt("errors.cannotPlaceTrim"),
|
||||
errorDescription: tt("errors.trimExistsAtLocation"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
pasteSpanRegion({
|
||||
existingRegions: speedRegions,
|
||||
createId: () => `speed-${nextSpeedIdRef.current++}`,
|
||||
createRegion: (id) => ({
|
||||
...timelineClipboard.region,
|
||||
id,
|
||||
startMs: targetStart,
|
||||
endMs: targetEnd,
|
||||
}),
|
||||
pushRegion: (region) => {
|
||||
pushState((prev) => ({
|
||||
speedRegions: [...prev.speedRegions, region],
|
||||
}));
|
||||
},
|
||||
selectRegion: setSelectedSpeedId,
|
||||
errorTitle: tt("errors.cannotPlaceSpeed"),
|
||||
errorDescription: tt("errors.speedExistsAtLocation"),
|
||||
});
|
||||
}, [
|
||||
timelineClipboard,
|
||||
duration,
|
||||
currentTime,
|
||||
pushState,
|
||||
zoomRegions,
|
||||
trimRegions,
|
||||
speedRegions,
|
||||
tt,
|
||||
notifyPasted,
|
||||
]);
|
||||
|
||||
const handleAnnotationDelete = useCallback(
|
||||
(id: string) => {
|
||||
pushState((prev) => ({
|
||||
@@ -2190,6 +2419,16 @@ export default function VideoEditor() {
|
||||
onBlurDelete={handleAnnotationDelete}
|
||||
selectedBlurId={selectedBlurId}
|
||||
onSelectBlur={handleSelectBlur}
|
||||
canCopySelectedItem={
|
||||
!!selectedZoomId ||
|
||||
!!selectedTrimId ||
|
||||
!!selectedAnnotationId ||
|
||||
!!selectedBlurId ||
|
||||
!!selectedSpeedId
|
||||
}
|
||||
canPasteTimelineItem={!!timelineClipboard && duration > 0}
|
||||
onCopySelectedItem={handleCopySelectedTimelineItem}
|
||||
onPasteTimelineItem={handlePasteTimelineItem}
|
||||
aspectRatio={aspectRatio}
|
||||
onAspectRatioChange={(ar) =>
|
||||
pushState({
|
||||
|
||||
@@ -85,6 +85,10 @@ interface TimelineEditorProps {
|
||||
onSpeedDelete?: (id: string) => void;
|
||||
selectedSpeedId?: string | null;
|
||||
onSelectSpeed?: (id: string | null) => void;
|
||||
canCopySelectedItem?: boolean;
|
||||
canPasteTimelineItem?: boolean;
|
||||
onCopySelectedItem?: () => void;
|
||||
onPasteTimelineItem?: () => void;
|
||||
aspectRatio: AspectRatio;
|
||||
onAspectRatioChange: (aspectRatio: AspectRatio) => void;
|
||||
}
|
||||
@@ -800,6 +804,10 @@ export default function TimelineEditor({
|
||||
onSpeedDelete,
|
||||
selectedSpeedId,
|
||||
onSelectSpeed,
|
||||
canCopySelectedItem = false,
|
||||
canPasteTimelineItem = false,
|
||||
onCopySelectedItem,
|
||||
onPasteTimelineItem,
|
||||
aspectRatio,
|
||||
onAspectRatioChange,
|
||||
}: TimelineEditorProps) {
|
||||
@@ -1228,7 +1236,42 @@ export default function TimelineEditor({
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
|
||||
const target = e.target;
|
||||
const isEditableTarget =
|
||||
target instanceof HTMLInputElement ||
|
||||
target instanceof HTMLTextAreaElement ||
|
||||
target instanceof HTMLSelectElement ||
|
||||
(target instanceof HTMLElement && target.isContentEditable);
|
||||
if (isEditableTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mod = isMac ? e.metaKey : e.ctrlKey;
|
||||
const key = e.key.toLowerCase();
|
||||
|
||||
if (
|
||||
mod &&
|
||||
!e.shiftKey &&
|
||||
!e.altKey &&
|
||||
key === "c" &&
|
||||
canCopySelectedItem &&
|
||||
onCopySelectedItem
|
||||
) {
|
||||
e.preventDefault();
|
||||
onCopySelectedItem();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
mod &&
|
||||
!e.shiftKey &&
|
||||
!e.altKey &&
|
||||
key === "v" &&
|
||||
canPasteTimelineItem &&
|
||||
onPasteTimelineItem
|
||||
) {
|
||||
e.preventDefault();
|
||||
onPasteTimelineItem();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1320,6 +1363,10 @@ export default function TimelineEditor({
|
||||
onSelectAnnotation,
|
||||
keyShortcuts,
|
||||
isMac,
|
||||
canCopySelectedItem,
|
||||
canPasteTimelineItem,
|
||||
onCopySelectedItem,
|
||||
onPasteTimelineItem,
|
||||
]);
|
||||
|
||||
const clampedRange = useMemo<Range>(() => {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
cloneAnnotationRegion,
|
||||
getPastedAnnotationPosition,
|
||||
spansOverlap,
|
||||
} from "./timelineClipboardUtils";
|
||||
import type { AnnotationRegion } from "./types";
|
||||
|
||||
function createAnnotationRegion(overrides: Partial<AnnotationRegion> = {}): AnnotationRegion {
|
||||
return {
|
||||
id: "annotation-1",
|
||||
startMs: 100,
|
||||
endMs: 600,
|
||||
type: "blur",
|
||||
content: "",
|
||||
position: { x: 10, y: 15 },
|
||||
size: { width: 30, height: 20 },
|
||||
style: {
|
||||
color: "#fff",
|
||||
backgroundColor: "transparent",
|
||||
fontSize: 32,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: "bold",
|
||||
fontStyle: "normal",
|
||||
textDecoration: "none",
|
||||
textAlign: "center",
|
||||
},
|
||||
zIndex: 1,
|
||||
blurData: {
|
||||
type: "mosaic",
|
||||
shape: "freehand",
|
||||
color: "white",
|
||||
intensity: 12,
|
||||
blockSize: 8,
|
||||
freehandPoints: [
|
||||
{ x: 10, y: 20 },
|
||||
{ x: 30, y: 40 },
|
||||
],
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("timelineClipboardUtils", () => {
|
||||
it("deep clones nested annotation data", () => {
|
||||
const original = createAnnotationRegion();
|
||||
const cloned = cloneAnnotationRegion(original);
|
||||
|
||||
expect(cloned).toEqual(original);
|
||||
expect(cloned).not.toBe(original);
|
||||
expect(cloned.position).not.toBe(original.position);
|
||||
expect(cloned.size).not.toBe(original.size);
|
||||
expect(cloned.style).not.toBe(original.style);
|
||||
expect(cloned.blurData).not.toBe(original.blurData);
|
||||
expect(cloned.blurData?.freehandPoints).not.toBe(original.blurData?.freehandPoints);
|
||||
expect(cloned.blurData?.freehandPoints?.[0]).not.toBe(original.blurData?.freehandPoints?.[0]);
|
||||
});
|
||||
|
||||
it("detects true overlaps but not adjacent spans", () => {
|
||||
expect(spansOverlap(100, 200, 150, 250)).toBe(true);
|
||||
expect(spansOverlap(100, 200, 200, 300)).toBe(false);
|
||||
expect(spansOverlap(100, 200, 0, 100)).toBe(false);
|
||||
});
|
||||
|
||||
it("preserves pasted annotation positions when they are already in bounds", () => {
|
||||
expect(getPastedAnnotationPosition({ x: 10, y: 15 }, { width: 30, height: 20 })).toEqual({
|
||||
x: 10,
|
||||
y: 15,
|
||||
});
|
||||
});
|
||||
|
||||
it("clamps pasted annotation positions when the source would overflow its bounds", () => {
|
||||
expect(getPastedAnnotationPosition({ x: 94, y: 93 }, { width: 12, height: 9 })).toEqual({
|
||||
x: 88,
|
||||
y: 91,
|
||||
});
|
||||
});
|
||||
|
||||
it("pins oversized pasted annotations to the visible origin", () => {
|
||||
expect(getPastedAnnotationPosition({ x: 50, y: 50 }, { width: 140, height: 120 })).toEqual({
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import type { AnnotationPosition, AnnotationRegion, AnnotationSize } from "./types";
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
export function cloneAnnotationRegion(region: AnnotationRegion): AnnotationRegion {
|
||||
return {
|
||||
...region,
|
||||
position: { ...region.position },
|
||||
size: { ...region.size },
|
||||
style: { ...region.style },
|
||||
figureData: region.figureData ? { ...region.figureData } : undefined,
|
||||
blurData: region.blurData
|
||||
? {
|
||||
...region.blurData,
|
||||
freehandPoints: region.blurData.freehandPoints?.map((point) => ({ ...point })),
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export function spansOverlap(startA: number, endA: number, startB: number, endB: number): boolean {
|
||||
return startA < endB && endA > startB;
|
||||
}
|
||||
|
||||
export function getPastedAnnotationPosition(
|
||||
position: AnnotationPosition,
|
||||
size: AnnotationSize,
|
||||
): AnnotationPosition {
|
||||
const maxX = Math.max(0, 100 - size.width);
|
||||
const maxY = Math.max(0, 100 - size.height);
|
||||
|
||||
return {
|
||||
x: clamp(position.x, 0, maxX),
|
||||
y: clamp(position.y, 0, maxY),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { useCallback } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useScopedT } from "@/contexts/I18nContext";
|
||||
|
||||
export type ClipboardAction = "copy" | "paste";
|
||||
|
||||
export function useClipboardFeedback() {
|
||||
const t = useScopedT("timeline");
|
||||
|
||||
const notifyClipboardAction = useCallback(
|
||||
(action: ClipboardAction) => {
|
||||
toast.success(action === "copy" ? t("feedback.copied") : t("feedback.pasted"));
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
const notifyCopied = useCallback(() => {
|
||||
notifyClipboardAction("copy");
|
||||
}, [notifyClipboardAction]);
|
||||
|
||||
const notifyPasted = useCallback(() => {
|
||||
notifyClipboardAction("paste");
|
||||
}, [notifyClipboardAction]);
|
||||
|
||||
return {
|
||||
notifyClipboardAction,
|
||||
notifyCopied,
|
||||
notifyPasted,
|
||||
};
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { type Locale, SUPPORTED_LOCALES } from "@/i18n/config";
|
||||
import arDialogs from "@/i18n/locales/ar/dialogs.json";
|
||||
import enDialogs from "@/i18n/locales/en/dialogs.json";
|
||||
import esDialogs from "@/i18n/locales/es/dialogs.json";
|
||||
import frDialogs from "@/i18n/locales/fr/dialogs.json";
|
||||
import jaJPDialogs from "@/i18n/locales/ja-JP/dialogs.json";
|
||||
import koKRDialogs from "@/i18n/locales/ko-KR/dialogs.json";
|
||||
import ruDialogs from "@/i18n/locales/ru/dialogs.json";
|
||||
import trDialogs from "@/i18n/locales/tr/dialogs.json";
|
||||
import viDialogs from "@/i18n/locales/vi/dialogs.json";
|
||||
import zhCNDialogs from "@/i18n/locales/zh-CN/dialogs.json";
|
||||
import zhTWDialogs from "@/i18n/locales/zh-TW/dialogs.json";
|
||||
|
||||
@@ -45,10 +41,6 @@ const dialogsByLocale = {
|
||||
fr: frDialogs,
|
||||
tr: trDialogs,
|
||||
"ko-KR": koKRDialogs,
|
||||
ru: ruDialogs,
|
||||
"ja-JP": jaJPDialogs,
|
||||
ar: arDialogs,
|
||||
vi: viDialogs,
|
||||
} satisfies Record<Locale, { tutorial: Record<string, unknown> }>;
|
||||
|
||||
describe("TutorialHelp translations", () => {
|
||||
|
||||
+1
-13
@@ -1,17 +1,5 @@
|
||||
export const DEFAULT_LOCALE = "en" as const;
|
||||
export const SUPPORTED_LOCALES = [
|
||||
"en",
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"es",
|
||||
"fr",
|
||||
"tr",
|
||||
"ko-KR",
|
||||
"ja-JP",
|
||||
"ar",
|
||||
"ru",
|
||||
"vi",
|
||||
] as const;
|
||||
export const SUPPORTED_LOCALES = ["en", "zh-CN", "zh-TW", "es", "fr", "tr", "ko-KR"] as const;
|
||||
export const I18N_NAMESPACES = [
|
||||
"common",
|
||||
"dialogs",
|
||||
|
||||
@@ -51,5 +51,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "تمت إضافة {{count}} اقتراح تكبير بناءً على المؤشر",
|
||||
"addedZoomSuggestionsPlural": "تمت إضافة {{count}} اقتراحات تكبير بناءً على المؤشر"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "تم النسخ!",
|
||||
"pasted": "تم اللصق!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,33 +9,12 @@
|
||||
"open": "Open",
|
||||
"upload": "Upload",
|
||||
"export": "Export",
|
||||
"showInFolder": "Show in Folder",
|
||||
"file": "File",
|
||||
"edit": "Edit",
|
||||
"view": "View",
|
||||
"window": "Window",
|
||||
"quit": "Quit",
|
||||
"stopRecording": "Stop Recording",
|
||||
"undo": "Undo",
|
||||
"redo": "Redo",
|
||||
"cut": "Cut",
|
||||
"copy": "Copy",
|
||||
"paste": "Paste",
|
||||
"selectAll": "Select All",
|
||||
"minimize": "Minimize",
|
||||
"reload": "Reload",
|
||||
"forceReload": "Force Reload",
|
||||
"toggleDevTools": "Toggle Developer Tools",
|
||||
"actualSize": "Actual Size",
|
||||
"zoomIn": "Zoom In",
|
||||
"zoomOut": "Zoom Out",
|
||||
"toggleFullScreen": "Toggle Full Screen",
|
||||
"recordingStatus": "Recording: {{source}}",
|
||||
"about": "About OpenScreen",
|
||||
"services": "Services",
|
||||
"hide": "Hide OpenScreen",
|
||||
"hideOthers": "Hide Others",
|
||||
"unhide": "Show All"
|
||||
"stopRecording": "Stop Recording"
|
||||
},
|
||||
"playback": {
|
||||
"play": "Play",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm"
|
||||
},
|
||||
"loadingVideo": "Loading video...",
|
||||
"errors": {
|
||||
"noVideoLoaded": "No video loaded",
|
||||
"videoNotReady": "Video not ready",
|
||||
@@ -15,7 +14,6 @@
|
||||
"failedToSaveVideo": "Failed to save video",
|
||||
"exportFailed": "Export failed",
|
||||
"exportFailedWithError": "Export failed: {{error}}",
|
||||
"exportBackgroundLoadFailed": "Export failed: could not load background image ({{url}})",
|
||||
"failedToSaveExport": "Failed to save export",
|
||||
"failedToSaveExportedVideo": "Failed to save exported video",
|
||||
"failedToRevealInFolder": "Error revealing in folder: {{error}}"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"zoom": {
|
||||
"level": "Zoom Level",
|
||||
"customScale": "Custom Zoom",
|
||||
"selectRegion": "Select a zoom region to adjust",
|
||||
"deleteZoom": "Delete Zoom",
|
||||
"focusMode": {
|
||||
@@ -10,19 +9,12 @@
|
||||
"auto": "Auto",
|
||||
"autoDescription": "Camera follows the recorded cursor position"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "3D Rotation",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "Left",
|
||||
"right": "Right"
|
||||
}
|
||||
},
|
||||
"position": {
|
||||
"title": "Focus Position",
|
||||
"x": "X (%)",
|
||||
"y": "Y (%)",
|
||||
"hint": "0 = leftmost / topmost, 100 = rightmost / bottommost"
|
||||
"speed": {
|
||||
"title": "Zoom Speed",
|
||||
"instant": "Instant",
|
||||
"fast": "Fast",
|
||||
"smooth": "Smooth",
|
||||
"lazy": "Lazy"
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
@@ -42,7 +34,6 @@
|
||||
"pictureInPicture": "Picture in Picture",
|
||||
"verticalStack": "Vertical Stack",
|
||||
"dualFrame": "Dual Frame",
|
||||
"noWebcam": "No Webcam",
|
||||
"webcamShape": "Camera Shape",
|
||||
"webcamSize": "Webcam Size"
|
||||
},
|
||||
@@ -51,23 +42,9 @@
|
||||
"blurBg": "Blur BG",
|
||||
"motionBlur": "Motion Blur",
|
||||
"off": "off",
|
||||
"on": "on",
|
||||
"shadow": "Shadow",
|
||||
"roundness": "Roundness",
|
||||
"padding": "Padding",
|
||||
"cursorHighlight": {
|
||||
"title": "Cursor highlight",
|
||||
"style": "Style",
|
||||
"dot": "Dot",
|
||||
"ring": "Ring",
|
||||
"size": "Size",
|
||||
"onlyOnClicks": "Only on clicks",
|
||||
"color": "Color",
|
||||
"offsetX": "Offset X (window recordings)",
|
||||
"offsetY": "Offset Y",
|
||||
"accessibilityPermissionTitle": "Accessibility permission needed",
|
||||
"accessibilityPermissionDescription": "Open System Settings → Privacy & Security → Accessibility, enable Openscreen, then restart the app."
|
||||
}
|
||||
"padding": "Padding"
|
||||
},
|
||||
"background": {
|
||||
"title": "Background",
|
||||
@@ -75,9 +52,7 @@
|
||||
"color": "Color",
|
||||
"gradient": "Gradient",
|
||||
"uploadCustom": "Upload Custom",
|
||||
"gradientLabel": "Gradient {{index}}",
|
||||
"colorWheel": "Color Wheel",
|
||||
"colorPalette": "Color Palette"
|
||||
"gradientLabel": "Gradient {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "Crop",
|
||||
@@ -145,8 +120,6 @@
|
||||
"background": "Background",
|
||||
"none": "None",
|
||||
"color": "Color",
|
||||
"colorWheel": "Color Wheel",
|
||||
"colorPalette": "Color Palette",
|
||||
"clearBackground": "Clear Background",
|
||||
"uploadImage": "Upload Image",
|
||||
"supportedFormats": "Supported formats: JPG, PNG, GIF, WebP",
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
"labels": {
|
||||
"pan": "Pan",
|
||||
"zoom": "Zoom",
|
||||
"trim": "Trim",
|
||||
"speed": "Speed",
|
||||
"zoomItem": "Zoom {{index}}",
|
||||
"trimItem": "Trim {{index}}",
|
||||
"speedItem": "Speed {{index}}",
|
||||
@@ -51,5 +49,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "Added {{count}} cursor-based zoom suggestion",
|
||||
"addedZoomSuggestionsPlural": "Added {{count}} cursor-based zoom suggestions"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "Copied!",
|
||||
"pasted": "Pasted!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"open": "Abrir",
|
||||
"upload": "Subir",
|
||||
"export": "Exportar",
|
||||
"showInFolder": "Mostrar en carpeta",
|
||||
"file": "Archivo",
|
||||
"edit": "Editar",
|
||||
"view": "Vista",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"failedToSaveVideo": "Error al guardar el video",
|
||||
"exportFailed": "La exportación falló",
|
||||
"exportFailedWithError": "La exportación falló: {{error}}",
|
||||
"exportBackgroundLoadFailed": "La exportación falló: no se pudo cargar la imagen de fondo ({{url}})",
|
||||
"failedToSaveExport": "Error al guardar la exportación",
|
||||
"failedToSaveExportedVideo": "Error al guardar el video exportado",
|
||||
"failedToRevealInFolder": "Error al mostrar en la carpeta: {{error}}"
|
||||
@@ -34,12 +33,5 @@
|
||||
"cameraDisconnected": "Cámara web desconectada.",
|
||||
"cameraNotFound": "Cámara no encontrada.",
|
||||
"permissionDenied": "Permiso de grabación denegado. Por favor permite la grabación de pantalla."
|
||||
},
|
||||
"loadingVideo": "Cargando video...",
|
||||
"newRecording": {
|
||||
"title": "Volver a la grabadora",
|
||||
"description": "Tu sesión actual ha sido guardada.",
|
||||
"cancel": "Cancelar",
|
||||
"confirm": "Confirmar"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
"auto": "Auto",
|
||||
"autoDescription": "La cámara sigue la posición del cursor grabado"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "Rotación 3D",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "Izquierda",
|
||||
"right": "Derecha"
|
||||
}
|
||||
"speed": {
|
||||
"title": "Velocidad de zoom",
|
||||
"instant": "Instantáneo",
|
||||
"fast": "Rápido",
|
||||
"smooth": "Suave",
|
||||
"lazy": "Lento"
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
@@ -53,9 +52,7 @@
|
||||
"color": "Color",
|
||||
"gradient": "Degradado",
|
||||
"uploadCustom": "Subir personalizado",
|
||||
"gradientLabel": "Degradado {{index}}",
|
||||
"colorWheel": "Rueda de colores",
|
||||
"colorPalette": "Paleta de colores"
|
||||
"gradientLabel": "Degradado {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "Recortar",
|
||||
@@ -123,8 +120,6 @@
|
||||
"background": "Fondo",
|
||||
"none": "Ninguno",
|
||||
"color": "Color",
|
||||
"colorWheel": "Rueda de colores",
|
||||
"colorPalette": "Paleta de colores",
|
||||
"clearBackground": "Quitar fondo",
|
||||
"uploadImage": "Subir imagen",
|
||||
"supportedFormats": "Formatos compatibles: JPG, PNG, GIF, WebP",
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
"labels": {
|
||||
"pan": "Desplazar",
|
||||
"zoom": "Zoom",
|
||||
"trim": "Recortar",
|
||||
"speed": "Velocidad",
|
||||
"zoomItem": "Zoom {{index}}",
|
||||
"trimItem": "Recorte {{index}}",
|
||||
"speedItem": "Velocidad {{index}}",
|
||||
@@ -51,5 +49,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "Se agregó {{count}} sugerencia de zoom basada en el cursor",
|
||||
"addedZoomSuggestionsPlural": "Se agregaron {{count}} sugerencias de zoom basadas en el cursor"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "¡Copiado!",
|
||||
"pasted": "¡Pegado!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"open": "Ouvrir",
|
||||
"upload": "Téléverser",
|
||||
"export": "Exporter",
|
||||
"showInFolder": "Afficher dans le dossier",
|
||||
"file": "Fichier",
|
||||
"edit": "Éditer",
|
||||
"view": "Affichage",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"description": "Comprendre comment supprimer les parties indésirables de votre vidéo.",
|
||||
"explanationBefore": "L'outil Coupe fonctionne en définissant les segments que vous souhaitez",
|
||||
"remove": "supprimer",
|
||||
"explanationMiddle": " — tout ce qui est",
|
||||
"explanationMiddle": " — tout élément",
|
||||
"covered": "couvert",
|
||||
"explanationAfter": "par un segment de coupe rouge sera coupé lors de l'export.",
|
||||
"visualExample": "Exemple visuel",
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
{
|
||||
"newRecording": {
|
||||
"title": "Retour à l'enregistreur",
|
||||
"description": "Votre session actuelle a été enregistrée.",
|
||||
"cancel": "Annuler",
|
||||
"confirm": "Confirmer"
|
||||
},
|
||||
"errors": {
|
||||
"noVideoLoaded": "Aucune vidéo chargée",
|
||||
"videoNotReady": "Vidéo non prête",
|
||||
@@ -14,7 +8,6 @@
|
||||
"failedToSaveVideo": "Échec de l'enregistrement de la vidéo",
|
||||
"exportFailed": "L'export a échoué",
|
||||
"exportFailedWithError": "L'export a échoué : {{error}}",
|
||||
"exportBackgroundLoadFailed": "L'export a échoué : impossible de charger l'image d'arrière-plan ({{url}})",
|
||||
"failedToSaveExport": "Échec de l'enregistrement de l'export",
|
||||
"failedToSaveExportedVideo": "Échec de l'enregistrement de la vidéo exportée",
|
||||
"failedToRevealInFolder": "Erreur lors de l'affichage dans le dossier : {{error}}"
|
||||
@@ -37,9 +30,6 @@
|
||||
"systemAudioUnavailable": "Audio système non disponible. Enregistrement sans audio système.",
|
||||
"microphoneDenied": "Accès au microphone refusé. L'enregistrement continuera sans audio.",
|
||||
"cameraDenied": "Accès à la caméra refusé. L'enregistrement continuera sans webcam.",
|
||||
"cameraDisconnected": "Webcam déconnectée.",
|
||||
"cameraNotFound": "Caméra introuvable.",
|
||||
"permissionDenied": "Permission d'enregistrement refusée. Veuillez autoriser l'enregistrement d'écran."
|
||||
},
|
||||
"loadingVideo": "Chargement de la vidéo..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,5 @@
|
||||
"recording": {
|
||||
"selectSource": "Veuillez sélectionner une source à enregistrer"
|
||||
},
|
||||
"language": "Langue",
|
||||
"systemLanguagePrompt": {
|
||||
"title": "Utiliser la langue de votre système ?",
|
||||
"description": "Nous avons détecté {{language}} comme langue système. Voulez-vous passer OpenScreen en {{language}} ?",
|
||||
"switch": "Passer en {{language}}",
|
||||
"keepDefault": "Conserver la langue actuelle"
|
||||
}
|
||||
"language": "Langue"
|
||||
}
|
||||
|
||||
@@ -8,29 +8,12 @@
|
||||
"manual": "Manuel",
|
||||
"auto": "Auto",
|
||||
"autoDescription": "La caméra suit la position du curseur enregistré"
|
||||
},
|
||||
"speed": {
|
||||
"title": "Vitesse du zoom",
|
||||
"instant": "Instantané",
|
||||
"fast": "Rapide",
|
||||
"smooth": "Fluide",
|
||||
"lazy": "Lent"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "Rotation 3D",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "Gauche",
|
||||
"right": "Droite"
|
||||
}
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
"playbackSpeed": "Vitesse de lecture",
|
||||
"selectRegion": "Sélectionnez une région de vitesse à ajuster",
|
||||
"deleteRegion": "Supprimer la région de vitesse",
|
||||
"customPlaybackSpeed": "Vitesse de lecture personnalisée",
|
||||
"maxSpeedError": "La vitesse ne peut pas dépasser 16×"
|
||||
"deleteRegion": "Supprimer la région de vitesse"
|
||||
},
|
||||
"trim": {
|
||||
"deleteRegion": "Supprimer la région de coupe"
|
||||
@@ -41,9 +24,7 @@
|
||||
"selectPreset": "Choisir un préréglage",
|
||||
"pictureInPicture": "Incrustation d'image",
|
||||
"verticalStack": "Empilement vertical",
|
||||
"dualFrame": "Double cadre",
|
||||
"webcamShape": "Forme de la caméra",
|
||||
"webcamSize": "Taille de la caméra"
|
||||
"webcamShape": "Forme de la caméra"
|
||||
},
|
||||
"effects": {
|
||||
"title": "Effets vidéo",
|
||||
@@ -60,9 +41,7 @@
|
||||
"color": "Couleur",
|
||||
"gradient": "Dégradé",
|
||||
"uploadCustom": "Téléverser une image",
|
||||
"gradientLabel": "Dégradé {{index}}",
|
||||
"colorWheel": "Roue chromatique",
|
||||
"colorPalette": "Palette de couleurs"
|
||||
"gradientLabel": "Dégradé {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "Recadrage",
|
||||
@@ -130,8 +109,6 @@
|
||||
"background": "Arrière-plan",
|
||||
"none": "Aucun",
|
||||
"color": "Couleur",
|
||||
"colorWheel": "Roue chromatique",
|
||||
"colorPalette": "Palette de couleurs",
|
||||
"clearBackground": "Supprimer l'arrière-plan",
|
||||
"uploadImage": "Téléverser une image",
|
||||
"supportedFormats": "Formats supportés : JPG, PNG, GIF, WebP",
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
"labels": {
|
||||
"pan": "Panoramique",
|
||||
"zoom": "Zoom",
|
||||
"trim": "Couper",
|
||||
"speed": "Vitesse",
|
||||
"zoomItem": "Zoom {{index}}",
|
||||
"trimItem": "Coupe {{index}}",
|
||||
"speedItem": "Vitesse {{index}}",
|
||||
@@ -33,23 +31,27 @@
|
||||
},
|
||||
"errors": {
|
||||
"cannotPlaceZoom": "Impossible de placer le zoom ici",
|
||||
"zoomExistsAtLocation": "Un zoom existe déjà à cet emplacement ou l\u0027espace disponible est insuffisant.",
|
||||
"zoomExistsAtLocation": "Un zoom existe déjà à cet emplacement ou l'espace disponible est insuffisant.",
|
||||
"zoomSuggestionUnavailable": "Gestionnaire de suggestions de zoom non disponible",
|
||||
"noCursorTelemetry": "Aucune télémétrie de curseur disponible",
|
||||
"noCursorTelemetryDescription": "Enregistrez d\u0027abord un screencast pour générer des suggestions basées sur le curseur.",
|
||||
"noCursorTelemetryDescription": "Enregistrez d'abord un screencast pour générer des suggestions basées sur le curseur.",
|
||||
"noUsableTelemetry": "Aucune télémétrie de curseur utilisable",
|
||||
"noUsableTelemetryDescription": "L\u0027enregistrement ne contient pas suffisamment de données de mouvement du curseur.",
|
||||
"noUsableTelemetryDescription": "L'enregistrement ne contient pas suffisamment de données de mouvement du curseur.",
|
||||
"noDwellMoments": "Aucun moment de pause du curseur trouvé",
|
||||
"noDwellMomentsDescription": "Essayez un enregistrement avec des pauses plus lentes du curseur sur les actions importantes.",
|
||||
"noAutoZoomSlots": "Aucun emplacement de zoom automatique disponible",
|
||||
"noAutoZoomSlotsDescription": "Les points de pause détectés chevauchent des régions de zoom existantes.",
|
||||
"cannotPlaceTrim": "Impossible de placer la coupe ici",
|
||||
"trimExistsAtLocation": "Une coupe existe déjà à cet emplacement ou l\u0027espace disponible est insuffisant.",
|
||||
"trimExistsAtLocation": "Une coupe existe déjà à cet emplacement ou l'espace disponible est insuffisant.",
|
||||
"cannotPlaceSpeed": "Impossible de placer la vitesse ici",
|
||||
"speedExistsAtLocation": "Une région de vitesse existe déjà à cet emplacement ou l\u0027espace disponible est insuffisant."
|
||||
"speedExistsAtLocation": "Une région de vitesse existe déjà à cet emplacement ou l'espace disponible est insuffisant."
|
||||
},
|
||||
"success": {
|
||||
"addedZoomSuggestions": "{{count}} suggestion de zoom basée sur le curseur ajoutée",
|
||||
"addedZoomSuggestionsPlural": "{{count}} suggestions de zoom basées sur le curseur ajoutées"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "Copié !",
|
||||
"pasted": "Collé !"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,5 +51,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "カーソルに基づくズーム提案を {{count}} 件追加しました",
|
||||
"addedZoomSuggestionsPlural": "カーソルに基づくズーム提案を {{count}} 件追加しました"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "コピーしました!",
|
||||
"pasted": "貼り付けました!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"open": "열기",
|
||||
"upload": "업로드",
|
||||
"export": "내보내기",
|
||||
"showInFolder": "폴더에 표시",
|
||||
"file": "파일",
|
||||
"edit": "편집",
|
||||
"view": "보기",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"cancel": "취소",
|
||||
"confirm": "확인"
|
||||
},
|
||||
"loadingVideo": "비디오 로드 중...",
|
||||
"errors": {
|
||||
"noVideoLoaded": "불러온 비디오가 없습니다",
|
||||
"videoNotReady": "비디오가 준비되지 않았습니다",
|
||||
@@ -15,7 +14,6 @@
|
||||
"failedToSaveVideo": "비디오 저장에 실패했습니다",
|
||||
"exportFailed": "내보내기에 실패했습니다",
|
||||
"exportFailedWithError": "내보내기 실패: {{error}}",
|
||||
"exportBackgroundLoadFailed": "내보내기 실패: 배경 이미지를 불러올 수 없습니다 ({{url}})",
|
||||
"failedToSaveExport": "내보낸 파일 저장에 실패했습니다",
|
||||
"failedToSaveExportedVideo": "내보낸 비디오 저장에 실패했습니다",
|
||||
"failedToRevealInFolder": "폴더에서 파일 표시 오류: {{error}}"
|
||||
@@ -38,8 +36,6 @@
|
||||
"systemAudioUnavailable": "시스템 오디오를 사용할 수 없습니다. 시스템 오디오 없이 녹화합니다.",
|
||||
"microphoneDenied": "마이크 접근이 거부되었습니다. 오디오 없이 녹화를 계속합니다.",
|
||||
"cameraDenied": "카메라 접근이 거부되었습니다. 웹캠 없이 녹화를 계속합니다.",
|
||||
"permissionDenied": "녹화 권한이 거부되었습니다. 화면 녹화를 허용해 주세요.",
|
||||
"cameraDisconnected": "웹캠 연결이 끊어졌습니다.",
|
||||
"cameraNotFound": "카메라를 찾을 수 없습니다."
|
||||
"permissionDenied": "녹화 권한이 거부되었습니다. 화면 녹화를 허용해 주세요."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,5 @@
|
||||
"recording": {
|
||||
"selectSource": "녹화할 소스를 선택해 주세요"
|
||||
},
|
||||
"language": "언어",
|
||||
"systemLanguagePrompt": {
|
||||
"title": "시스템 언어를 사용하시겠습니까?",
|
||||
"description": "시스템 언어가 {{language}}(으)로 감지되었습니다. OpenScreen을 {{language}}(으)로 전환하시겠습니까?",
|
||||
"switch": "{{language}}(으)로 전환",
|
||||
"keepDefault": "현재 언어 유지"
|
||||
}
|
||||
"language": "언어"
|
||||
}
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
"manual": "수동",
|
||||
"auto": "자동",
|
||||
"autoDescription": "녹화된 커서 위치를 따라 카메라가 이동합니다"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "3D 회전",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "왼쪽",
|
||||
"right": "오른쪽"
|
||||
}
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
@@ -35,8 +27,7 @@
|
||||
"pictureInPicture": "화면 속 화면",
|
||||
"verticalStack": "세로 배치",
|
||||
"webcamShape": "카메라 모양",
|
||||
"webcamSize": "웹캠 크기",
|
||||
"dualFrame": "듀얼 프레임"
|
||||
"webcamSize": "웹캠 크기"
|
||||
},
|
||||
"effects": {
|
||||
"title": "비디오 효과",
|
||||
@@ -53,9 +44,7 @@
|
||||
"color": "색상",
|
||||
"gradient": "그라디언트",
|
||||
"uploadCustom": "직접 업로드",
|
||||
"gradientLabel": "그라디언트 {{index}}",
|
||||
"colorWheel": "색상 휠",
|
||||
"colorPalette": "색상 팔레트"
|
||||
"gradientLabel": "그라디언트 {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "자르기",
|
||||
@@ -122,8 +111,6 @@
|
||||
"background": "배경",
|
||||
"none": "없음",
|
||||
"color": "색상",
|
||||
"colorWheel": "색상 휠",
|
||||
"colorPalette": "색상 팔레트",
|
||||
"clearBackground": "배경 지우기",
|
||||
"uploadImage": "이미지 업로드",
|
||||
"supportedFormats": "지원 형식: JPG, PNG, GIF, WebP",
|
||||
@@ -138,20 +125,7 @@
|
||||
"invalidImageType": "지원하지 않는 파일 형식입니다",
|
||||
"imageFormatsOnly": "JPG, PNG, GIF 또는 WebP 이미지 파일을 업로드해 주세요.",
|
||||
"imageUploadSuccess": "이미지가 성공적으로 업로드되었습니다!",
|
||||
"failedImageUpload": "이미지 업로드에 실패했습니다",
|
||||
"blurColor": "블러 색상",
|
||||
"blurColorBlack": "검정",
|
||||
"blurColorWhite": "흰색",
|
||||
"blurIntensity": "블러 강도",
|
||||
"blurShape": "블러 모양",
|
||||
"blurShapeFreehand": "자유 곡선",
|
||||
"blurShapeOval": "타원",
|
||||
"blurShapeRectangle": "사각형",
|
||||
"blurType": "블러 종류",
|
||||
"blurTypeBlur": "블러",
|
||||
"blurTypeMosaic": "모자이크 블러",
|
||||
"mosaicBlockSize": "모자이크 블록 크기",
|
||||
"typeBlur": "블러"
|
||||
"failedImageUpload": "이미지 업로드에 실패했습니다"
|
||||
},
|
||||
"fontStyles": {
|
||||
"classic": "클래식",
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
"addAnnotation": "주석 추가",
|
||||
"addKeyframe": "키프레임 추가",
|
||||
"deleteSelected": "선택 항목 삭제",
|
||||
"playPause": "재생 / 일시정지",
|
||||
"addBlur": "블러 추가"
|
||||
"playPause": "재생 / 일시정지"
|
||||
},
|
||||
"fixedActions": {
|
||||
"undo": "실행 취소",
|
||||
|
||||
@@ -4,28 +4,23 @@
|
||||
"suggestZooms": "커서 기반 줌 제안",
|
||||
"addTrim": "트림 추가 (T)",
|
||||
"addAnnotation": "주석 추가 (A)",
|
||||
"addSpeed": "속도 추가 (S)",
|
||||
"addBlur": "블러 추가 (B)"
|
||||
"addSpeed": "속도 추가 (S)"
|
||||
},
|
||||
"hints": {
|
||||
"pressZoom": "Z를 눌러 줌 추가",
|
||||
"pressTrim": "T를 눌러 트림 추가",
|
||||
"pressAnnotation": "A를 눌러 주석 추가",
|
||||
"pressSpeed": "S를 눌러 속도 추가",
|
||||
"pressBlur": "B 키를 눌러 블러 영역을 추가하세요"
|
||||
"pressSpeed": "S를 눌러 속도 추가"
|
||||
},
|
||||
"labels": {
|
||||
"pan": "이동",
|
||||
"zoom": "줌",
|
||||
"trim": "트림",
|
||||
"speed": "속도",
|
||||
"zoomItem": "줌 {{index}}",
|
||||
"trimItem": "트림 {{index}}",
|
||||
"speedItem": "속도 {{index}}",
|
||||
"annotationItem": "주석",
|
||||
"imageItem": "이미지",
|
||||
"emptyText": "빈 텍스트",
|
||||
"blurItem": "블러 {{index}}"
|
||||
"emptyText": "빈 텍스트"
|
||||
},
|
||||
"emptyState": {
|
||||
"noVideo": "불러온 비디오 없음",
|
||||
@@ -51,5 +46,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "커서 기반 줌 제안 {{count}}개가 추가되었습니다",
|
||||
"addedZoomSuggestionsPlural": "커서 기반 줌 제안 {{count}}개가 추가되었습니다"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "복사됨!",
|
||||
"pasted": "붙여넣음!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,5 +51,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "Добавлено {{count}} предложение масштабирования на основе курсора",
|
||||
"addedZoomSuggestionsPlural": "Добавлено {{count}} предложений масштабирования на основе курсора"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "Скопировано!",
|
||||
"pasted": "Вставлено!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"open": "Aç",
|
||||
"upload": "Yükle",
|
||||
"export": "Dışa Aktar",
|
||||
"showInFolder": "Klasörde Göster",
|
||||
"file": "Dosya",
|
||||
"edit": "Düzenle",
|
||||
"view": "Görünüm",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"failedToSaveVideo": "Video kaydedilemedi",
|
||||
"exportFailed": "Dışa aktarım başarısız oldu",
|
||||
"exportFailedWithError": "Dışa aktarım başarısız: {{error}}",
|
||||
"exportBackgroundLoadFailed": "Dışa aktarım başarısız: arka plan görüntüsü yüklenemedi ({{url}})",
|
||||
"failedToSaveExport": "Dışa aktarım kaydedilemedi",
|
||||
"failedToSaveExportedVideo": "Dışa aktarılan video kaydedilemedi",
|
||||
"failedToRevealInFolder": "Klasörde gösterme hatası: {{error}}"
|
||||
@@ -31,15 +30,6 @@
|
||||
"systemAudioUnavailable": "Sistem sesi kullanılamıyor. Sistem sesi olmadan kaydediliyor.",
|
||||
"microphoneDenied": "Mikrofon erişimi reddedildi. Kayıt ses olmadan devam edecek.",
|
||||
"cameraDenied": "Kamera erişimi reddedildi. Kayıt kamera olmadan devam edecek.",
|
||||
"permissionDenied": "Kayıt izni reddedildi. Lütfen ekran kaydına izin verin.",
|
||||
"cameraDisconnected": "Webcam bağlantısı kesildi.",
|
||||
"cameraNotFound": "Kamera bulunamadı."
|
||||
},
|
||||
"loadingVideo": "Video yükleniyor...",
|
||||
"newRecording": {
|
||||
"title": "Kaydediciye Dön",
|
||||
"description": "Mevcut oturumunuz kaydedildi.",
|
||||
"cancel": "İptal",
|
||||
"confirm": "Onayla"
|
||||
"permissionDenied": "Kayıt izni reddedildi. Lütfen ekran kaydına izin verin."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +44,5 @@
|
||||
"recording": {
|
||||
"selectSource": "Lütfen kayıt için bir kaynak seçin"
|
||||
},
|
||||
"language": "Dil",
|
||||
"systemLanguagePrompt": {
|
||||
"title": "Sistem dilinizi kullanmak ister misiniz?",
|
||||
"description": "Sistem diliniz {{language}} olarak algılandı. OpenScreen i {{language}} diline geçirmek ister misiniz?",
|
||||
"switch": "{{language}} diline geç",
|
||||
"keepDefault": "Mevcut dili koru"
|
||||
}
|
||||
"language": "Dil"
|
||||
}
|
||||
|
||||
@@ -8,22 +8,12 @@
|
||||
"manual": "Manuel",
|
||||
"auto": "Otomatik",
|
||||
"autoDescription": "Kamera kaydedilen imleç konumunu takip eder"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "3D Döndürme",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "Sol",
|
||||
"right": "Sağ"
|
||||
}
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
"playbackSpeed": "Oynatma Hızı",
|
||||
"selectRegion": "Ayarlamak için bir hız bölgesi seçin",
|
||||
"deleteRegion": "Hız Bölgesini Sil",
|
||||
"customPlaybackSpeed": "Özel Oynatma Hızı",
|
||||
"maxSpeedError": "Hız 16× değerinden yüksek olamaz"
|
||||
"deleteRegion": "Hız Bölgesini Sil"
|
||||
},
|
||||
"trim": {
|
||||
"deleteRegion": "Kırpma Bölgesini Sil"
|
||||
@@ -34,9 +24,7 @@
|
||||
"selectPreset": "Ön ayar seçin",
|
||||
"pictureInPicture": "Resim İçinde Resim",
|
||||
"verticalStack": "Dikey Yığın",
|
||||
"webcamShape": "Kamera Şekli",
|
||||
"dualFrame": "Çift Kare",
|
||||
"webcamSize": "Webcam Boyutu"
|
||||
"webcamShape": "Kamera Şekli"
|
||||
},
|
||||
"effects": {
|
||||
"title": "Video Efektleri",
|
||||
@@ -53,9 +41,7 @@
|
||||
"color": "Renk",
|
||||
"gradient": "Gradyan",
|
||||
"uploadCustom": "Özel Yükle",
|
||||
"gradientLabel": "Gradyan {{index}}",
|
||||
"colorWheel": "Renk çarkı",
|
||||
"colorPalette": "Renk paleti"
|
||||
"gradientLabel": "Gradyan {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "Kırpma",
|
||||
@@ -123,8 +109,6 @@
|
||||
"background": "Arka Plan",
|
||||
"none": "Yok",
|
||||
"color": "Renk",
|
||||
"colorWheel": "Renk çarkı",
|
||||
"colorPalette": "Renk paleti",
|
||||
"clearBackground": "Arka Planı Temizle",
|
||||
"uploadImage": "Görüntü Yükle",
|
||||
"supportedFormats": "Desteklenen biçimler: JPG, PNG, GIF, WebP",
|
||||
@@ -144,14 +128,7 @@
|
||||
"invalidImageType": "Geçersiz dosya türü",
|
||||
"imageFormatsOnly": "Lütfen bir JPG, PNG, GIF veya WebP görüntü dosyası yükleyin.",
|
||||
"imageUploadSuccess": "Görüntü başarıyla yüklendi!",
|
||||
"failedImageUpload": "Görüntü yüklenemedi",
|
||||
"blurColor": "Bulanıklık Rengi",
|
||||
"blurColorBlack": "Siyah",
|
||||
"blurColorWhite": "Beyaz",
|
||||
"blurType": "Bulanıklık Türü",
|
||||
"blurTypeBlur": "Bulanık",
|
||||
"blurTypeMosaic": "Mozaik Bulanıklık",
|
||||
"mosaicBlockSize": "Mozaik Blok Boyutu"
|
||||
"failedImageUpload": "Görüntü yüklenemedi"
|
||||
},
|
||||
"fontStyles": {
|
||||
"classic": "Klasik",
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
"labels": {
|
||||
"pan": "Kaydır",
|
||||
"zoom": "Yakınlaştır",
|
||||
"trim": "Kırp",
|
||||
"speed": "Hız",
|
||||
"zoomItem": "Yakınlaştırma {{index}}",
|
||||
"trimItem": "Kırpma {{index}}",
|
||||
"speedItem": "Hız {{index}}",
|
||||
@@ -51,5 +49,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "{{count}} imleç tabanlı yakınlaştırma önerisi eklendi",
|
||||
"addedZoomSuggestionsPlural": "{{count}} imleç tabanlı yakınlaştırma önerisi eklendi"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "Kopyalandı!",
|
||||
"pasted": "Yapıştırıldı!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,5 +51,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "Đã thêm {{count}} đề xuất thu phóng dựa trên con trỏ",
|
||||
"addedZoomSuggestionsPlural": "Đã thêm {{count}} đề xuất thu phóng dựa trên con trỏ"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "Đã sao chép!",
|
||||
"pasted": "Đã dán!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"open": "打开",
|
||||
"upload": "上传",
|
||||
"export": "导出",
|
||||
"showInFolder": "在文件夹中显示",
|
||||
"file": "文件",
|
||||
"edit": "编辑",
|
||||
"view": "视图",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"cancel": "取消",
|
||||
"confirm": "确认"
|
||||
},
|
||||
"loadingVideo": "正在加载视频...",
|
||||
"errors": {
|
||||
"noVideoLoaded": "未加载视频",
|
||||
"videoNotReady": "视频未就绪",
|
||||
@@ -15,7 +14,6 @@
|
||||
"failedToSaveVideo": "保存视频失败",
|
||||
"exportFailed": "导出失败",
|
||||
"exportFailedWithError": "导出失败:{{error}}",
|
||||
"exportBackgroundLoadFailed": "导出失败:无法加载背景图片({{url}})",
|
||||
"failedToSaveExport": "保存导出文件失败",
|
||||
"failedToSaveExportedVideo": "保存导出的视频失败",
|
||||
"failedToRevealInFolder": "在文件夹中显示时出错:{{error}}"
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
"auto": "自动",
|
||||
"autoDescription": "摄像头跟随录制时的光标位置"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "3D 旋转",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "左",
|
||||
"right": "右"
|
||||
}
|
||||
"speed": {
|
||||
"title": "缩放速度",
|
||||
"instant": "即时",
|
||||
"fast": "快速",
|
||||
"smooth": "平滑",
|
||||
"lazy": "缓慢"
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
@@ -53,9 +52,7 @@
|
||||
"color": "颜色",
|
||||
"gradient": "渐变",
|
||||
"uploadCustom": "上传自定义",
|
||||
"gradientLabel": "渐变 {{index}}",
|
||||
"colorWheel": "颜色轮",
|
||||
"colorPalette": "颜色调色板"
|
||||
"gradientLabel": "渐变 {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "裁剪",
|
||||
@@ -123,8 +120,6 @@
|
||||
"background": "背景",
|
||||
"none": "无",
|
||||
"color": "颜色",
|
||||
"colorWheel": "颜色轮",
|
||||
"colorPalette": "颜色调色板",
|
||||
"clearBackground": "清除背景",
|
||||
"uploadImage": "上传图片",
|
||||
"supportedFormats": "支持的格式:JPG、PNG、GIF、WebP",
|
||||
@@ -144,14 +139,7 @@
|
||||
"invalidImageType": "无效的文件类型",
|
||||
"imageFormatsOnly": "请上传 JPG、PNG、GIF 或 WebP 格式的图片文件。",
|
||||
"imageUploadSuccess": "图片上传成功!",
|
||||
"failedImageUpload": "上传图片失败",
|
||||
"blurColor": "模糊颜色",
|
||||
"blurColorBlack": "黑色",
|
||||
"blurColorWhite": "白色",
|
||||
"blurType": "模糊类型",
|
||||
"blurTypeBlur": "模糊",
|
||||
"blurTypeMosaic": "马赛克模糊",
|
||||
"mosaicBlockSize": "马赛克块大小"
|
||||
"failedImageUpload": "上传图片失败"
|
||||
},
|
||||
"fontStyles": {
|
||||
"classic": "经典",
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
"labels": {
|
||||
"pan": "平移",
|
||||
"zoom": "缩放",
|
||||
"trim": "剪辑",
|
||||
"speed": "速度",
|
||||
"zoomItem": "缩放 {{index}}",
|
||||
"trimItem": "剪辑 {{index}}",
|
||||
"speedItem": "速度 {{index}}",
|
||||
@@ -51,5 +49,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "已添加 {{count}} 个基于光标的缩放建议",
|
||||
"addedZoomSuggestionsPlural": "已添加 {{count}} 个基于光标的缩放建议"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "已复制!",
|
||||
"pasted": "已粘贴!"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"open": "開啟",
|
||||
"upload": "上傳",
|
||||
"export": "匯出",
|
||||
"showInFolder": "在資料夾中顯示",
|
||||
"file": "檔案",
|
||||
"edit": "編輯",
|
||||
"view": "檢視",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"cancel": "取消",
|
||||
"confirm": "確認"
|
||||
},
|
||||
"loadingVideo": "正在載入影片...",
|
||||
"errors": {
|
||||
"noVideoLoaded": "未載入影片",
|
||||
"videoNotReady": "影片未就緒",
|
||||
@@ -15,7 +14,6 @@
|
||||
"failedToSaveVideo": "儲存影片失敗",
|
||||
"exportFailed": "匯出失敗",
|
||||
"exportFailedWithError": "匯出失敗:{{error}}",
|
||||
"exportBackgroundLoadFailed": "匯出失敗:無法載入背景圖片({{url}})",
|
||||
"failedToSaveExport": "儲存匯出檔案失敗",
|
||||
"failedToSaveExportedVideo": "儲存匯出的影片失敗",
|
||||
"failedToRevealInFolder": "在資料夾中顯示時出錯:{{error}}"
|
||||
@@ -38,8 +36,6 @@
|
||||
"systemAudioUnavailable": "系統音訊不可用。將在無系統音訊的情況下錄製。",
|
||||
"microphoneDenied": "麥克風權限被拒絕。錄製將繼續,但不包含音訊。",
|
||||
"cameraDenied": "攝影機權限被拒絕。錄製將繼續,但不包含攝影機畫面。",
|
||||
"permissionDenied": "錄影權限被拒絕。請允許螢幕錄製。",
|
||||
"cameraDisconnected": "網路攝影機已中斷連線。",
|
||||
"cameraNotFound": "找不到攝影機。"
|
||||
"permissionDenied": "錄影權限被拒絕。請允許螢幕錄製。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,5 @@
|
||||
"recording": {
|
||||
"selectSource": "請選擇要錄製的來源"
|
||||
},
|
||||
"language": "語言",
|
||||
"systemLanguagePrompt": {
|
||||
"title": "要使用系統語言嗎?",
|
||||
"description": "偵測到系統語言為 {{language}}。要將 OpenScreen 切換為 {{language}} 嗎?",
|
||||
"switch": "切換為 {{language}}",
|
||||
"keepDefault": "保持目前語言"
|
||||
}
|
||||
"language": "語言"
|
||||
}
|
||||
|
||||
@@ -15,14 +15,6 @@
|
||||
"fast": "快速",
|
||||
"smooth": "平滑",
|
||||
"lazy": "緩慢"
|
||||
},
|
||||
"threeD": {
|
||||
"title": "3D 旋轉",
|
||||
"preset": {
|
||||
"iso": "Iso",
|
||||
"left": "左",
|
||||
"right": "右"
|
||||
}
|
||||
}
|
||||
},
|
||||
"speed": {
|
||||
@@ -60,9 +52,7 @@
|
||||
"color": "顏色",
|
||||
"gradient": "漸層",
|
||||
"uploadCustom": "上傳自訂",
|
||||
"gradientLabel": "漸層 {{index}}",
|
||||
"colorWheel": "色輪",
|
||||
"colorPalette": "調色盤"
|
||||
"gradientLabel": "漸層 {{index}}"
|
||||
},
|
||||
"crop": {
|
||||
"title": "裁剪",
|
||||
@@ -130,8 +120,6 @@
|
||||
"background": "背景",
|
||||
"none": "無",
|
||||
"color": "顏色",
|
||||
"colorWheel": "色輪",
|
||||
"colorPalette": "調色盤",
|
||||
"clearBackground": "清除背景",
|
||||
"uploadImage": "上傳圖片",
|
||||
"supportedFormats": "支援的格式:JPG、PNG、GIF、WebP",
|
||||
@@ -151,14 +139,7 @@
|
||||
"invalidImageType": "無效的檔案類型",
|
||||
"imageFormatsOnly": "請上傳 JPG、PNG、GIF 或 WebP 格式的圖片檔案。",
|
||||
"imageUploadSuccess": "圖片上傳成功!",
|
||||
"failedImageUpload": "上傳圖片失敗",
|
||||
"blurColor": "模糊顏色",
|
||||
"blurColorBlack": "黑色",
|
||||
"blurColorWhite": "白色",
|
||||
"blurType": "模糊類型",
|
||||
"blurTypeBlur": "模糊",
|
||||
"blurTypeMosaic": "馬賽克模糊",
|
||||
"mosaicBlockSize": "馬賽克區塊大小"
|
||||
"failedImageUpload": "上傳圖片失敗"
|
||||
},
|
||||
"fontStyles": {
|
||||
"classic": "經典",
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
"labels": {
|
||||
"pan": "平移",
|
||||
"zoom": "縮放",
|
||||
"trim": "剪輯",
|
||||
"speed": "速度",
|
||||
"zoomItem": "縮放 {{index}}",
|
||||
"trimItem": "剪輯 {{index}}",
|
||||
"speedItem": "速度 {{index}}",
|
||||
@@ -51,5 +49,9 @@
|
||||
"success": {
|
||||
"addedZoomSuggestions": "已新增 {{count}} 個基於游標的縮放建議",
|
||||
"addedZoomSuggestionsPlural": "已新增 {{count}} 個基於游標的縮放建議"
|
||||
},
|
||||
"feedback": {
|
||||
"copied": "已複製!",
|
||||
"pasted": "已貼上!"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user