From a969fce5ac95fe999b9dfff53d23532ada4124f9 Mon Sep 17 00:00:00 2001 From: zyronon Date: Sun, 17 Aug 2025 17:03:50 +0800 Subject: [PATCH] fix:opt --- package.json | 7 +- pnpm-lock.yaml | 112 ++------------ src/App.vue | 1 + src/hooks/translate.ts | 10 +- src/libs/qs.ts | 7 + src/libs/translate/README.md | 1 + src/libs/translate/baidu.ts | 145 ++++++++++++++++++ src/libs/translate/languages/index.ts | 2 + src/libs/translate/languages/languages.ts | 123 +++++++++++++++ src/libs/translate/languages/locales.ts | 3 + src/libs/translate/translator/index.ts | 3 + src/libs/translate/translator/translator.ts | 100 ++++++++++++ src/libs/translate/translator/type.ts | 45 ++++++ .../pc/article/components/EditArticle.vue | 18 +-- .../components/EditSingleArticleModal.vue | 3 +- src/pages/pc/components/ConflictNotice.vue | 4 +- src/pages/pc/components/dialog/Dialog.vue | 6 +- src/pages/pc/word/Statistics.vue | 4 +- src/pages/pc/word/WordHomePage.vue | 10 +- src/router.ts | 9 +- src/stores/setting.ts | 6 +- src/utils/index.ts | 20 +-- vite.config.ts | 20 ++- 23 files changed, 511 insertions(+), 148 deletions(-) create mode 100644 src/libs/qs.ts create mode 100644 src/libs/translate/README.md create mode 100644 src/libs/translate/baidu.ts create mode 100644 src/libs/translate/languages/index.ts create mode 100644 src/libs/translate/languages/languages.ts create mode 100644 src/libs/translate/languages/locales.ts create mode 100644 src/libs/translate/translator/index.ts create mode 100644 src/libs/translate/translator/translator.ts create mode 100644 src/libs/translate/translator/type.ts diff --git a/package.json b/package.json index 39e3be87..e4178a3c 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,6 @@ }, "dependencies": { "@imengyu/vue3-context-menu": "^1.5.1", - "@opentranslate/baidu": "^1.4.2", - "@opentranslate/translator": "^1.4.2", "axios": "^1.10.0", "compromise": "^14.14.4", "copy-to-clipboard": "^3.3.3", @@ -30,13 +28,14 @@ "mitt": "^3.0.1", "nanoid": "^5.1.5", "pinia": "^3.0.3", - "sentence-splitter": "^4.4.1", "string-comparison": "^1.3.0", "vue": "^3.5.17", "vue-router": "^4.5.1", - "vue-virtual-scroller": "2.0.0-beta.8" + "vue-virtual-scroller": "2.0.0-beta.8", + "md5": "^2.2.1" }, "devDependencies": { + "@types/md5": "^2.1.33", "@alicloud/pop-core": "^1.8.0", "@iconify-json/basil": "^1.2.4", "@iconify-json/bi": "^1.2.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e00f579..6bef4ea4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,6 @@ importers: '@imengyu/vue3-context-menu': specifier: ^1.5.1 version: 1.5.2 - '@opentranslate/baidu': - specifier: ^1.4.2 - version: 1.4.2 - '@opentranslate/translator': - specifier: ^1.4.2 - version: 1.4.2 axios: specifier: ^1.10.0 version: 1.11.0 @@ -38,6 +32,9 @@ importers: libarchive-wasm: specifier: ^1.2.0 version: 1.2.0 + md5: + specifier: ^2.2.1 + version: 2.3.0 mitt: specifier: ^3.0.1 version: 3.0.1 @@ -53,9 +50,6 @@ importers: string-comparison: specifier: ^1.3.0 version: 1.3.0 - vite-plugin-externals: - specifier: ^0.6.2 - version: 0.6.2(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0)) vue: specifier: ^3.5.17 version: 3.5.18(typescript@5.9.2) @@ -159,6 +153,9 @@ importers: '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 + '@types/md5': + specifier: ^2.1.33 + version: 2.3.5 '@unocss/postcss': specifier: ^66.4.0 version: 66.4.2(postcss@8.5.6) @@ -219,9 +216,9 @@ importers: vite: specifier: ^7.0.3 version: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0) - vite-plugin-cdn-import: - specifier: file:./plugins/vite-plugin-cdn-import/dist - version: dist@file:plugins/vite-plugin-cdn-import/dist + vite-plugin-externals: + specifier: ^0.6.2 + version: 0.6.2(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(sass@1.90.0)) vue-tsc: specifier: ^3.0.1 version: 3.0.5(typescript@5.9.2) @@ -668,15 +665,6 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@opentranslate/baidu@1.4.2': - resolution: {integrity: sha512-j8V7P+OCzEIAa+Zh4P6tbgWizVuVfKJOXDvk6M865J4QOE1lUQIN/Hb5SdodePkFinwNbQK2mAb7qF9wO/nQbA==} - - '@opentranslate/languages@1.4.2': - resolution: {integrity: sha512-cexyjCYyvFRCUAsuCSpmfO1k4RWxrEHKFJYdCEsb+RqFWrTC8PsXupiWo2172c/8rNOW6BOMxiN3bZ2mETKV7g==} - - '@opentranslate/translator@1.4.2': - resolution: {integrity: sha512-AI5hLx5fiBOvhRsrmBwOTBa7ZHV1AsRsbfrowkL2wzLLmt3nBtHN+pqv8xVDEkPHUtOLVGqcmtuO2UQgbp+spQ==} - '@oxc-resolver/binding-darwin-arm64@4.2.0': resolution: {integrity: sha512-DP+KY4nXRJvL5XayKda0P7NCjcP1zZ5x6RZznMM/bMPCBrjcYNG4XKV9v/EbkSq3Et24mEJFYOM55WmPxtqf0w==} cpu: [arm64] @@ -977,9 +965,6 @@ packages: '@types/node@24.3.0': resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} - '@types/qs@6.14.0': - resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} - '@types/web-bluetooth@0.0.16': resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} @@ -1507,10 +1492,6 @@ packages: engines: {node: '>= 4.5.0'} hasBin: true - axios@0.19.2: - resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==} - deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410 - axios@1.11.0: resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} @@ -1703,9 +1684,6 @@ packages: resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} engines: {node: '>=0.8'} - collapse-white-space@1.0.6: - resolution: {integrity: sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==} - collection-map@1.0.0: resolution: {integrity: sha512-5D2XXSpkOnleOI21TG7p3T0bGAsZ/XknZpKBmGYyluO8pw4zA3K8ZlrBIbC4FXg3m6z/RNFiUFfT2sQK01+UHA==} engines: {node: '>=0.10.0'} @@ -1955,9 +1933,6 @@ packages: resolution: {integrity: sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==} engines: {node: '>= 8.0.0'} - dist@file:plugins/vite-plugin-cdn-import/dist: - resolution: {directory: plugins/vite-plugin-cdn-import/dist, type: directory} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2180,10 +2155,6 @@ packages: debug: optional: true - follow-redirects@1.5.10: - resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==} - engines: {node: '>=4.0'} - for-in@1.0.2: resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} engines: {node: '>=0.10.0'} @@ -2207,9 +2178,6 @@ packages: resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} engines: {node: '>=0.10.0'} - franc-min@4.1.1: - resolution: {integrity: sha512-7xpOX5GymdaT6d0qmSNFpyFuEd6tPuEHVZpL+KIh9DocVCVn59c2OnUvLn+NcWGGi7btqV1VZ5VbjSox5KbZKA==} - fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -2853,9 +2821,6 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - n-gram@1.1.2: - resolution: {integrity: sha512-mBTpWKp0NHdujHmxrskPg2jc108mjyMmVxHN1rZGK/ogTLi9O0debDIXlQPqotNELdNmVGtL4jr7SCig+4OWvQ==} - nan@2.23.0: resolution: {integrity: sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==} @@ -3556,13 +3521,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - trigram-utils@1.0.3: - resolution: {integrity: sha512-UAhS1Ll21FtClVIzIN0I/SmGnJ+D08BOxX7Dl1penV8raC0ksf2dJkhNI6kU1Mj3uT86Bul12iMvxXquXSYSng==} - - trim@0.0.1: - resolution: {integrity: sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==} - deprecated: Use String.prototype.trim() instead - ts-macro@0.1.35: resolution: {integrity: sha512-cMPJUCH8VsH9s9FANjL1r/SrkV2T6CKBjgWqgP2XGiS+y/zBBwmw0C3C31M4LqrLEjb8djgUMDV18vQ4Dr+/mg==} @@ -4464,26 +4422,6 @@ snapshots: '@tybys/wasm-util': 0.10.0 optional: true - '@opentranslate/baidu@1.4.2': - dependencies: - '@opentranslate/translator': 1.4.2 - '@types/md5': 2.3.5 - '@types/qs': 6.14.0 - md5: 2.3.0 - qs: 6.14.0 - transitivePeerDependencies: - - supports-color - - '@opentranslate/languages@1.4.2': {} - - '@opentranslate/translator@1.4.2': - dependencies: - '@opentranslate/languages': 1.4.2 - axios: 0.19.2 - franc-min: 4.1.1 - transitivePeerDependencies: - - supports-color - '@oxc-resolver/binding-darwin-arm64@4.2.0': optional: true @@ -4683,8 +4621,6 @@ snapshots: undici-types: 7.10.0 optional: true - '@types/qs@6.14.0': {} - '@types/web-bluetooth@0.0.16': optional: true @@ -5428,12 +5364,6 @@ snapshots: atob@2.1.2: {} - axios@0.19.2: - dependencies: - follow-redirects: 1.5.10 - transitivePeerDependencies: - - supports-color - axios@1.11.0: dependencies: follow-redirects: 1.15.11 @@ -5679,8 +5609,6 @@ snapshots: codepage@1.15.0: {} - collapse-white-space@1.0.6: {} - collection-map@1.0.0: dependencies: arr-map: 2.0.2 @@ -5912,8 +5840,6 @@ snapshots: digest-header@1.1.0: {} - dist@file:plugins/vite-plugin-cdn-import/dist: {} - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6195,12 +6121,6 @@ snapshots: follow-redirects@1.15.11: {} - follow-redirects@1.5.10: - dependencies: - debug: 3.1.0 - transitivePeerDependencies: - - supports-color - for-in@1.0.2: {} for-own@1.0.0: @@ -6228,10 +6148,6 @@ snapshots: dependencies: map-cache: 0.2.2 - franc-min@4.1.1: - dependencies: - trigram-utils: 1.0.3 - fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -6904,8 +6820,6 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - n-gram@1.1.2: {} - nan@2.23.0: optional: true @@ -7671,14 +7585,6 @@ snapshots: totalist@3.0.1: {} - trigram-utils@1.0.3: - dependencies: - collapse-white-space: 1.0.6 - n-gram: 1.1.2 - trim: 0.0.1 - - trim@0.0.1: {} - ts-macro@0.1.35: dependencies: muggle-string: 0.4.1 diff --git a/src/App.vue b/src/App.vue index 0bdb4a00..d2fa16a3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -22,6 +22,7 @@ watch(store.$state, (n: BaseState) => { }) watch(settingStore.$state, (n) => { + console.log('watch',settingStore.$state) set(SAVE_SETTING_KEY.key, JSON.stringify({val: n, version: SAVE_SETTING_KEY.version})) }) diff --git a/src/hooks/translate.ts b/src/hooks/translate.ts index f2c70450..ae6d0f32 100644 --- a/src/hooks/translate.ts +++ b/src/hooks/translate.ts @@ -1,13 +1,13 @@ import {Article, Sentence, TranslateEngine} from "@/types/types.ts"; -import Baidu from "@opentranslate/baidu"; -import {Translator} from "@opentranslate/translator/src/translator.ts"; +import Baidu from "@/libs/translate/baidu"; +import {Translator} from "@/libs/translate/translator/index.ts"; export function getSentenceAllTranslateText(article: Article) { - return article.sections.map(v => v.map(s => s.translate.trim()).filter(v=>v).join(' \n')).filter(v=>v).join(' \n\n'); + return article.sections.map(v => v.map(s => s.translate.trim()).filter(v => v).join(' \n')).filter(v => v).join(' \n\n'); } export function getSentenceAllText(article: Article) { - return article.sections.map(v => v.map(s => s.text.trim()).filter(v=>v).join(' \n')).filter(v=>v).join(' \n\n'); + return article.sections.map(v => v.map(s => s.text.trim()).filter(v => v).join(' \n')).filter(v => v).join(' \n\n'); } /*** @@ -48,6 +48,8 @@ export async function getNetworkTranslate( const translate = async (sentence: Sentence) => { try { let r = await translator.translate(sentence.text, 'en', 'zh-CN') + console.log(r) + if (r) { const cb = () => { sentence.translate = r.trans.paragraphs[0] diff --git a/src/libs/qs.ts b/src/libs/qs.ts new file mode 100644 index 00000000..f4694615 --- /dev/null +++ b/src/libs/qs.ts @@ -0,0 +1,7 @@ +export default { + stringify: (params: Record): string => { + return Object.entries(params) + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); + } +} diff --git a/src/libs/translate/README.md b/src/libs/translate/README.md new file mode 100644 index 00000000..d68ff75b --- /dev/null +++ b/src/libs/translate/README.md @@ -0,0 +1 @@ +复制这个库是因为他引入了franc-min这个包,太大了50多k,我用不到 diff --git a/src/libs/translate/baidu.ts b/src/libs/translate/baidu.ts new file mode 100644 index 00000000..e728a1bf --- /dev/null +++ b/src/libs/translate/baidu.ts @@ -0,0 +1,145 @@ +import { + Language, + Translator, + TranslateError, + TranslateQueryResult +} from "./translator"; +import md5 from "md5"; +import qs from "../qs"; + +const langMap: [Language, string][] = [ + ["auto", "auto"], + ["zh-CN", "zh"], + ["en", "en"], + ["yue", "yue"], + ["wyw", "wyw"], + ["ja", "jp"], + ["ko", "kor"], + ["fr", "fra"], + ["es", "spa"], + ["th", "th"], + ["ar", "ara"], + ["ru", "ru"], + ["pt", "pt"], + ["de", "de"], + ["it", "it"], + ["el", "el"], + ["nl", "nl"], + ["pl", "pl"], + ["bg", "bul"], + ["et", "est"], + ["da", "dan"], + ["fi", "fin"], + ["cs", "cs"], + ["ro", "rom"], + ["sl", "slo"], + ["sv", "swe"], + ["hu", "hu"], + ["zh-TW", "cht"], + ["vi", "vie"] +]; + +export interface BaiduConfig { + placeholder?: string; + appid: string; + key: string; +} + +export class Baidu extends Translator { + readonly name = "baidu"; + + readonly endpoint = "https://api.fanyi.baidu.com/api/trans/vip/translate"; + + protected async query( + text: string, + from: Language, + to: Language, + config: BaiduConfig + ): Promise { + type BaiduTranslateError = { + error_code: "54001" | string; + error_msg: "Invalid Sign" | string; + }; + + type BaiduTranslateResult = { + from: string; + to: string; + trans_result: Array<{ + dst: string; + src: string; + }>; + }; + + const salt = Date.now(); + const {endpoint} = this; + const {appid, key} = config; + + const res = await this.request( + endpoint, + { + params: { + from: Baidu.langMap.get(from), + to: Baidu.langMap.get(to), + q: text, + salt, + appid, + sign: md5(appid + text + salt + key) + } + } + ).catch(() => { + throw new TranslateError("NETWORK_ERROR"); + }); + + const {data} = res; + + if ((data as BaiduTranslateError).error_code) { + console.error( + new Error("[Baidu service]" + (data as BaiduTranslateError).error_msg) + ); + throw new TranslateError("API_SERVER_ERROR"); + } + + const { + trans_result: transResult, + from: langDetected + } = data as BaiduTranslateResult; + const transParagraphs = transResult.map(({dst}) => dst); + const detectedFrom = Baidu.langMapReverse.get(langDetected) as Language; + + return { + text, + from: detectedFrom, + to, + origin: { + paragraphs: transResult.map(({src}) => src), + tts: await this.textToSpeech(text, detectedFrom) + }, + trans: { + paragraphs: transParagraphs, + tts: await this.textToSpeech(transParagraphs.join(" "), to) + } + }; + } + + /** Translator lang to custom lang */ + private static readonly langMap = new Map(langMap); + + /** Custom lang to translator lang */ + private static readonly langMapReverse = new Map( + langMap.map(([translatorLang, lang]) => [lang, translatorLang]) + ); + + getSupportLanguages(): Language[] { + return [...Baidu.langMap.keys()]; + } + + async textToSpeech(text: string, lang: Language): Promise { + return `https://fanyi.baidu.com/gettts?${qs.stringify({ + lan: Baidu.langMap.get(lang !== "auto" ? lang : "zh-CN") || "zh", + text, + spd: 5, + })}`; + } +} + +export default Baidu; diff --git a/src/libs/translate/languages/index.ts b/src/libs/translate/languages/index.ts new file mode 100644 index 00000000..d539d171 --- /dev/null +++ b/src/libs/translate/languages/index.ts @@ -0,0 +1,2 @@ +export * from "./languages"; +export * from "./locales"; diff --git a/src/libs/translate/languages/languages.ts b/src/libs/translate/languages/languages.ts new file mode 100644 index 00000000..2795d098 --- /dev/null +++ b/src/libs/translate/languages/languages.ts @@ -0,0 +1,123 @@ +// eslint-disable-next-line @typescript-eslint/no-use-before-define +export type Language = (typeof languages)[number]; + +export const languages = [ + "af", + "am", + "ar", + "auto", + "az", + "be", + "bg", + "bn", + "bs", + "ca", + "ceb", + "co", + "cs", + "cy", + "da", + "de", + "el", + "en", + "eo", + "es", + "et", + "eu", + "fa", + "fi", + "fil", + "fj", + "fr", + "fy", + "ga", + "gd", + "gl", + "gu", + "ha", + "haw", + "he", + "hi", + "hmn", + "hr", + "ht", + "hu", + "hy", + "id", + "ig", + "is", + "it", + "ja", + "jw", + "ka", + "kk", + "km", + "kn", + "ko", + "ku", + "ky", + "la", + "lb", + "lo", + "lt", + "lv", + "mg", + "mi", + "mk", + "ml", + "mn", + "mr", + "ms", + "mt", + "mww", + "my", + "ne", + "nl", + "no", + "ny", + "otq", + "pa", + "pl", + "ps", + "pt", + "ro", + "ru", + "sd", + "si", + "sk", + "sl", + "sm", + "sn", + "so", + "sq", + "sr", + "sr-Cyrl", + "sr-Latn", + "st", + "su", + "sv", + "sw", + "ta", + "te", + "tg", + "th", + "tlh", + "tlh-Qaak", + "to", + "tr", + "ty", + "ug", + "uk", + "ur", + "uz", + "vi", + "wyw", + "xh", + "yi", + "yo", + "yua", + "yue", + "zh-CN", + "zh-TW", + "zu" +] as const; diff --git a/src/libs/translate/languages/locales.ts b/src/libs/translate/languages/locales.ts new file mode 100644 index 00000000..ada236b2 --- /dev/null +++ b/src/libs/translate/languages/locales.ts @@ -0,0 +1,3 @@ +import { Language } from "./languages"; + +export type Locale = { [key in Language]: string }; diff --git a/src/libs/translate/translator/index.ts b/src/libs/translate/translator/index.ts new file mode 100644 index 00000000..971260de --- /dev/null +++ b/src/libs/translate/translator/index.ts @@ -0,0 +1,3 @@ +export * from "../languages"; +export * from "./type"; +export * from "./translator"; diff --git a/src/libs/translate/translator/translator.ts b/src/libs/translate/translator/translator.ts new file mode 100644 index 00000000..d683ed52 --- /dev/null +++ b/src/libs/translate/translator/translator.ts @@ -0,0 +1,100 @@ +import { + Languages, + TranslatorEnv, + TranslatorInit, + TranslateResult, + TranslateQueryResult +} from "./type"; +import {Language} from "../languages"; +import Axios, {AxiosInstance, AxiosRequestConfig, AxiosPromise} from "axios"; + +export abstract class Translator { + axios: AxiosInstance; + + protected readonly env: TranslatorEnv; + + /** + * 自定义选项 + */ + config: Config; + + /** + * 翻译源标识符 + */ + abstract readonly name: string; + + /** + * 可选的axios实例 + */ + constructor(init: TranslatorInit = {}) { + this.env = init.env || "node"; + this.axios = init.axios || Axios; + this.config = init.config || ({} as Config); + } + + /** + * 获取翻译器所支持的语言列表: 语言标识符数组 + */ + abstract getSupportLanguages(): Languages; + + /** + * 下游应用调用的接口 + */ + async translate( + text: string, + from: Language, + to: Language, + config = {} as Config + ): Promise { + const queryResult = await this.query(text, from, to, { + ...this.config, + ...config + }); + + return { + ...queryResult, + engine: this.name + }; + } + + /** + * 更新 token 的方法 + */ + updateToken?(): Promise; + + /** + * 翻译源需要实现的方法 + */ + protected abstract query( + text: string, + from: Language, + to: Language, + config: Config + ): Promise; + + protected request( + url: string, + config?: AxiosRequestConfig + ): AxiosPromise { + return this.axios(url, config); + } + + /** + * 如果翻译源提供了单独的检测语言的功能,请实现此接口 + */ + async detect(text: string): Promise { + return + } + + /** + * 文本转换为语音 + * @returns {Promise} 语言文件地址 + */ + textToSpeech( + text: string, + lang: Language, + meta?: any // eslint-disable-line @typescript-eslint/no-explicit-any + ): Promise { + return Promise.resolve(null); + } +} diff --git a/src/libs/translate/translator/type.ts b/src/libs/translate/translator/type.ts new file mode 100644 index 00000000..cddc98a9 --- /dev/null +++ b/src/libs/translate/translator/type.ts @@ -0,0 +1,45 @@ +import {Language} from "../languages"; +import {AxiosInstance} from "axios"; + +export type Languages = Array; + +export type TranslatorEnv = "node" | "ext"; + +export interface TranslatorInit { + env?: TranslatorEnv; + axios?: AxiosInstance; + config?: Config; +} + +export type TranslateErrorType = + | "NETWORK_ERROR" + | "NETWORK_TIMEOUT" + | "API_SERVER_ERROR" + | "UNSUPPORTED_LANG" + | "UNKNOWN"; + +export class TranslateError extends Error { + constructor(message: TranslateErrorType) { + super(message); + } +} + +/** 统一的查询结果的数据结构 */ +export interface TranslateResult { + engine: string; + text: string; + from: Language; + to: Language; + /** 原文 */ + origin: { + paragraphs: string[]; + tts?: string; + }; + /** 译文 */ + trans: { + paragraphs: string[]; + tts?: string; + }; +} + +export type TranslateQueryResult = Omit; diff --git a/src/pages/pc/article/components/EditArticle.vue b/src/pages/pc/article/components/EditArticle.vue index c99f3989..3655bf7b 100644 --- a/src/pages/pc/article/components/EditArticle.vue +++ b/src/pages/pc/article/components/EditArticle.vue @@ -6,17 +6,17 @@ import EditAbleText from "@/pages/pc/components/EditAbleText.vue"; import {getNetworkTranslate, getSentenceAllText, getSentenceAllTranslateText} from "@/hooks/translate.ts"; import {genArticleSectionData, splitCNArticle2, splitEnArticle2, usePlaySentenceAudio} from "@/hooks/article.ts"; import {_nextTick, _parseLRC, cloneDeep, last} from "@/utils"; -import {watch} from "vue"; +import {defineAsyncComponent, watch} from "vue"; import Empty from "@/components/Empty.vue"; import Toast from '@/pages/pc/components/base/toast/Toast.ts' import * as Comparison from "string-comparison" import BaseIcon from "@/components/BaseIcon.vue"; -import Dialog from "@/pages/pc/components/dialog/Dialog.vue"; import {getDefaultArticle} from "@/types/func.ts"; import copy from "copy-to-clipboard"; import {Option, Select} from "@/pages/pc/components/base/select"; import Tooltip from "@/pages/pc/components/base/Tooltip.vue"; import InputNumber from "@/pages/pc/components/base/InputNumber.vue"; +const Dialog = defineAsyncComponent(() => import('@/pages/pc/components/dialog/Dialog.vue')) interface IProps { article?: Article, @@ -38,8 +38,8 @@ let progress = $ref(0) let failCount = $ref(0) let textareaRef = $ref() const TranslateEngineOptions = [ - {value: 'baidu', label: '百度'}, {value: 'youdao', label: '有道'}, + {value: 'baidu', label: '百度'}, ] let editArticle = $ref
(getDefaultArticle()) @@ -494,11 +494,11 @@ function setStartTime(val: Sentence, i: number, j: number) { - {{ editSentence.audioPosition?.[1] }}s - 结束 - - +
@@ -507,18 +507,18 @@ function setStartTime(val: Sentence, i: number, j: number) {
- - - + - +
记录
diff --git a/src/pages/pc/article/components/EditSingleArticleModal.vue b/src/pages/pc/article/components/EditSingleArticleModal.vue index 00290577..65cf2449 100644 --- a/src/pages/pc/article/components/EditSingleArticleModal.vue +++ b/src/pages/pc/article/components/EditSingleArticleModal.vue @@ -1,10 +1,11 @@