feat(typeartice.vue): add baidu translate

This commit is contained in:
zyronon
2023-09-10 23:52:59 +08:00
parent 7b1b82430a
commit f22a6fb322
7 changed files with 349 additions and 2 deletions

View File

@@ -0,0 +1,3 @@
[[redirects]]
from = "/baidu"
to = "https://api.fanyi.baidu.com/api/trans/vip/translate"

View File

@@ -7,12 +7,16 @@
"dev": "vite",
"build": "vue-tsc && vite build",
"build2": "vite build",
"preview": "vite preview"
"preview": "vite preview",
"commit": "git-cz",
"prepare": "husky install",
"test": ""
},
"dependencies": {
"@icon-park/vue-next": "^1.4.2",
"@opentranslate/baidu": "^1.4.2",
"@opentranslate/translator": "^1.4.2",
"axios": "^1.5.0",
"element-plus": "^2.3.9",
"hover.css": "^2.3.2",
"localforage": "^1.10.0",
@@ -32,6 +36,7 @@
"@vue/compiler-sfc": "^3.3.4",
"commitizen": "^4.3.0",
"cz-conventional-changelog": "^3.3.0",
"husky": "^8.0.3",
"sass": "^1.64.2",
"typescript": "^5.2.0",
"unplugin-icons": "^0.16.5",

73
pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ dependencies:
'@opentranslate/translator':
specifier: ^1.4.2
version: 1.4.2
axios:
specifier: ^1.5.0
version: 1.5.0
element-plus:
specifier: ^2.3.9
version: 2.3.9(vue@3.3.4)
@@ -67,6 +70,9 @@ devDependencies:
cz-conventional-changelog:
specifier: ^3.3.0
version: 3.3.0
husky:
specifier: ^8.0.3
version: 8.0.3
sass:
specifier: ^1.64.2
version: 1.64.2
@@ -1128,6 +1134,10 @@ packages:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
dev: false
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/at-least-node@1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
@@ -1142,6 +1152,16 @@ packages:
- supports-color
dev: false
/axios@1.5.0:
resolution: {integrity: sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==}
dependencies:
follow-redirects: 1.15.2
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
@@ -1320,6 +1340,13 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/commitizen@4.3.0:
resolution: {integrity: sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==}
engines: {node: '>= 12'}
@@ -1471,6 +1498,11 @@ packages:
clone: 1.0.4
dev: true
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/detect-file@1.0.0:
resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==}
engines: {node: '>=0.10.0'}
@@ -1656,6 +1688,16 @@ packages:
resolve-dir: 1.0.1
dev: true
/follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/follow-redirects@1.5.10:
resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==}
engines: {node: '>=4.0'}
@@ -1665,6 +1707,15 @@ packages:
- supports-color
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/franc-min@4.1.1:
resolution: {integrity: sha512-7xpOX5GymdaT6d0qmSNFpyFuEd6tPuEHVZpL+KIh9DocVCVn59c2OnUvLn+NcWGGi7btqV1VZ5VbjSox5KbZKA==}
dependencies:
@@ -1826,6 +1877,12 @@ packages:
engines: {node: '>=10.17.0'}
dev: true
/husky@8.0.3:
resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
engines: {node: '>=14'}
hasBin: true
dev: true
/iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
@@ -2162,6 +2219,18 @@ packages:
picomatch: 2.3.1
dev: true
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: false
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
@@ -2387,6 +2456,10 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}

View File

@@ -24,6 +24,7 @@ import {useEventListener} from "@/hooks/useEvent.ts";
import TypeWord from "@/components/Practice/TypeWord.vue";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import Baidu from "@opentranslate/baidu";
import {AxiosInstance} from "@/utils/http";
let article1 = `How does the older investor differ in his approach to investment from the younger investor?
There is no shortage of tipsters around offering 'get-rich-quick' opportunities. But if you are a serious private investor, leave the Las Vegas mentality to those with money to fritter. The serious investor needs a proper 'portfolio' -- a well-planned selection of investments, with a definite structure and a clear aim. But exactly how does a newcomer to the stock market go about achieving that?
@@ -96,12 +97,13 @@ onMounted(() => {
let sections = useSplitArticle(article.article)
let temp = useSplitCNArticle(article.articleTranslate, 'cn', CnKeyboardMap)
const baidu = new Baidu({
axios: AxiosInstance,
config: {
appid: "20230910001811857",
key: "Xxe_yftQR3K3Ue43NQMC"
}
})
baidu.translate('fuck', 'en','zh-CN').then(r => {
baidu.translate('fuck', 'en', 'zh-CN').then(r => {
console.log('s', r)
})
practiceStore.total = 0

View File

@@ -0,0 +1,146 @@
import {
Language,
Translator,
TranslateError,
TranslateQueryResult
} from "@opentranslate/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 BaiduTranslate {
readonly name = "baidu";
apiUrl = "https://api.fanyi.baidu.com/api/trans/vip/translate";
readonly endpoint = "https://api.fanyi.baidu.com/api/trans/vip/translate";
protected async query(
text: string,
from: Language,
to: Language,
config: BaiduConfig
): Promise<TranslateQueryResult> {
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<BaiduTranslateResult | BaiduTranslateError>(
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<string> {
return `https://fanyi.baidu.com/gettts?${qs.stringify({
lan: Baidu.langMap.get(lang !== "auto" ? lang : "zh-CN") || "zh",
text,
spd: 5,
})}`;
}
}
export default Baidu;

114
src/utils/http.ts Normal file
View File

@@ -0,0 +1,114 @@
import axios from 'axios'
// import globalMethods from './global-methods'
// import Config from '../config/index'
// import CONSTANT from './const_var'
// import store from '../store'
// import Storage from './storage'
export const AxiosInstance = axios.create({
// baseURL: process.env.NODE_ENV === 'production' ? Config.PRODUCT_API_URL : Config.API_URL,
// baseURL: 'http://testtestgp.com',
timeout: 15000,
})
// request 拦截器
AxiosInstance.interceptors.request.use(
(config) => {
console.log('config', config)
if (config.url === 'https://api.fanyi.baidu.com/api/trans/vip/translate'){
config.url = '/baidu'
}
return config
},
error => Promise.reject(error),
)
// respone 拦截器
// instance.interceptors.response.use(
// // 响应正常的处理
// (response) => {
// // console.log(response)
// // console.log(response.data)
// const { data } = response
// if (response.status !== 200) {
// globalMethods.$warning(response.statusText)
// return Promise.reject(data)
// }
// if (data === null) {
// return Promise.resolve({
// code: '009900',
// msg: '系统出现错误',
// data: {},
// })
// }
// return Promise.resolve(data)
// },
// // 请求出错的处理
// (error) => {
// console.log(error)
// if (error.response === undefined && error.status === undefined) {
// return Promise.resolve({
// code: '009900',
// msg: '服务器响应超时',
// data: null,
// })
// }
// if (error.response.status >= 500) {
// return Promise.resolve({
// code: '009900',
// msg: '服务器出现错误',
// data: null,
// })
// }
// if (error.response.status === 401) {
// return Promise.resolve({
// code: '009900',
// msg: '用户名或密码不正确',
// data: null,
// })
// }
// const { data } = error.response
// if (data.code !== undefined) {
// return Promise.resolve({
// code: data.code,
// msg: data.msg,
// })
// }
// return Promise.resolve({
// code: '009900',
// msg: data.msg,
// data: null,
// })
// },
// )
/**
* @apiDescription 封装的网络请求方法
* @apiGroup
* @apiName request
* @apiParam url 地址
* @apiParam data 请求数据
* @apiParam params 请求参数
* @apiParam method 方法类型get或者post
* @apiParam version 接口版本号
* @apiParamExample
* request('Appointment/appointmentList', data, params, CONSTANT.GET)
* @apiReturn Promise
*/
// async function request(url, data = {}, params = {}, method = CONSTANT.POST, version = Config.API_VERSION) {
// // console.log(url)
// if (method === CONSTANT.POST) {
// data.userId = store.state.user.userInfo === null ? '' : store.state.user.userInfo.id
// } else {
// params.userId = store.state.user.userInfo === null ? '' : store.state.user.userInfo.id
// }
// return instance({
// url: version + url,
// method,
// data,
// params,
// })
// }
// export default request

View File

@@ -33,6 +33,10 @@ export default defineConfig({
host: '0.0.0.0',
fs: {
strict: false,
},
proxy: {
'/baidu': 'https://api.fanyi.baidu.com/api/trans/vip/translate'
}
}
})