diff --git a/package-lock.json b/package-lock.json index 901f8ca24df..fbd5b974ff7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24329,6 +24329,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -24346,6 +24347,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -24357,13 +24359,15 @@ "version": "9.2.2", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -24381,6 +24385,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -24396,6 +24401,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^7.0.4" }, @@ -24407,13 +24413,15 @@ "version": "1.1.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/@npmcli/agent": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -24430,6 +24438,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^4.0.0", @@ -24479,6 +24488,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/map-workspaces": "^4.0.1", "@npmcli/package-json": "^6.0.1", @@ -24498,6 +24508,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "semver": "^7.3.5" }, @@ -24510,6 +24521,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/promise-spawn": "^8.0.0", "ini": "^5.0.0", @@ -24529,6 +24541,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "npm-bundled": "^4.0.0", "npm-normalize-package-bin": "^4.0.0" @@ -24545,6 +24558,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/name-from-folder": "^3.0.0", "@npmcli/package-json": "^6.0.0", @@ -24560,6 +24574,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "cacache": "^19.0.0", "json-parse-even-better-errors": "^4.0.0", @@ -24576,6 +24591,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/git": "^6.0.0", "@npmcli/installed-package-contents": "^3.0.0", @@ -24607,6 +24623,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -24616,6 +24633,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -24625,6 +24643,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/git": "^6.0.0", "glob": "^10.2.2", @@ -24643,6 +24662,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "which": "^5.0.0" }, @@ -24655,6 +24675,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "postcss-selector-parser": "^7.0.0" }, @@ -24667,6 +24688,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -24676,6 +24698,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/node-gyp": "^4.0.0", "@npmcli/package-json": "^6.0.0", @@ -24694,6 +24717,7 @@ "inBundle": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=14" } @@ -24703,6 +24727,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -24712,6 +24737,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@sigstore/protobuf-specs": "^0.4.1", "tuf-js": "^3.0.1" @@ -24725,6 +24751,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -24734,6 +24761,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -24743,6 +24771,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 14" } @@ -24752,6 +24781,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -24761,6 +24791,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -24772,25 +24803,29 @@ "version": "2.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/archy": { "version": "1.0.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/balanced-match": { "version": "1.0.2", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/bin-links": { "version": "5.0.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "cmd-shim": "^7.0.0", "npm-normalize-package-bin": "^4.0.0", @@ -24807,6 +24842,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" }, @@ -24819,6 +24855,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -24828,6 +24865,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/fs": "^4.0.0", "fs-minipass": "^3.0.0", @@ -24851,6 +24889,7 @@ "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", + "peer": true, "engines": { "node": ">=18" } @@ -24860,6 +24899,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "bin": { "mkdirp": "dist/cjs/src/bin.js" }, @@ -24875,6 +24915,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", @@ -24892,6 +24933,7 @@ "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", + "peer": true, "engines": { "node": ">=18" } @@ -24901,6 +24943,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -24913,6 +24956,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": ">=10" } @@ -24928,6 +24972,7 @@ ], "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -24937,6 +24982,7 @@ "dev": true, "inBundle": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "ip-regex": "^5.0.0" }, @@ -24949,6 +24995,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "string-width": "^4.2.3", "strip-ansi": "^6.0.1" @@ -24962,6 +25009,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -24971,6 +25019,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -24982,19 +25031,22 @@ "version": "1.1.4", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/cross-spawn": { "version": "7.0.6", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -25009,6 +25061,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "isexe": "^2.0.0" }, @@ -25024,6 +25077,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "bin": { "cssesc": "bin/cssesc" }, @@ -25036,6 +25090,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ms": "^2.1.3" }, @@ -25053,6 +25108,7 @@ "dev": true, "inBundle": true, "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=0.3.1" } @@ -25061,13 +25117,15 @@ "version": "0.2.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/encoding": { "version": "0.1.13", @@ -25075,6 +25133,7 @@ "inBundle": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -25084,6 +25143,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -25092,19 +25152,22 @@ "version": "2.0.3", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/exponential-backoff": { "version": "3.1.2", "dev": true, "inBundle": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/npm/node_modules/fastest-levenshtein": { "version": "1.0.16", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 4.9.1" } @@ -25114,6 +25177,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -25130,6 +25194,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^7.0.3" }, @@ -25142,6 +25207,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -25161,13 +25227,15 @@ "version": "4.2.11", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/hosted-git-info": { "version": "8.1.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "lru-cache": "^10.0.1" }, @@ -25179,13 +25247,15 @@ "version": "4.2.0", "dev": true, "inBundle": true, - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "peer": true }, "node_modules/npm/node_modules/http-proxy-agent": { "version": "7.0.2", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -25199,6 +25269,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "agent-base": "^7.1.2", "debug": "4" @@ -25213,6 +25284,7 @@ "inBundle": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -25225,6 +25297,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minimatch": "^9.0.0" }, @@ -25237,6 +25310,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.19" } @@ -25246,6 +25320,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -25255,6 +25330,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/package-json": "^6.0.0", "npm-package-arg": "^12.0.0", @@ -25273,6 +25349,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -25286,6 +25363,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -25298,6 +25376,7 @@ "dev": true, "inBundle": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "cidr-regex": "^4.1.1" }, @@ -25310,6 +25389,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -25318,13 +25398,15 @@ "version": "2.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/jackspeak": { "version": "3.4.3", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", + "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -25339,13 +25421,15 @@ "version": "1.1.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/json-parse-even-better-errors": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -25355,6 +25439,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -25366,25 +25451,29 @@ "node >= 0.2.0" ], "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/just-diff": { "version": "6.0.2", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/just-diff-apply": { "version": "5.5.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/libnpmaccess": { "version": "9.0.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "npm-package-arg": "^12.0.0", "npm-registry-fetch": "^18.0.1" @@ -25398,6 +25487,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/arborist": "^8.0.1", "@npmcli/installed-package-contents": "^3.0.0", @@ -25417,6 +25507,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/arborist": "^8.0.1", "@npmcli/run-script": "^9.0.1", @@ -25438,6 +25529,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/arborist": "^8.0.1" }, @@ -25450,6 +25542,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^18.0.1" @@ -25463,6 +25556,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^18.0.1" @@ -25476,6 +25570,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/arborist": "^8.0.1", "@npmcli/run-script": "^9.0.1", @@ -25491,6 +25586,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "ci-info": "^4.0.0", "normalize-package-data": "^7.0.0", @@ -25510,6 +25606,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "npm-registry-fetch": "^18.0.1" }, @@ -25522,6 +25619,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "aproba": "^2.0.0", "npm-registry-fetch": "^18.0.1" @@ -25535,6 +25633,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/git": "^6.0.1", "@npmcli/run-script": "^9.0.1", @@ -25550,13 +25649,15 @@ "version": "10.4.3", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "14.0.3", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/agent": "^3.0.0", "cacache": "^19.0.1", @@ -25579,6 +25680,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.6" } @@ -25588,6 +25690,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -25603,6 +25706,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -25612,6 +25716,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^7.0.3" }, @@ -25624,6 +25729,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -25641,6 +25747,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -25653,6 +25760,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -25665,6 +25773,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -25677,6 +25786,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -25689,6 +25799,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -25701,6 +25812,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -25713,6 +25825,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "minipass": "^7.1.2" }, @@ -25725,6 +25838,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -25736,13 +25850,15 @@ "version": "2.1.3", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/mute-stream": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -25752,6 +25868,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", @@ -25776,6 +25893,7 @@ "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", + "peer": true, "engines": { "node": ">=18" } @@ -25785,6 +25903,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "bin": { "mkdirp": "dist/cjs/src/bin.js" }, @@ -25800,6 +25919,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", @@ -25817,6 +25937,7 @@ "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", + "peer": true, "engines": { "node": ">=18" } @@ -25826,6 +25947,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "abbrev": "^3.0.0" }, @@ -25841,6 +25963,7 @@ "dev": true, "inBundle": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "hosted-git-info": "^8.0.0", "semver": "^7.3.5", @@ -25855,6 +25978,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -25864,6 +25988,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "npm-normalize-package-bin": "^4.0.0" }, @@ -25876,6 +26001,7 @@ "dev": true, "inBundle": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "semver": "^7.1.1" }, @@ -25888,6 +26014,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -25897,6 +26024,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "hosted-git-info": "^8.0.0", "proc-log": "^5.0.0", @@ -25912,6 +26040,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "ignore-walk": "^7.0.0" }, @@ -25924,6 +26053,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "npm-install-checks": "^7.1.0", "npm-normalize-package-bin": "^4.0.0", @@ -25939,6 +26069,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "npm-registry-fetch": "^18.0.0", "proc-log": "^5.0.0" @@ -25952,6 +26083,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/redact": "^3.0.0", "jsonparse": "^1.3.1", @@ -25971,6 +26103,7 @@ "dev": true, "inBundle": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -25980,6 +26113,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -25991,13 +26125,15 @@ "version": "1.0.1", "dev": true, "inBundle": true, - "license": "BlueOak-1.0.0" + "license": "BlueOak-1.0.0", + "peer": true }, "node_modules/npm/node_modules/pacote": { "version": "19.0.1", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "@npmcli/git": "^6.0.0", "@npmcli/installed-package-contents": "^3.0.0", @@ -26029,6 +26165,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "json-parse-even-better-errors": "^4.0.0", "just-diff": "^6.0.0", @@ -26043,6 +26180,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -26052,6 +26190,7 @@ "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", + "peer": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -26068,6 +26207,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -26081,6 +26221,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -26090,6 +26231,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -26099,6 +26241,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -26108,6 +26251,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -26117,6 +26261,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -26130,6 +26275,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "read": "^4.0.0" }, @@ -26141,6 +26287,7 @@ "version": "0.12.0", "dev": true, "inBundle": true, + "peer": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" } @@ -26150,6 +26297,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "mute-stream": "^2.0.0" }, @@ -26162,6 +26310,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -26171,6 +26320,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "json-parse-even-better-errors": "^4.0.0", "npm-normalize-package-bin": "^4.0.0" @@ -26184,6 +26334,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 4" } @@ -26193,13 +26344,15 @@ "dev": true, "inBundle": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/npm/node_modules/semver": { "version": "7.7.2", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -26212,6 +26365,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -26224,6 +26378,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -26233,6 +26388,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": ">=14" }, @@ -26245,6 +26401,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", @@ -26262,6 +26419,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@sigstore/protobuf-specs": "^0.4.0" }, @@ -26274,6 +26432,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -26283,6 +26442,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", @@ -26300,6 +26460,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@sigstore/bundle": "^3.1.0", "@sigstore/core": "^2.0.0", @@ -26314,6 +26475,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -26324,6 +26486,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -26338,6 +26501,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", @@ -26352,6 +26516,7 @@ "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -26362,6 +26527,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -26371,13 +26537,15 @@ "version": "2.5.0", "dev": true, "inBundle": true, - "license": "CC-BY-3.0" + "license": "CC-BY-3.0", + "peer": true }, "node_modules/npm/node_modules/spdx-expression-parse": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -26387,19 +26555,22 @@ "version": "3.0.21", "dev": true, "inBundle": true, - "license": "CC0-1.0" + "license": "CC0-1.0", + "peer": true }, "node_modules/npm/node_modules/sprintf-js": { "version": "1.1.3", "dev": true, "inBundle": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/npm/node_modules/ssri": { "version": "12.0.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^7.0.3" }, @@ -26412,6 +26583,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -26427,6 +26599,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -26441,6 +26614,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -26454,6 +26628,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -26466,6 +26641,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -26478,6 +26654,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -26495,6 +26672,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "minipass": "^3.0.0" }, @@ -26507,6 +26685,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -26519,6 +26698,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": ">=8" } @@ -26528,6 +26708,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -26541,6 +26722,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -26552,19 +26734,22 @@ "version": "0.2.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/tiny-relative-date": { "version": "1.3.0", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/tinyglobby": { "version": "0.2.14", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" @@ -26581,6 +26766,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -26595,6 +26781,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -26607,6 +26794,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -26616,6 +26804,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "@tufjs/models": "3.0.1", "debug": "^4.3.6", @@ -26630,6 +26819,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.5" @@ -26643,6 +26833,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "unique-slug": "^5.0.0" }, @@ -26655,6 +26846,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "imurmurhash": "^0.1.4" }, @@ -26666,13 +26858,15 @@ "version": "1.0.2", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/validate-npm-package-license": { "version": "3.0.4", "dev": true, "inBundle": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -26683,6 +26877,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -26693,6 +26888,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -26701,13 +26897,15 @@ "version": "3.0.1", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/npm/node_modules/which": { "version": "5.0.0", "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "isexe": "^3.1.1" }, @@ -26723,6 +26921,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "engines": { "node": ">=16" } @@ -26732,6 +26931,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -26750,6 +26950,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -26767,6 +26968,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -26782,6 +26984,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -26793,13 +26996,15 @@ "version": "9.2.2", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { "version": "5.1.2", "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -26817,6 +27022,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -26832,6 +27038,7 @@ "dev": true, "inBundle": true, "license": "ISC", + "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" @@ -26844,7 +27051,8 @@ "version": "4.0.0", "dev": true, "inBundle": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/nth-check": { "version": "2.1.1", diff --git a/src/app/services/teacherProjectTranslationService.spec.ts b/src/app/services/teacherProjectTranslationService.spec.ts index d7ddb632fa6..c206f6c0b3c 100644 --- a/src/app/services/teacherProjectTranslationService.spec.ts +++ b/src/app/services/teacherProjectTranslationService.spec.ts @@ -48,4 +48,19 @@ describe('TeacherProjectTranslationService', () => { expect(request.request.body).toEqual({}); }); }); + describe('getTranslationSuggestion()', () => { + it('makes a POST request to backend with do not translate tags', () => { + service + .getTranslationSuggestion('srcLang', 'targetLang', 'srcText untagged') + .subscribe(); + const request = http.expectOne(`/api/author/project/translate/translationSuggestions`); + expect(request.request.method).toEqual('POST'); + expect(request.request.body).toEqual({ + srcLang: 'srcLang', + targetLang: 'targetLang', + srcText: + 'srcText untagged' + }); + }); + }); }); diff --git a/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.scss b/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.scss index 2f11ee88776..65d27e7d69e 100644 --- a/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.scss +++ b/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.scss @@ -19,3 +19,21 @@ mat-form-field.translatable-form-field { margin-top: 4px; } } + +.translatable-input-hints { + display: flex; +} + +.translation-suggestions { + margin-left: 8px; + text-decoration: underline; + color: blue; +} + +.translation-suggestions:hover { + cursor: pointer; +} + +.translation-tools { + padding: 8px 0; +} \ No newline at end of file diff --git a/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.ts b/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.ts index e58bde1ec7f..2c9d7904e13 100644 --- a/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.ts +++ b/src/assets/wise5/authoringTool/components/abstract-translatable-field/abstract-translatable-field.component.ts @@ -1,4 +1,5 @@ import { Input, Signal, Output, computed, Directive } from '@angular/core'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Subject, Subscription, debounceTime } from 'rxjs'; import { Language } from '../../../../../app/domain/language'; import { TeacherProjectTranslationService } from '../../../services/teacherProjectTranslationService'; @@ -6,6 +7,7 @@ import { TeacherProjectService } from '../../../services/teacherProjectService'; import { generateRandomKey } from '../../../common/string/string'; import { toObservable } from '@angular/core/rxjs-interop'; import { Translations } from '../../../../../app/domain/translations'; +import { TranslationSuggestionsDialogComponent } from '../translation-suggestions-dialog/translation-suggestions-dialog.component'; import { copy } from '../../../common/object/object'; @Directive() @@ -27,6 +29,7 @@ export abstract class AbstractTranslatableFieldComponent { protected translationText: string; protected translationTextChanged: Subject = new Subject(); constructor( + protected dialog: MatDialog, protected projectService: TeacherProjectService, protected projectTranslationService: TeacherProjectTranslationService ) {} @@ -75,4 +78,39 @@ export abstract class AbstractTranslatableFieldComponent { currentTranslations[this.i18nId] = { value: text, modified: new Date().getTime() }; this.projectTranslationService.saveCurrentTranslations(currentTranslations).subscribe(); } + + protected async translateText(): Promise { + if (this.translationText) { + this.openDialog(); + } else { + this.projectTranslationService + .getTranslationSuggestion( + this.defaultLanguage.language, + this.currentLanguage().language, + this.content[this.key] + ) + .subscribe((translation) => this.saveTranslationText(translation)); + } + } + + private openDialog(): void { + const dialogRef = this.createDialogRef(); + dialogRef.afterClosed().subscribe((result: string) => { + if (result) { + this.saveTranslationText(result); + } + }); + } + + private createDialogRef(): MatDialogRef { + return this.dialog.open(TranslationSuggestionsDialogComponent, { + width: '40%', + data: { + defaultLanguage: this.defaultLanguage.language, + currentLanguage: this.currentLanguage().language, + defaultLanguageContent: this.content[this.key], + currentLanguageContent: this.translationText + } + }); + } } diff --git a/src/assets/wise5/authoringTool/components/translatable-asset-chooser/translatable-asset-chooser.component.ts b/src/assets/wise5/authoringTool/components/translatable-asset-chooser/translatable-asset-chooser.component.ts index 610a9f945bf..2ec78115985 100644 --- a/src/assets/wise5/authoringTool/components/translatable-asset-chooser/translatable-asset-chooser.component.ts +++ b/src/assets/wise5/authoringTool/components/translatable-asset-chooser/translatable-asset-chooser.component.ts @@ -22,11 +22,11 @@ export class TranslatableAssetChooserComponent extends AbstractTranslatableField }; constructor( - private dialog: MatDialog, + protected dialog: MatDialog, protected projectService: TeacherProjectService, protected projectTranslationService: TeacherProjectTranslationService ) { - super(projectService, projectTranslationService); + super(dialog, projectService, projectTranslationService); } protected chooseAsset(): void { diff --git a/src/assets/wise5/authoringTool/components/translatable-input/translatable-input.component.html b/src/assets/wise5/authoringTool/components/translatable-input/translatable-input.component.html index 0e418991fa8..933f7480d9d 100644 --- a/src/assets/wise5/authoringTool/components/translatable-input/translatable-input.component.html +++ b/src/assets/wise5/authoringTool/components/translatable-input/translatable-input.component.html @@ -11,9 +11,16 @@ @if (hint) { {{ hint }} } - - translate {{ defaultLanguage.language }}: - {{ content[key] }} + +
+ translate {{ defaultLanguage.language }}: + {{ content[key] }} +
+ @if (content[key]) { +
+ auto_awesome Translate with AI +
+ }
} @else { diff --git a/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.html b/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.html index 900e80f181f..893bf510acd 100644 --- a/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.html +++ b/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.html @@ -41,6 +41,13 @@ + @if (content[key]) { +
+ + auto_awesome Translate with AI + +
+ } } @else { } diff --git a/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.ts b/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.ts index 40fddaf4437..ec4ddc300ba 100644 --- a/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.ts +++ b/src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.ts @@ -6,12 +6,20 @@ import { insertWiseLinks, replaceWiseLinks } from '../../../common/wise-link/wis import { ConfigService } from '../../../services/configService'; import { TeacherProjectTranslationService } from '../../../services/teacherProjectTranslationService'; import { TeacherProjectService } from '../../../services/teacherProjectService'; +import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; @Component({ - imports: [MatButtonModule, MatTabsModule, WiseAuthoringTinymceEditorComponent], + imports: [ + MatButtonModule, + MatDialogModule, + MatIconModule, + MatTabsModule, + WiseAuthoringTinymceEditorComponent + ], selector: 'translatable-rich-text-editor', - styles: ['.translation-tools { padding: 8px 0; }'], + styleUrl: '../abstract-translatable-field/abstract-translatable-field.component.scss', templateUrl: './translatable-rich-text-editor.component.html' }) export class TranslatableRichTextEditorComponent extends AbstractTranslatableFieldComponent { @@ -20,10 +28,11 @@ export class TranslatableRichTextEditorComponent extends AbstractTranslatableFie constructor( private configService: ConfigService, + protected dialog: MatDialog, protected projectService: TeacherProjectService, protected projectTranslationService: TeacherProjectTranslationService ) { - super(projectService, projectTranslationService); + super(dialog, projectService, projectTranslationService); } ngOnChanges(): void { diff --git a/src/assets/wise5/authoringTool/components/translatable-textarea/translatable-textarea.component.html b/src/assets/wise5/authoringTool/components/translatable-textarea/translatable-textarea.component.html index 5a71253a018..b8745a19def 100644 --- a/src/assets/wise5/authoringTool/components/translatable-textarea/translatable-textarea.component.html +++ b/src/assets/wise5/authoringTool/components/translatable-textarea/translatable-textarea.component.html @@ -12,9 +12,16 @@ @if (hint) { {{ hint }} } - - translate {{ defaultLanguage.language }}: - {{ content[key] }} + +
+ translate {{ defaultLanguage.language }}: + {{ content[key] }} +
+ @if (content[key]) { +
+ auto_awesome Translate with AI +
+ }
} @else { diff --git a/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.html b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.html new file mode 100644 index 00000000000..c443962adaf --- /dev/null +++ b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.html @@ -0,0 +1,21 @@ + +

+ {{ this.data.defaultLanguage }} text +

+

{{ this.data.defaultLanguageContent }}

+

+ {{ this.data.currentLanguage }} text (current translation) +

+

{{ this.data.currentLanguageContent }}

+

+ {{ this.data.currentLanguage }} text (AI suggested translation) +

+

{{ this.translation }}

+

+ Do you want to replace the current translation with the AI suggested translation? +

+
+ + + + diff --git a/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.scss b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.scss new file mode 100644 index 00000000000..2991245a003 --- /dev/null +++ b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.scss @@ -0,0 +1,7 @@ +.text-content { + margin-left: 15px; +} + +.replace-translation { + margin-top: 20px; +} \ No newline at end of file diff --git a/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.spec.ts b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.spec.ts new file mode 100644 index 00000000000..5a129a2df31 --- /dev/null +++ b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.spec.ts @@ -0,0 +1,35 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TeacherProjectTranslationService } from '../../../services/teacherProjectTranslationService'; +import { TranslationSuggestionsDialogComponent } from './translation-suggestions-dialog.component'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MockProvider } from 'ng-mocks'; +import { of } from 'rxjs'; + +describe('TranslationSuggestionsDialogComponent', () => { + let component: TranslationSuggestionsDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TranslationSuggestionsDialogComponent], + providers: [ + MockProvider(TeacherProjectTranslationService), + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: MatDialogRef, useValue: {} } + ] + }).compileComponents(); + + spyOn( + TestBed.inject(TeacherProjectTranslationService), + 'getTranslationSuggestion' + ).and.returnValue(of('Example translated text')); + + fixture = TestBed.createComponent(TranslationSuggestionsDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.ts b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.ts new file mode 100644 index 00000000000..214ad5c9491 --- /dev/null +++ b/src/assets/wise5/authoringTool/components/translation-suggestions-dialog/translation-suggestions-dialog.component.ts @@ -0,0 +1,58 @@ +import { Component, inject } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogActions, + MatDialogContent, + MatDialogRef +} from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { TeacherProjectTranslationService } from '../../../services/teacherProjectTranslationService'; + +interface TranslationSuggestionsDialogData { + defaultLanguage: string; + currentLanguage: string; + defaultLanguageContent: string; + currentLanguageContent?: string; +} + +@Component({ + selector: 'translation-suggestions-dialog', + imports: [ + MatFormFieldModule, + MatInputModule, + FormsModule, + MatButtonModule, + MatDialogContent, + MatDialogActions + ], + templateUrl: './translation-suggestions-dialog.component.html', + styleUrl: './translation-suggestions-dialog.component.scss' +}) +export class TranslationSuggestionsDialogComponent { + readonly dialogRef = inject(MatDialogRef); + readonly data = inject(MAT_DIALOG_DATA); + protected translation; + + constructor(protected projectTranslationService: TeacherProjectTranslationService) { + this.generateTranslationSuggestion(); + } + + private generateTranslationSuggestion(): void { + this.projectTranslationService + .getTranslationSuggestion( + this.data.defaultLanguage, + this.data.currentLanguage, + this.data.defaultLanguageContent + ) + .subscribe((suggestedTranslation: string) => { + this.translation = suggestedTranslation; + }); + } + + protected onClose(saveTranslation: boolean): void { + this.dialogRef.close(saveTranslation && this.translation); + } +} diff --git a/src/assets/wise5/services/teacherProjectTranslationService.ts b/src/assets/wise5/services/teacherProjectTranslationService.ts index 627dfd30a2e..e65f2611ef9 100644 --- a/src/assets/wise5/services/teacherProjectTranslationService.ts +++ b/src/assets/wise5/services/teacherProjectTranslationService.ts @@ -48,4 +48,35 @@ export class TeacherProjectTranslationService extends ProjectTranslationService }) ); } + + getTranslationSuggestion( + defaultLanguage: string, + currentLanguage: string, + defaultLanguageText: string + ): Observable { + return this.http + .post( + `/api/author/project/translate/translationSuggestions`, + { + srcLang: defaultLanguage, + targetLang: currentLanguage, + srcText: this.addDoNotTranslateTags(defaultLanguageText) + }, + { responseType: 'text' } + ) + .pipe(map(this.removeDoNotTranslateTags)); + } + + private addDoNotTranslateTags(textToTranslate: string): string { + return textToTranslate.replaceAll( + /<.*?>/g, + (match) => '' + match + '' + ); + } + + private removeDoNotTranslateTags(translatedText: string): string { + return translatedText.replaceAll(/<.*?><\/span>/g, (match) => + match.slice(21, -7) + ); + } } diff --git a/src/messages.xlf b/src/messages.xlf index 4013aba5253..26a59d6082f 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -11048,7 +11048,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.Are you sure you want to replace the content in with content in for this item? src/assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component.ts - 50,52 + 59,61