parent
cb1da01788
commit
855fbf1b96
@ -1,3 +1,6 @@ |
|||||||
node_modules |
node_modules |
||||||
dist/ |
dist/ |
||||||
*.log |
*.log |
||||||
|
.env |
||||||
|
deploy |
||||||
|
.idea |
File diff suppressed because it is too large
Load Diff
@ -1,50 +1,164 @@ |
|||||||
import { Text, Window, hot, View } from "@nodegui/react-nodegui"; |
import {Button, ComboBox, hot, PlainTextEdit, Text, View, Window} from "@nodegui/react-nodegui"; |
||||||
import React from "react"; |
import React from "react"; |
||||||
import { QIcon } from "@nodegui/nodegui"; |
import {AlignmentFlag, QIcon} from "@nodegui/nodegui"; |
||||||
import { StepOne } from "./components/stepone"; |
|
||||||
import { StepTwo } from "./components/steptwo"; |
|
||||||
import nodeguiIcon from "../assets/nodegui.jpg"; |
import nodeguiIcon from "../assets/nodegui.jpg"; |
||||||
|
import {RNComboBox} from "@nodegui/react-nodegui/dist/components/ComboBox/RNComboBox"; |
||||||
|
import {RNText} from "@nodegui/react-nodegui/dist/components/Text/RNText"; |
||||||
|
import tencentTmt from "./tencent"; |
||||||
|
import {RNPlainTextEdit} from "@nodegui/react-nodegui/dist/components/PlainTextEdit/RNPlainTextEdit"; |
||||||
|
import baiduTranslate from "./baidu" |
||||||
|
import Translate from "./components/Translate"; |
||||||
|
|
||||||
|
class App extends React.Component<any, any> { |
||||||
|
private getComboBoxHandler: (key: ("sourceIndex" | "targetIndex")) => (index: number) => void; |
||||||
|
private sourceLang: Array<{text:string,lang:string}>; |
||||||
|
private lang: { [key: string]: string }; |
||||||
|
private sourceRef: React.RefObject<RNComboBox>; |
||||||
|
private targetRef:React.RefObject<RNComboBox>; |
||||||
|
private labelRef: React.RefObject<RNText>; |
||||||
|
private sourceTextRef: React.RefObject<RNPlainTextEdit>; |
||||||
|
private tencentTextRef: React.RefObject<RNPlainTextEdit>; |
||||||
|
private baiduTextRef: React.RefObject<RNPlainTextEdit>; |
||||||
|
|
||||||
|
constructor(props: any) { |
||||||
|
super(props); |
||||||
|
this.state = { |
||||||
|
additionalButtons: [], |
||||||
|
size: {height: 300, width: 900}, |
||||||
|
allow:false, |
||||||
|
} |
||||||
|
this.sourceRef=React.createRef<RNComboBox>() |
||||||
|
this.targetRef=React.createRef<RNComboBox>() |
||||||
|
this.labelRef=React.createRef<RNText>() |
||||||
|
this.sourceTextRef=React.createRef<RNPlainTextEdit>() |
||||||
|
this.tencentTextRef=React.createRef<RNPlainTextEdit>() |
||||||
|
this.baiduTextRef=React.createRef<RNPlainTextEdit>() |
||||||
|
this.getComboBoxHandler = (key: 'sourceIndex' | 'targetIndex') => { |
||||||
|
return (index: number) => { |
||||||
|
let ref |
||||||
|
if(key==='sourceIndex'){ |
||||||
|
ref=this.targetRef |
||||||
|
}else{ |
||||||
|
ref=this.sourceRef |
||||||
|
} |
||||||
|
if (ref.current?.currentIndex() === index) { |
||||||
|
for(let langIndex in this.sourceLang){ |
||||||
|
if(+langIndex!==index){ |
||||||
|
ref.current?.setCurrentIndex(+langIndex) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// console.debug(`${key}选中${this.sourceLang[index].text}`)
|
||||||
|
} |
||||||
|
} |
||||||
|
this.lang = { |
||||||
|
'en': '英语', |
||||||
|
'zh': '中文' |
||||||
|
} |
||||||
|
this.sourceLang = [] |
||||||
|
|
||||||
|
|
||||||
|
for (let key in this.lang) { |
||||||
|
this.sourceLang.push({text: this.lang[key],lang:key}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
componentDidMount() { |
||||||
|
this.labelRef.current?.setAlignment(AlignmentFlag.AlignCenter) |
||||||
|
} |
||||||
|
|
||||||
const minSize = { width: 500, height: 520 }; |
|
||||||
const winIcon = new QIcon(nodeguiIcon); |
|
||||||
class App extends React.Component { |
|
||||||
render() { |
render() { |
||||||
|
|
||||||
|
const winIcon = new QIcon(nodeguiIcon); |
||||||
|
|
||||||
|
const comboHandler = { |
||||||
|
currentIndexChanged: this.getComboBoxHandler("sourceIndex"), |
||||||
|
} |
||||||
|
const targetComboHandler = { |
||||||
|
currentIndexChanged: this.getComboBoxHandler("targetIndex") |
||||||
|
} |
||||||
|
|
||||||
|
const sourceHandler={ |
||||||
|
textChanged:()=>{ |
||||||
|
let flag=(this.sourceTextRef.current?.toPlainText().length||0)>0 |
||||||
|
this.setState({allow:flag}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const translateHandler={ |
||||||
|
clicked:()=>{ |
||||||
|
let source=this.sourceTextRef.current?.toPlainText()||'' |
||||||
|
let target=this.sourceLang[this.targetRef.current?.currentIndex()||0].lang |
||||||
|
tencentTmt(source,target) |
||||||
|
.then(res=>{ |
||||||
|
console.info(res); |
||||||
|
this.tencentTextRef.current?.setPlainText(res.TargetText) |
||||||
|
}).catch(err=>console.error("error", err)) |
||||||
|
|
||||||
|
baiduTranslate(source,target).then((res: { text: () => any; })=>res.text()).then((res: string)=>{ |
||||||
|
console.info(res) |
||||||
|
let r=JSON.parse(res) |
||||||
|
this.baiduTextRef.current?.setPlainText(r["trans_result"][0]["dst"]) |
||||||
|
}).catch((err: any)=>console.error("error", err)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
return ( |
return ( |
||||||
<Window |
<Window styleSheet={styleSheet} |
||||||
windowIcon={winIcon} |
windowIcon={winIcon} size={this.state.size}> |
||||||
windowTitle="Hello 👋🏽" |
<View id="rootView"> |
||||||
minSize={minSize} |
<View style={`flex-direction:row`}> |
||||||
styleSheet={styleSheet} |
<ComboBox style={`flex:1;`} items={this.sourceLang.concat({lang:'auto',text:'自动'})} currentIndex={0} |
||||||
> |
on={comboHandler} ref={this.sourceRef}></ComboBox> |
||||||
<View style={containerStyle}> |
<ComboBox style={`flex:1;`} items={this.sourceLang} currentIndex={1} |
||||||
<Text id="welcome-text">Welcome to NodeGui 🐕</Text> |
on={targetComboHandler} ref={this.targetRef}></ComboBox> |
||||||
<Text id="step-1">1. Play around</Text> |
</View> |
||||||
<StepOne /> |
<View style={`flex-direction:row;flex:1;`}> |
||||||
<Text id="step-2">2. Debug</Text> |
|
||||||
<StepTwo /> |
<View style={`flex-direction:column;flex:1;`}> |
||||||
|
<PlainTextEdit placeholderText='请输入原文' |
||||||
|
ref={this.sourceTextRef} |
||||||
|
on={sourceHandler} |
||||||
|
style={`flex:9`} |
||||||
|
></PlainTextEdit> |
||||||
|
<Text id="tencent" style={`flex:1`} ref={this.labelRef}></Text> |
||||||
|
</View> |
||||||
|
|
||||||
|
|
||||||
|
<Translate targetTextRef={this.tencentTextRef} name={"腾讯翻译"} href={"https://cloud.tencent.com/product/tmt"}/> |
||||||
|
<Translate targetTextRef={this.baiduTextRef} name={"百度翻译"} href={"https://api.fanyi.baidu.com/"}/> |
||||||
|
|
||||||
|
</View> |
||||||
|
<View style={`align-items:'center';padding:5px`}> |
||||||
|
<Button enabled={this.state.allow} text="翻译" on={translateHandler}></Button> |
||||||
|
</View> |
||||||
</View> |
</View> |
||||||
</Window> |
</Window> |
||||||
); |
); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
const containerStyle = ` |
|
||||||
flex: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const styleSheet = ` |
const styleSheet = ` |
||||||
#welcome-text { |
#rootView{ |
||||||
font-size: 24px; |
height: '100%'; |
||||||
padding-top: 20px; |
flex-direction:'column'; |
||||||
qproperty-alignment: 'AlignHCenter'; |
} |
||||||
font-family: 'sans-serif'; |
|
||||||
} |
|
||||||
|
|
||||||
#step-1, #step-2 { |
QPushButton{ |
||||||
font-size: 18px; |
width:300; |
||||||
padding-top: 10px; |
color:red; |
||||||
padding-horizontal: 20px; |
font-size:20px; |
||||||
} |
background-color:gray; |
||||||
`;
|
border-radius:10px; |
||||||
|
} |
||||||
|
QPushButton:pressed{ |
||||||
|
background-color:gray; |
||||||
|
} |
||||||
|
QPushButton:enabled{
|
||||||
|
background-color: white; |
||||||
|
} |
||||||
|
` |
||||||
|
|
||||||
export default hot(App); |
export default hot(App); |
||||||
|
@ -0,0 +1,12 @@ |
|||||||
|
const fetch = require("node-fetch"); |
||||||
|
const MD5 = require('md5.js'); |
||||||
|
|
||||||
|
function md5(message:string){ |
||||||
|
return new MD5().update(message).digest('hex') |
||||||
|
} |
||||||
|
|
||||||
|
export default async function baiduTranslate(q:string,to:string){ |
||||||
|
let salt=Math.round(Math.random()*new Date().getTime()) |
||||||
|
let sign=md5(process.env.REACT_APP_BAIDU_APP_ID+q+salt+process.env.REACT_APP_BAIDU_SECRET_KEY) |
||||||
|
return fetch.default(`http://api.fanyi.baidu.com/api/trans/vip/translate?q=${q}&from=auto&to=${to}&appid=${process.env.REACT_APP_BAIDU_APP_ID}&salt=${salt}&sign=${sign}`) |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
import {PlainTextEdit, Text, View} from "@nodegui/react-nodegui"; |
||||||
|
import React, {useEffect, useRef} from "react"; |
||||||
|
import {RNPlainTextEdit} from "@nodegui/react-nodegui/dist/components/PlainTextEdit/RNPlainTextEdit"; |
||||||
|
import {RNText} from "@nodegui/react-nodegui/dist/components/Text/RNText"; |
||||||
|
import {AlignmentFlag} from "@nodegui/nodegui"; |
||||||
|
|
||||||
|
export default function Translate(props: {targetTextRef:React.RefObject<RNPlainTextEdit>,name:string,href:string}){ |
||||||
|
|
||||||
|
const labelRef=useRef<RNText>() |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
labelRef.current?.setAlignment(AlignmentFlag.AlignCenter) |
||||||
|
}); |
||||||
|
|
||||||
|
return <View style={`flex-direction:column;flex:1;`}> |
||||||
|
<PlainTextEdit style={`flex:9`} readOnly={true} ref={props.targetTextRef}></PlainTextEdit> |
||||||
|
<Text openExternalLinks={true} ref={labelRef} style={`flex:1;text-align:center;`} on={{ |
||||||
|
}}>{"<a href=\""+props.href+"\">"+props.name}</Text> |
||||||
|
</View> |
||||||
|
} |
@ -1,30 +0,0 @@ |
|||||||
module.exports = `data:image/png;base64,
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAADIAAAAzCAMAAADivasmAAACglBMVEUAAABPPz9RQj9QQUBPPj5PPz5TRENQQEBTQUFRQUFRQUFTQ0J |
|
||||||
RQUFQQEBkWFdXSkpVSUhTQEFRQUFUQUFQQUBQQEBOPj1QQD9WQkVdUE5RRERZTEtWRkdRQUFQQEBQQEBSQUJRQUFRQEBURUVQQEBPPT |
|
||||||
1aRUVOPT1VRkZPQUBRQEBRQUBSQUFPQEBTQUFSQ0NRQEFQQkFUPkFUQkNOPz5RPj9SP0BTRERVRUVUQEFWRUX///+jnpz+//6lnpykn
|
|
||||||
pz9/f2inpyinZv9/v2kn538+/v///6inpv7+vmknZv+/v/+/f22s7KnoJ6Xj4+ln51SQkJVP0ClnZtTQEK0sa6koJ38/Pr19fTT0c+m
|
|
||||||
oJ6Gfn3w7u6wrKuhm5lOQkBSPj/l5OLBv72sp6Wmo6CdlpSblJL6f4f3gIRRQD9NQD78/fv5+fbz8/Lr6enf3dzFw8G/u7qkm5qgmJa |
|
||||||
MhoV6cnF/T1D8/f3y8vLt7Ovh4N/a2NjLx8bIxsWuqaeknp+nn52akZCTi4mRiIePhoV/eXjKcnh5bWxrYmFpYF9gVVVdUVJYSklMPT |
|
||||||
v49/jl5OTd29nOy8rMycjHxsS8uLaopKShmZf2goiLg4KIfn2DeXh5cG9yaGdvZmVoXV1cTU9VR0dLPzry8O/p6Ofm5ubZ1tbW1NLS0 |
|
||||||
tHRzszDwb+6trS1srD4gomEfXt1a2q0ZWpsZWT29/Xo5ePV0tO7ubicl5iYkpKVjY3ofofde4KMgYHNc3qtZmuRWFhZTUxPQ0RbQEG1 |
|
||||||
sLGyrq6qqqr4gYbzhYXpfYXxhISJfHx+dHPDbnO/bnOAcnK+bHG5a3B0bGy2ZWqgZGicWVxlXFqWXFlyUE9KQ0GhVcLgAAAAO3RSTlM |
|
||||||
AB9CjBc/izbaqZzInDf759e7DbmtGGxYR+fj29cm5rpaNXT07A/3669mdkoV7elJPLSHz6d3UfV9UML/w/okAAAWkSURBVEjHhZZlVx |
|
||||||
tBFIaXUqAtdXd3d8vszmp2kwBpQkJKDCkUd0pb3IpTijvU3d3dXf9PZzbaNpy+n/acO8+ZK+/chHBq8taoLZOWEENp/YiGCfOnE96a1 |
|
||||||
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`;
|
|
@ -1,30 +0,0 @@ |
|||||||
import { Text, View } from "@nodegui/react-nodegui"; |
|
||||||
import React from "react"; |
|
||||||
const dogImg = require("./dog"); |
|
||||||
|
|
||||||
export function StepOne() { |
|
||||||
return ( |
|
||||||
<View style={containerStyle}> |
|
||||||
<Text wordWrap={true}> |
|
||||||
Edit App.tsx to make changes to this screen. Then come back to see your |
|
||||||
changes. Changes should reflect live thanks to Hot Reloading. 🔥 |
|
||||||
</Text> |
|
||||||
<Text> |
|
||||||
{` |
|
||||||
<p style="color: rgb(255,72,38);">
|
|
||||||
<center> |
|
||||||
<img src="${dogImg}" alt="doggy" />
|
|
||||||
</center> |
|
||||||
<center>You can even use <i><strong>Rich Html</strong></i> text like this if you want 😎.</center> |
|
||||||
</p> |
|
||||||
<hr /> |
|
||||||
`}
|
|
||||||
</Text> |
|
||||||
</View> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
const containerStyle = ` |
|
||||||
margin-horizontal: 20px; |
|
||||||
padding-horizontal: 10px; |
|
||||||
`;
|
|
@ -1,53 +0,0 @@ |
|||||||
import { Text, View, Button, useEventHandler } from "@nodegui/react-nodegui"; |
|
||||||
import { QPushButtonSignals } from "@nodegui/nodegui"; |
|
||||||
import React from "react"; |
|
||||||
import open from "open"; |
|
||||||
|
|
||||||
export function StepTwo() { |
|
||||||
const btnHandler = useEventHandler<QPushButtonSignals>( |
|
||||||
{ |
|
||||||
clicked: () => open("https://react.nodegui.org").catch(console.log) |
|
||||||
}, |
|
||||||
[] |
|
||||||
); |
|
||||||
return ( |
|
||||||
<View style={containerStyle}> |
|
||||||
<Text style={textStyle} wordWrap={true}> |
|
||||||
{` |
|
||||||
<ol> |
|
||||||
<li> |
|
||||||
Open chrome and navigate to chrome://inspect. You should see a target below with your app.
|
|
||||||
</li> |
|
||||||
<br/> |
|
||||||
<li> |
|
||||||
Next click on "Open dedicated DevTools for Node" |
|
||||||
</li> |
|
||||||
<br/> |
|
||||||
<li> |
|
||||||
On the dedicated devtools. Click on Source > Node > "Your node process" |
|
||||||
</li> |
|
||||||
</ol> |
|
||||||
`}
|
|
||||||
</Text> |
|
||||||
<Button |
|
||||||
style={btnStyle} |
|
||||||
on={btnHandler} |
|
||||||
text={`Open React NodeGui docs`} |
|
||||||
></Button> |
|
||||||
</View> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
const containerStyle = ` |
|
||||||
flex: 1; |
|
||||||
justify-content: 'space-around'; |
|
||||||
`;
|
|
||||||
|
|
||||||
const textStyle = ` |
|
||||||
padding-right: 20px; |
|
||||||
`;
|
|
||||||
|
|
||||||
const btnStyle = ` |
|
||||||
margin-horizontal: 20px; |
|
||||||
height: 40px; |
|
||||||
`;
|
|
@ -0,0 +1,40 @@ |
|||||||
|
import {TextTranslateResponse} from "tencentcloud-sdk-nodejs/tencentcloud/services/tmt/v20180321/tmt_models"; |
||||||
|
|
||||||
|
const tencentcloud = require("tencentcloud-sdk-nodejs") |
||||||
|
|
||||||
|
const TmtClient = tencentcloud.tmt.v20180321.Client; |
||||||
|
|
||||||
|
const clientConfig = { |
||||||
|
credential: { |
||||||
|
secretId: process.env.REACT_APP_TENCENT_SECRET_ID, |
||||||
|
secretKey: process.env.REACT_APP_TENCENT_SECRET_KEY, |
||||||
|
}, |
||||||
|
region: process.env.REACT_APP_TENCENT_REGION, |
||||||
|
profile: { |
||||||
|
httpProfile: { |
||||||
|
endpoint: process.env.REACT_APP_TENCENT_ENDPOINT, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
const client = new TmtClient(clientConfig) |
||||||
|
export default function tencentTmt(SourceText:string,Target:string){ |
||||||
|
return new Promise((resolve:(value:TextTranslateResponse)=>void, reject) => { |
||||||
|
const params = { |
||||||
|
SourceText, |
||||||
|
"Source": "auto", |
||||||
|
Target, |
||||||
|
"ProjectId": 0 |
||||||
|
}; |
||||||
|
client.TextTranslate(params).then( |
||||||
|
(res:TextTranslateResponse) => { |
||||||
|
resolve(res) |
||||||
|
}, |
||||||
|
(err: any) => { |
||||||
|
reject(err) |
||||||
|
} |
||||||
|
) |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue