feat(typeartice.vue): add baidu translate
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
[[redirects]]
|
||||
from = "/baidu"
|
||||
to = "https://api.fanyi.baidu.com/api/trans/vip/translate"
|
||||
@@ -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
73
pnpm-lock.yaml
generated
@@ -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'}
|
||||
|
||||
@@ -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
|
||||
|
||||
146
src/translate/baidu/index.ts
Normal file
146
src/translate/baidu/index.ts
Normal 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
114
src/utils/http.ts
Normal 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
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user