Compare commits

...

51 Commits

Author SHA1 Message Date
DESKTOP-3BO4HSG\ksat f265b48e8a chore: optimized singleton pattern is lazy and thread-safe
2 years ago
DESKTOP-3BO4HSG\ksat 758a21f9ad perf: update new serve
2 years ago
Song 0b3a9ee6f0
feat: update config model
2 years ago
DESKTOP-3BO4HSG\ksat ec2ded168e perf: optimize animation effects
2 years ago
DESKTOP-3BO4HSG\ksat 98b6408115 docs: api failure description
2 years ago
DESKTOP-3BO4HSG\ksat 67141f97bd docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 5b9731caec perf: update version to 0.25
2 years ago
SONGE9B3\song_pd_win11 d5eac2ebf0 perf: optimized display
2 years ago
SONGE9B3\song_pd_win11 7eaa02503c feat: add toast
2 years ago
Song 0bdd7757ce
docs: update readme
2 years ago
SONGE9B3\song_pd_win11 4000bd23d5 docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 46b1da8b14 Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
SONGE9B3\song_pd_win11 af38ef7cfb chore: update version tag
2 years ago
Song 18ecb6aca5
Update README.md
2 years ago
SONGE9B3\song_pd_win11 8abd2f3dea feat: update new api
2 years ago
DESKTOP-3BO4HSG\ksat 21c5cab0f8 feat: add tooltip
2 years ago
DESKTOP-3BO4HSG\ksat 9b2fbc6e49 perf: create desktop shorcut at first time
2 years ago
DESKTOP-3BO4HSG\ksat 01b9af34dd Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
DESKTOP-3BO4HSG\ksat e4c690f226 feat: optimize the problem of blurred icons when switching resolution
2 years ago
zggsong d3da657e52 chore: ignore .dsstore
2 years ago
zggsong 127c5c3d56 docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 1f6b277c8e Merge branch 'main' of https://github.com/ZGGSONG/STranslate
2 years ago
DESKTOP-3BO4HSG\ksat 1d91ab510e 0.21
2 years ago
DESKTOP-3BO4HSG\ksat b561f44678 feat: add reset hot keys
2 years ago
DESKTOP-3BO4HSG\ksat 471cc632b2 feat: add change hotkeys func
2 years ago
DESKTOP-3BO4HSG\ksat 84ea248601 perf: add keydown to textbox
2 years ago
DESKTOP-3BO4HSG\ksat 74eb8755a5 fix: hot keys conflict message
2 years ago
Song 0de7a3776d
docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 5fbfc19ec3 feat: add translation local cache function
2 years ago
DESKTOP-3BO4HSG\ksat a93c422838 perf: update chinese and english automatic recognition proportion configuration item
2 years ago
DESKTOP-3BO4HSG\ksat 4974e53bf1 Merge branch 'dev_settings'
2 years ago
DESKTOP-3BO4HSG\ksat d9d8d71fa7 perf: update translate while change api
2 years ago
DESKTOP-3BO4HSG\ksat 1a7e9599f5 chore: update click event
2 years ago
DESKTOP-3BO4HSG\ksat dcd47be44a perf: update setting
2 years ago
DESKTOP-3BO4HSG\ksat 655335d49f tmp
2 years ago
zggsong 1753630c90 docs: update readme for .net env
2 years ago
DESKTOP-3BO4HSG\ksat 999ed5c459 chore: add setting view
2 years ago
DESKTOP-3BO4HSG\ksat 41422a0f83 docs: update readme
2 years ago
DESKTOP-3BO4HSG\ksat 03e9652ad6 publish: 0.18
2 years ago
DESKTOP-3BO4HSG\ksat 4db74c1a66 chore(tray): add shortcut text
2 years ago
DESKTOP-3BO4HSG\ksat a91965a75d perf: adding manual gc ensures a very small memory footprint
2 years ago
DESKTOP-3BO4HSG\ksat c0643c40e9 feat: add updater by https://github.com/Planshit/Tai
2 years ago
DESKTOP-3BO4HSG\ksat 96fe851fbe perf: update combobox style
2 years ago
DESKTOP-3BO4HSG\ksat 11385128bc perf: optimize dark mode theme style
2 years ago
DESKTOP-3BO4HSG\ksat 6429342193 publish: 0.16
2 years ago
DESKTOP-3BO4HSG\ksat c7d7b984a0 fix: esc bind no control
2 years ago
SONGE9B3\song_pd_win11 579d967003 perf: replace hardcodet by forms notifyicon(win11 will have a better experience)
2 years ago
DESKTOP-3BO4HSG\ksat 741d9a2efd fix: topmost shortcut
2 years ago
SONGE9B3\song_pd_win11 3c3949fe07 chore: update close view when close
2 years ago
DESKTOP-3BO4HSG\ksat ca3d75a4fc chore: update tray and readme
2 years ago
DESKTOP-3BO4HSG\ksat 0923ccf415 fix: null input
2 years ago

4
.gitignore vendored

@ -2,6 +2,8 @@
bin/
obj/
*.user
.idea/
packages/
packages/
.DS_Store

@ -10,11 +10,11 @@
<a href="https://github.com/ZGGSONG/STranslate/releases/latest" target="_blank">
<img alt="Latest GitHub release" src="https://img.shields.io/github/release/ZGGSONG/STranslate.svg" />
</a>
<a href="https://github.com/ZGGSONG/STranslate" target="_self">
<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/ZGGSONG/STranslate" />
<a href="https://hub.docker.com/r/zggsong/translate">
<img alt="Docker pull" src="https://img.shields.io/docker/pulls/zggsong/translate">
</a>
<a href="https://github.com/ZGGSONG/STranslate" target="_self">
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/ZGGSONG/STranslate" />
<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/ZGGSONG/STranslate" />
</a>
</p>
<h1 align="center">STranslate</h1>
@ -25,17 +25,20 @@
## 功能
- [x] 添加 DeepL API
- [x] 实现基本翻译功能
- [x] 优化防止多开
- [x] 添加划词翻译
- [x] 添加复制结果蛇形、大小驼峰
- [x] 软件层面识别语种(目前支持中英文)
- [x] 软件层面识别语种(中英文)
- [x] 添加开机自启
- [x] 添加/暗主题
- [x] 添加/暗主题
- [x] 添加 UI 设置缓存(用户目录下 `AppData\Local\STranslate`)
- [x] 添加语音合成
- [ ] 添加 OCR 翻译
- [ ] 添加翻译记录缓存功能
- [x] 添加离线语音合成
- [x] 添加离线截图文字识别(支持英文, 中文数据包过大且体验不好)
- [x] 添加检查更新
- [x] 添加翻译记录缓存功能
## 安装
下载最新 [Release](https://github.com/ZGGSONG/STranslate/releases) 版本后解压即可使用
## 使用
@ -44,28 +47,92 @@
![previews_dark](./example_dark.png)
打开软件后会静默在后台,等待调用
1. 全局监听快捷键
- `Alt` + `A` 打开软件界面,输入内容按回车翻译
- `Alt` + `D` 复制当前鼠标选中内容并翻译
- `Alt` + `S` 截图选中区域内容并翻译
- `Alt` + `G` 打开窗口(不清空内容)
2. 软件内快捷键
1. 软件内快捷键
- `ESC` 隐藏界面
- `Ctrl+Shift+Q` 退出程序
- `Ctrl+Shift+R` 切换主题
- `Ctrl+Shift+T` 置顶/取消置顶
点击软件外部界面任意处或点击软件则会自动隐藏到后台,即用即走。
点击软件外部任意处即自动隐藏到后台——即用即走。
> STranslate依赖于.NET Framework 4.8 运行环境如果程序启动时提示“This application requires *** .NETFramework,Version=v4.8”,请点击以下链接下载并安装.NET Framework 4.8 运行环境。
> [适用于 Windows 的 Microsoft .NET Framework 4.8 脱机安装程序下载](https://download.visualstudio.microsoft.com/download/pr/2d6bb6b2-226a-4baa-bdec-798822606ff1/8494001c276a4b96804cde7829c04d7f/ndp48-x86-x64-allos-enu.exe) | [Microsoft Support](https://support.microsoft.com/zh-cn/topic/%E9%80%82%E7%94%A8%E4%BA%8E-windows-%E7%9A%84-microsoft-net-framework-4-8-%E8%84%B1%E6%9C%BA%E5%AE%89%E8%A3%85%E7%A8%8B%E5%BA%8F-9d23f658-3b97-68ab-d013-aa3c3e7495e0)
## 卸载
1. 删除软件运行目录
2. 打开 cmd 运行下面的命令即可
```shell
rd /s /q "%localappdata%\stranslate"
```
## 开发历史
- 2023-03-02 0.25 添加复制提醒动画
- 2023-02-28 0.24 添加 deepl([deno.dev](deno.dev)) 接口(已经安装的cmd运行 `del %localappdata%\stranslate\stranslate.json` 后打开即可更新接口)
- 2023-02-24 0.22 优化分辨率切换时托盘图标模糊问题
- 2023-01-17 0.20 添加翻译记录缓存功能,重复翻译从本地数据库获取,本地记录数量上限可调整
- 2023-01-12 0.18 优化 GC 后台静默运行内存占用保持 4MB 左右
- 2023-01-12 0.17 添加检查更新功能
- 2023-01-10 0.15 添加离线 OCR 功能,其使用 [tesseract](https://github.com/tesseract-ocr/tesseract) 目前仅支持英文
<details>
<summary>自修改提示</summary>
有经验者可自行下载 [语言包](https://github.com/tesseract-ocr/tessdata) 至 `tessdata` 目录后修改 `Util`中`TesseractGetText`方法即可
```C#
public static string TesseractGetText(Bitmap bmp)
{
try
{
using (var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default))
//using (var engine = new TesseractEngine(@"./tessdata", "chi_sim", EngineMode.Default))
{
using(var pix = PixConverter.ToPix(bmp))
{
using (var page = engine.Process(pix))
{
return page.GetText();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
```
</details>
3. 0.08 版本添加开机启动
- 2023-12-28 0.10 添加明暗主题切换功能
![previews](./example_tray.png)
- 2022-12-27 0.08 版本添加开机启动
## 接口失效
## 如果接口失效
若远端接口均失效,需要自己本地运行翻译服务(感谢[zu1k](https://github.com/zu1k)),根据自己的系统 [下载可执行文件](https://github.com/zu1k/removed-2022-07-12/releases/tag/0.1.2) 自己的版本,软件右上角选择 `local` 接口即可
当请求人数较多时,远端接口可能暂时失效,可自行运行翻译接口程序
1. **【推荐】** 下载对应平台可 [执行文件](https://github.com/ZGGSONG/STranslate/releases/tag/0.01),随后在软件右上角选择 `local` 接口即可
2. 【进阶】 下载 [docker镜像](https://hub.docker.com/r/zggsong/translate),关闭软件 - cmd 运行 `start %localappdata%\stranslate\stranslate.json` - 修改接口地址 - 重启软件即可
## 参考项目
[https://github.com/NPCDW/WpfTool](https://github.com/NPCDW/WpfTool)
[https://github.com/zu1k/removed-2022-07-12/releases/tag/0.1.2](https://github.com/zu1k/removed-2022-07-12/releases/tag/0.1.2)
[https://github.com/Planshit/Tai](https://github.com/Planshit/Tai)

@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STranslate", "STranslate\STranslate.csproj", "{2597B480-185C-4D6D-94EC-8641BB6777F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Updater", "Updater\Updater.csproj", "{A49C9514-81CA-4FB6-A586-17477E4F28A8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{2597B480-185C-4D6D-94EC-8641BB6777F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2597B480-185C-4D6D-94EC-8641BB6777F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2597B480-185C-4D6D-94EC-8641BB6777F5}.Release|Any CPU.Build.0 = Release|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A49C9514-81CA-4FB6-A586-17477E4F28A8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -18,6 +18,8 @@ namespace STranslate
if (mutex.WaitOne(0, false))
{
base.OnStartup(e);
Util.Util.FlushMemory();
}
else
{

@ -0,0 +1,2 @@
@echo off
rd /s /q "%localappdata%\stranslate"

@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace STranslate.Helper
{
public class ConfigHelper
public class ConfigHelper : Singleton<ConfigHelper>
{
public T ReadConfig<T>()
{
@ -34,6 +34,7 @@ namespace STranslate.Helper
if (!Directory.Exists(_ApplicationData))//判断是否存在
{
Directory.CreateDirectory(_ApplicationData);//创建新路径
ShortcutHelper.SetDesktopShortcut();//创建桌面快捷方式
}
if (!File.Exists(_CnfName))//文件不存在
{
@ -53,7 +54,5 @@ namespace STranslate.Helper
/// </summary>
private static string _ApplicationData => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\{_AppName}";
private static readonly string _AppName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
private static ConfigHelper _Instance;
public static ConfigHelper Instance { get => _Instance ?? (_Instance = new ConfigHelper()); }
}
}

@ -9,7 +9,8 @@ namespace STranslate.Helper
public static String Get()
{
SendCtrlC();
Thread.Sleep(200);
System.Diagnostics.Debug.Print(STranslate.ViewModel.SettingsVM.Instance.WordPickupInterval.ToString());
Thread.Sleep((int)STranslate.ViewModel.SettingsVM.Instance.WordPickupInterval);
return NativeMethodHelper.GetText();
}

@ -2,45 +2,11 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Interop;
using WpfScreenHelper;
using static STranslate.Helper.NativeMethodHelper;
namespace STranslate.Helper
{
public static class Hotkeys
{
public static class InputTranslate
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 65;
public static String Text = "A";
public static bool Conflict = false;
}
public static class CrosswordTranslate
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 68;
public static String Text = "D";
public static bool Conflict = false;
}
#if true
public static class ScreenShotTranslate
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 83;
public static String Text = "S";
public static bool Conflict = false;
}
#endif
public static class OpenMainWindow
{
public static byte Modifiers = (byte)KeyModifiers.MOD_ALT;
public static int Key = 71;
public static String Text = "G";
public static bool Conflict = false;
}
}
internal class HotkeysHelper
{
@ -81,6 +47,19 @@ namespace STranslate.Helper
{
keymap[id] = callBack;
}
/// <summary>
/// 屏幕分辨率以及文本显示比例变更对应的消息标志
/// </summary>
private const int WmDisplayChange = 0x007e;
/// <summary>
/// 文本显示比例变更消息标志
/// </summary>
private const int WmTextChange = 0x02E0;
/// <summary>
/// window消息定义的 注册的热键消息标志
/// </summary>
private const int WmHotkeys = 0x0312;
/// <summary>
/// 快捷键消息处理
/// </summary>
@ -88,7 +67,7 @@ namespace STranslate.Helper
{
switch (msg)
{
case 0x0312: //这个是window消息定义的 注册的热键消息
case WmHotkeys:
int id = wParam.ToInt32();
if (keymap.TryGetValue(id, out var callback))
{
@ -107,31 +86,31 @@ namespace STranslate.Helper
{
HotkeysHelper.mainFormHandle = mainFormHandle;
InputTranslateModifiers = Hotkeys.InputTranslate.Modifiers;
InputTranslateKey = Hotkeys.InputTranslate.Key;
CrosswordTranslateModifiers = Hotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = Hotkeys.CrosswordTranslate.Key;
InputTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers;
InputTranslateKey = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key;
CrosswordTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key;
#if true
ScreenShotTranslateModifiers = Hotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = Hotkeys.ScreenShotTranslate.Key;
if (Hotkeys.ScreenShotTranslate.Key != 0)
ScreenShotTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key;
if (ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key != 0)
{
Hotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, Hotkeys.ScreenShotTranslate.Modifiers, Hotkeys.ScreenShotTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key);
}
#endif
if (Hotkeys.InputTranslate.Key != 0)
if (ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key != 0)
{
Hotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, Hotkeys.InputTranslate.Modifiers, Hotkeys.InputTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key);
}
if (Hotkeys.CrosswordTranslate.Key != 0)
if (ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key != 0)
{
Hotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, Hotkeys.CrosswordTranslate.Modifiers, Hotkeys.CrosswordTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key);
}
if (Hotkeys.OpenMainWindow.Key != 0)
if (ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key != 0)
{
Hotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, Hotkeys.OpenMainWindow.Modifiers, Hotkeys.OpenMainWindow.Key);
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key);
}
}
@ -153,59 +132,59 @@ namespace STranslate.Helper
/// </summary>
public static void ReRegisterHotKey()
{
if (Hotkeys.InputTranslate.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key == 0)
{
UnregisterHotKey(mainFormHandle, InputTranslateId);
}
else if (InputTranslateModifiers != Hotkeys.InputTranslate.Modifiers || InputTranslateKey != Hotkeys.InputTranslate.Key)
else if (InputTranslateModifiers != ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers || InputTranslateKey != ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key)
{
{
UnregisterHotKey(mainFormHandle, InputTranslateId);
Hotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, Hotkeys.InputTranslate.Modifiers, Hotkeys.InputTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, InputTranslateId, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key);
}
}
InputTranslateModifiers = Hotkeys.InputTranslate.Modifiers;
InputTranslateKey = Hotkeys.InputTranslate.Key;
InputTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers;
InputTranslateKey = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key;
if (Hotkeys.CrosswordTranslate.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key == 0)
{
UnregisterHotKey(mainFormHandle, CrosswordTranslateId);
}
else if (CrosswordTranslateModifiers != Hotkeys.CrosswordTranslate.Modifiers || CrosswordTranslateKey != Hotkeys.CrosswordTranslate.Key)
else if (CrosswordTranslateModifiers != ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers || CrosswordTranslateKey != ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key)
{
{
UnregisterHotKey(mainFormHandle, CrosswordTranslateId);
Hotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, Hotkeys.CrosswordTranslate.Modifiers, Hotkeys.CrosswordTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, CrosswordTranslateId, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key);
}
}
CrosswordTranslateModifiers = Hotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = Hotkeys.CrosswordTranslate.Key;
CrosswordTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers;
CrosswordTranslateKey = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key;
#if true
if (Hotkeys.ScreenShotTranslate.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key == 0)
{
UnregisterHotKey(mainFormHandle, ScreenShotTranslateId);
}
else if (ScreenShotTranslateModifiers != Hotkeys.ScreenShotTranslate.Modifiers || ScreenShotTranslateKey != Hotkeys.ScreenShotTranslate.Key)
else if (ScreenShotTranslateModifiers != ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers || ScreenShotTranslateKey != ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key)
{
UnregisterHotKey(mainFormHandle, ScreenShotTranslateId);
Hotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, Hotkeys.ScreenShotTranslate.Modifiers, Hotkeys.ScreenShotTranslate.Key);
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, ScreenShotTranslateId, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers, ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key);
}
ScreenShotTranslateModifiers = Hotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = Hotkeys.ScreenShotTranslate.Key;
ScreenShotTranslateModifiers = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers;
ScreenShotTranslateKey = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key;
#endif
if (Hotkeys.OpenMainWindow.Key == 0)
if (ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key == 0)
{
UnregisterHotKey(mainFormHandle, OpenMainWindowId);
}
else if (OpenMainWindowModifiers != Hotkeys.OpenMainWindow.Modifiers || OpenMainWindowKey != Hotkeys.OpenMainWindow.Key)
else if (OpenMainWindowModifiers != ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers || OpenMainWindowKey != ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key)
{
UnregisterHotKey(mainFormHandle, OpenMainWindowId);
Hotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, Hotkeys.OpenMainWindow.Modifiers, Hotkeys.OpenMainWindow.Key);
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict = !NativeMethodHelper.RegisterHotKey(mainFormHandle, OpenMainWindowId, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers, ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key);
}
OpenMainWindowModifiers = Hotkeys.OpenMainWindow.Modifiers;
OpenMainWindowKey = Hotkeys.OpenMainWindow.Key;
OpenMainWindowModifiers = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers;
OpenMainWindowKey = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key;
}
}
}

@ -5,6 +5,18 @@ using System.Runtime.CompilerServices;
namespace STranslate.Helper
{
/// <summary>
/// Generate Singleton
/// </summary>
/// <typeparam name="T"></typeparam>
public class Singleton<T> where T : class
{
private static readonly Lazy<T> _instance = new Lazy<T>(()
=> Activator.CreateInstance(typeof(T), true) as T, true);
public static T Instance => _instance.Value;
}
/// <summary>
/// 通知
/// </summary>

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Helper
{
public class ProcessHelper
{
public static bool Run(string filename, string[] args)
{
try
{
string arguments = "";
foreach (string arg in args)
{
arguments += $"\"{arg}\" ";
}
arguments = arguments.Trim();
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(filename, arguments);
process.StartInfo = startInfo;
process.Start();
return true;
}
catch (Exception)
{
//Logger.Error(ex.ToString());
return false;
}
}
}
}

@ -6,7 +6,7 @@ using IWshRuntimeLibrary;
namespace STranslate.Helper
{
public class StartupHelper
public class ShortcutHelper
{
#region public method
@ -32,6 +32,13 @@ namespace STranslate.Helper
{
ShortCutDelete(appPath, StartUpPath);
}
/// <summary>
/// 设置桌面快捷方式
/// </summary>
public static void SetDesktopShortcut()
{
ShortCutCreate(true);
}
#endregion
#region params
@ -40,6 +47,11 @@ namespace STranslate.Helper
/// </summary>
private static readonly string StartUpPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
/// <summary>
/// 用户桌面目录
/// </summary>
private static readonly string DesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
/// <summary>
/// 当前程序二进制文件路径
/// </summary>
@ -49,6 +61,8 @@ namespace STranslate.Helper
/// 组合的开机启动目录中的快捷方式路径
/// </summary>
private static readonly string appShortcutPath = Path.Combine(StartUpPath, Path.GetFileNameWithoutExtension(appPath) + ".lnk");
private static readonly string desktopShortcutPath = Path.Combine(DesktopPath, Path.GetFileNameWithoutExtension(appPath) + ".lnk");
#endregion
#region native method
@ -136,18 +150,25 @@ namespace STranslate.Helper
return Result;
}
/// <summary>
/// 为本程序创建一个开机启动快捷方式
/// 为本程序创建一个快捷方式
/// </summary>
private static bool ShortCutCreate()
/// <param name="isDesktop">是否为桌面快捷方式</param>
/// <returns></returns>
private static bool ShortCutCreate(bool isDesktop = false)
{
bool Result = false;
try
{
ShortCutDelete(appPath, StartUpPath);
if (!isDesktop)
ShortCutDelete(appPath, StartUpPath);
var shellType = Type.GetTypeFromProgID("WScript.Shell");
dynamic shell = Activator.CreateInstance(shellType);
var shortcut = shell.CreateShortcut(appShortcutPath);
IWshShortcut shortcut;
if (!isDesktop)
shortcut = shell.CreateShortcut(appShortcutPath);
else
shortcut = shell.CreateShortcut(desktopShortcutPath);
shortcut.TargetPath = Assembly.GetEntryAssembly().Location;
shortcut.Arguments = string.Empty;
shortcut.WorkingDirectory = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

@ -0,0 +1,98 @@
using SQLite;
using STranslate.Model;
using STranslate.ViewModel;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace STranslate.Helper
{
//https://github.com/praeclarum/sqlite-net
public class SqliteHelper : IDisposable
{
public SqliteHelper()
{
_sqlDB = new SQLiteConnection(_dbName);
_sqlDB.CreateTable<SqliteModel>();
}
public void Insert(DateTime time, string source, string target, LanguageEnum sourceLang, LanguageEnum targetLang, string api)
{
try
{
var model = new SqliteModel
{
Time = time,
SourceText = source,
TargetText = target,
SourceLang = sourceLang.ToString(),
TargetLang = targetLang.ToString(),
Api = api,
};
//查询最大数量
var count = _sqlDB.Table<SqliteModel>().Count();
if (count >= SettingsVM.Instance.MaxHistoryCount)
{
_sqlDB.Execute("delete from histories where id in (select id from histories limit (?))"
, count + 1 - SettingsVM.Instance.MaxHistoryCount);
}
//手动切换目标语言强制插入替换
_sqlDB.Table<SqliteModel>()
.Where(x => x.SourceText.Equals(model.SourceText))
.ToList().ForEach(x =>
{
_sqlDB.Delete(x);
});
_sqlDB.Insert(model);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show($"本地记录插入错误\n{ex.Message}");
}
}
/// <summary>
/// 查询记录
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string Query(string str)
{
var query = _sqlDB.Table<SqliteModel>().Where(x => x.SourceText.Equals(str));
if (query.Count() <= 0)
{
return string.Empty;
}
else//如果超过一个删除多余的
{
var tmp = query.ToList();
for (int i = 1; i < tmp.Count; i++)
{
_sqlDB.Delete(tmp[i]);
}
return query.First().TargetText;
}
}
public void Dispose()
{
_sqlDB.Close();
}
private readonly SQLiteConnection _sqlDB;
/// <summary>
/// 数据文件
/// </summary>
private static string _dbName => $"{_ApplicationData}\\{_AppName.ToLower()}.db";
/// <summary>
/// C:\Users\user\AppData\Local\STranslate
/// </summary>
private static string _ApplicationData => $"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\\{_AppName}";
private static readonly string _AppName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
}
}

Binary file not shown.

@ -7,8 +7,102 @@ using System.Threading.Tasks;
namespace STranslate.Model
{
public class Hotkeys
{
[JsonProperty("inputTranslate")]
public InputTranslate InputTranslate { get; set; }
[JsonProperty("crosswordTranslate")]
public CrosswordTranslate CrosswordTranslate { get; set; }
[JsonProperty("screenShotTranslate")]
public ScreenShotTranslate ScreenShotTranslate { get; set; }
[JsonProperty("openMainWindow")]
public OpenMainWindow OpenMainWindow { get; set; }
}
public class InputTranslate
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class CrosswordTranslate
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class ScreenShotTranslate
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class OpenMainWindow
{
public byte Modifiers { get; set; }
public int Key { get; set; }
public String Text { get; set; }
public bool Conflict { get; set; }
}
public class Server
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("api")]
public string Api { get; set; }
}
public class ConfigModel
{
/// <summary>
/// 最大历史记录数量
/// </summary>
[JsonProperty("maxHistoryCount")]
public int MaxHistoryCount { get; set; }
/// <summary>
/// 自动识别语种标度
/// </summary>
[JsonProperty("autoScale")]
public double AutoScale { get; set; }
/// <summary>
/// 取词间隔
/// </summary>
[JsonProperty("wordPickupInterval")]
public double WordPickupInterval { get; set; }
/// <summary>
/// 是否亮色模式
/// </summary>
[JsonProperty("isBright")]
public bool IsBright { get; set; }
[JsonProperty("sourceLanguage")]
public string SourceLanguage { get; set; }
[JsonProperty("targetLanguage")]
public string TargetLanguage { get; set; }
[JsonProperty("selectServer")]
public int SelectServer { get; set; }
/// <summary>
/// 服务
/// </summary>
[JsonProperty("servers")]
public Server[] Servers { get; set; }
/// <summary>
/// 热键
/// </summary>
[JsonProperty("hotkeys")]
public Hotkeys Hotkeys { get; set; }
public ConfigModel()
{
}
@ -17,6 +111,9 @@ namespace STranslate.Model
{
return new ConfigModel
{
MaxHistoryCount = 100,
AutoScale = 0.8,
WordPickupInterval = 200,
IsBright = true,
SourceLanguage = LanguageEnum.AUTO.GetDescription(),
TargetLanguage = LanguageEnum.AUTO.GetDescription(),
@ -26,7 +123,7 @@ namespace STranslate.Model
new Server
{
Name = "zggsong",
Api = "https://zggsong.cn/tt"
Api = "https://dfree.deno.dev/translate"
},
new Server
{
@ -38,39 +135,39 @@ namespace STranslate.Model
Name = "local",
Api = "http://127.0.0.1:8000/translate"
}
},
Hotkeys = new Hotkeys
{
InputTranslate = new InputTranslate
{
Modifiers = 1,
Key = 65,
Text = "Alt + A",
Conflict = false,
},
CrosswordTranslate = new CrosswordTranslate
{
Modifiers = 1,
Key = 68,
Text = "Alt + D",
Conflict = false,
},
ScreenShotTranslate = new ScreenShotTranslate
{
Modifiers = 1,
Key = 83,
Text = "Alt + S",
Conflict = false,
},
OpenMainWindow = new OpenMainWindow
{
Modifiers = 1,
Key = 71,
Text = "Alt + G",
Conflict = false,
},
}
};
}
/// <summary>
/// 是否亮色模式
/// </summary>
[JsonProperty("isBright")]
public bool IsBright { get; set; }
[JsonProperty("sourceLanguage")]
public string SourceLanguage { get; set; }
[JsonProperty("targetLanguage")]
public string TargetLanguage { get; set; }
[JsonProperty("selectServer")]
public int SelectServer { get; set; }
/// <summary>
/// 服务
/// </summary>
[JsonProperty("servers")]
public Server[] Servers { get; set; }
}
public class Server
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("api")]
public string Api { get; set; }
}
}

@ -0,0 +1,38 @@
using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace STranslate.Model
{
[Table("Histories")]
public class SqliteModel
{
[PrimaryKey, AutoIncrement]
[Column("id")]
public int Id { get; set; }
[Column("time")]
public DateTime Time { get; set; }
[Column("source_lang")]
public string SourceLang { get; set; }
[Column("target_lang")]
public string TargetLang { get; set; }
[Column("source_text")]
public string SourceText { get; set; }
[Column("target_text")]
public string TargetText { get; set; }
[Column("api")]
public string Api { get; set; }
[Column("remark")]
public string Remark { get; set; }
}
}

@ -0,0 +1,20 @@
using System;
using System.Windows.Data;
namespace STranslate.Model
{
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double w = System.Convert.ToDouble(value);
return w + 30;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

@ -47,6 +47,6 @@ using System.Windows;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.1.4.0")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyVersion("0.2.6.0")]
[assembly: AssemblyFileVersion("0.2.6.0")]
[assembly: Guid("CE252DD8-179F-4544-9989-453F5DEA378D")]

@ -19,7 +19,7 @@ namespace STranslate.Properties {
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {

@ -53,18 +53,43 @@
<ApplicationIcon>Images\translate.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Hardcodet.NotifyIcon.Wpf, Version=1.1.0.0, Culture=neutral, PublicKeyToken=682384a853a08aad, processorArchitecture=MSIL">
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.1.0\lib\net472\Hardcodet.NotifyIcon.Wpf.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.39\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SQLite-net, Version=1.8.116.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\sqlite-net-pcl.1.8.116\lib\netstandard2.0\SQLite-net.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.4.976, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.bundle_green.2.0.4\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=2.0.4.976, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.core.2.0.4\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.4.976, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.bundle_green.2.0.4\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.4.976, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
<HintPath>..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Speech" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
@ -97,9 +122,13 @@
<Compile Include="Helper\HotkeysHelper.cs" />
<Compile Include="Helper\MvvmHelper.cs" />
<Compile Include="Helper\NativeMethodHelper.cs" />
<Compile Include="Helper\StartupHelper.cs" />
<Compile Include="Helper\Processhelper.cs" />
<Compile Include="Helper\SqliteHelper.cs" />
<Compile Include="Helper\ShortcutHelper.cs" />
<Compile Include="Model\ConfigModel.cs" />
<Compile Include="Model\SqliteModel.cs" />
<Compile Include="Model\VisibilityConverter.cs" />
<Compile Include="Model\WidthConverter.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@ -108,9 +137,13 @@
<Compile Include="Util\Util.cs" />
<Compile Include="ViewModel\MainVM.cs" />
<Compile Include="ViewModel\ScreenShotVM.cs" />
<Compile Include="ViewModel\SettingsVM.cs" />
<Compile Include="View\ScreenShotWindow.xaml.cs">
<DependentUpon>ScreenShotWindow.xaml</DependentUpon>
</Compile>
<Compile Include="View\SettingsWindow.xaml.cs">
<DependentUpon>SettingsWindow.xaml</DependentUpon>
</Compile>
<Page Include="View\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -159,6 +192,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="View\SettingsWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Model\BaiduModel.cs" />
@ -176,12 +213,15 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="tessdata\eng.traineddata">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Resource Include="Images\iconfont.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<Content Include="ClearCache.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="tessdata\eng.traineddata">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
@ -224,5 +264,7 @@
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tesseract.5.2.0\build\Tesseract.targets'))" />
<Error Condition="!Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
</Target>
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
</Project>

@ -19,7 +19,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe994;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -39,7 +39,7 @@
Padding="5"
HorizontalAlignment="Left"
Margin="8,5,0,0"
MaxHeight="30">
Height="30">
<TextBlock Style="{StaticResource IconStyle}"
FontSize="21"
VerticalAlignment="Center"
@ -69,7 +69,7 @@
FontSize="22"
VerticalAlignment="Center"
Text="&#xe9ba;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -92,7 +92,7 @@
FontSize="17"
VerticalAlignment="Center"
Text="&#xe610;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -114,7 +114,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe692;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -136,7 +136,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe600;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -158,7 +158,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe602;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -180,7 +180,7 @@
FontSize="18"
VerticalAlignment="Center"
Text="&#xe601;"
Foreground="WhiteSmoke"/>
Foreground="#abb2bf"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
@ -191,4 +191,17 @@
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--ToolTip-->
<ControlTemplate x:Key="ToolTipTemplate"
TargetType="ToolTip">
<Border CornerRadius="3"
BorderThickness="1"
BorderBrush="#393c43"
Background="#2e323a"
Padding="4">
<TextBlock Text="{TemplateBinding Name}"
Foreground="#abb2bf"/>
</Border>
</ControlTemplate>
</ResourceDictionary>

@ -1,36 +1,33 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--引入字体文件-->
<Style x:Key="IconStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/STranslate;component/Images/#iconfont"/>
</Style>
<!--Combox-->
<Style TargetType="{x:Type ComboBox}" x:Key="cmbstyle">
<Setter Property="Background" Value="#282c34"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<!--ComBoxItem-->
<Style TargetType="ComboBoxItem">
<Setter Property="MinHeight" Value="22"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Back"
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"></ContentPresenter>
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Back" Property="Background" Value="#47484c"></Setter>
<Setter TargetName="Back" Property="Background" Value="#47484c"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Back" Property="Background" Value="#47484c"></Setter>
<Setter TargetName="Back" Property="Background" Value="#47484c"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
@ -42,7 +39,8 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30" Background="{TemplateBinding Background}" >
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30"
Background="#282c34" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
@ -72,10 +70,10 @@
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#282c34"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#282c34"/>
</Trigger>
</Style.Triggers>
</Style>
@ -95,7 +93,7 @@
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{StaticResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{DynamicResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@ -150,9 +148,6 @@
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{TemplateBinding ActualWidth}"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="2" ShadowDepth="0" Opacity="0.5"/>
</Border.Effect>
<ScrollViewer Margin="4,6,4,6" MaxHeight="{TemplateBinding MaxDropDownHeight}" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<!-- StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True -->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="#282c34"/>
@ -160,11 +155,6 @@
</Border>
</Popup>
</Grid>
<Border.Effect>
<DropShadowEffect ShadowDepth="-1" Opacity="0.3" Color="#FF969696" BlurRadius="2"/>
</Border.Effect>
</Border>
</ControlTemplate>
</Setter.Value>

@ -21,11 +21,11 @@
<Style x:Key="TextBoxInputStyle"
TargetType="TextBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="BorderThickness" Value="0"/>
<!--光标颜色-->
<Setter Property="CaretBrush" Value="WhiteSmoke"/>
<Setter Property="CaretBrush" Value="#abb2bf"/>
<!--选区颜色-->
<Setter Property="SelectionBrush" Value="#404856"/>
<Setter Property="Margin" Value="10,10,5,35"/>
@ -47,13 +47,13 @@
</Style>
<Style x:Key="LanguageMarkTextBlockStyle"
TargetType="TextBlock">
<Setter Property="Foreground" Value="#eaeaea"/>
<Setter Property="Foreground" Value="#cecece"/>
</Style>
<Style x:Key="TextBoxOutputStyle"
TargetType="TextBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="IsReadOnly" Value="True"/>
@ -71,6 +71,6 @@
<Style x:Key="MidStyle"
TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="WhiteSmoke"/>
<Setter Property="Foreground" Value="#abb2bf"/>
</Style>
</ResourceDictionary>

@ -191,4 +191,16 @@
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!--ToolTip-->
<ControlTemplate x:Key="ToolTipTemplate"
TargetType="ToolTip">
<Border CornerRadius="3"
BorderThickness="1"
BorderBrush="#dfdfdf"
Background="#f6f6f6"
Padding="4">
<TextBlock Text="{TemplateBinding Name}"/>
</Border>
</ControlTemplate>
</ResourceDictionary>

@ -1,35 +1,31 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--引入字体文件-->
<Style x:Key="IconStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="/STranslate;component/Images/#iconfont"/>
</Style>
<!--Combox-->
<Style TargetType="{x:Type ComboBox}" x:Key="cmbstyle">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<!--ComBoxItem-->
<Style TargetType="ComboBoxItem">
<Setter Property="MinHeight" Value="22"></Setter>
<Setter Property="MinWidth" Value="40"></Setter>
<Setter Property="MinHeight" Value="22"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Back"
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"></ContentPresenter>
CornerRadius="2"
Background="Transparent"
BorderThickness="0">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Back" Property="Background" Value="#eaeaea"></Setter>
<Setter TargetName="Back" Property="Background" Value="#eaeaea"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Back" Property="Background" Value="#eaeaea"></Setter>
<Setter TargetName="Back" Property="Background" Value="#eaeaea"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
@ -41,7 +37,8 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30" Background="{TemplateBinding Background}" >
<Border BorderThickness="0" CornerRadius="5" Width="80" Height="30"
Background="#f6f6f6" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
@ -59,7 +56,7 @@
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
<ToggleButton.Style >
<Style TargetType="ToggleButton">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
@ -71,10 +68,10 @@
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
</Trigger>
</Style.Triggers>
</Style>
@ -88,13 +85,13 @@
ClickMode="Press">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Background" Value="White"/>
<Setter Property="Background" Value="#f6f6f6"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{StaticResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock Foreground="{TemplateBinding Foreground}" x:Name="arrow_tb" Text="&#xe61d;" Style="{DynamicResource IconStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
@ -149,21 +146,13 @@
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{TemplateBinding ActualWidth}"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect Color="Black" BlurRadius="2" ShadowDepth="0" Opacity="0.5"/>
</Border.Effect>
<ScrollViewer Margin="4,6,4,6" MaxHeight="{TemplateBinding MaxDropDownHeight}" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<!-- StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True -->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="White"/>
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="#f6f6f6"/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
<Border.Effect>
<DropShadowEffect ShadowDepth="-1" Opacity="0.3" Color="#FF969696" BlurRadius="2"/>
</Border.Effect>
</Border>
</ControlTemplate>
</Setter.Value>

@ -1,10 +1,12 @@
using Newtonsoft.Json;
using IWshRuntimeLibrary;
using Newtonsoft.Json;
using STranslate.Model;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@ -295,5 +297,30 @@ namespace STranslate.Util
}
}
#endregion
#region Shortcut
public static void CreateShortcut()
{
string deskTop = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop);
string dirPath = System.Environment.CurrentDirectory;
string exePath = Assembly.GetExecutingAssembly().Location;
System.Diagnostics.FileVersionInfo exeInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(exePath);
if (System.IO.File.Exists(string.Format(@"{0}\STranslate.lnk", deskTop)))
{
System.IO.File.Delete(string.Format(@"{0}\STranslate.lnk",deskTop));//删除原来的桌面快捷键方式
return;
}
WshShell shell = new WshShell();
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\" + "STranslate.lnk");
shortcut.TargetPath = @exePath; //目标文件
shortcut.WorkingDirectory = dirPath; //目标文件夹
shortcut.WindowStyle = 1; //目标应用程序的窗口状态分为普通、最大化、最小化【1,3,7】
shortcut.Description = "自动更新程序"; //描述
shortcut.IconLocation = string.Format(@"{0}\64.ico", dirPath); //快捷方式图标
shortcut.Arguments = "";
shortcut.Hotkey = "SHIFT+DELETE"; // 快捷键
shortcut.Save();
}
#endregion
}
}

@ -3,10 +3,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:model="clr-namespace:STranslate.Model"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:vm="clr-namespace:STranslate.ViewModel"
xmlns:local="clr-namespace:STranslate.View"
mc:Ignorable="d"
x:Name="Mwin"
Background="Transparent"
@ -18,24 +16,10 @@
WindowStyle="None"
SizeToContent="Height"
Width="400"
FontFamily="{DynamicResource {x:Static SystemFonts.CaptionFontFamilyKey}}"
Icon="/Images/translate.ico">
<Window.Resources>
<ContextMenu x:Key="TrayMenu">
<MenuItem Header="输入翻译"
Command="{Binding InputTranslateCmd}"/>
<MenuItem Header="截图翻译"
Command="{Binding ScreenShotTranslateCmd}"/>
<Separator />
<MenuItem Header="显示主界面"
Command="{Binding ShowMainWinCmd}"/>
<MenuItem Header="开机自启"
IsChecked="{Binding IsStartup}"
Command="{Binding StartupCmd}"/>
<Separator />
<MenuItem Header="退出"
Command="{Binding ExitCmd}"/>
</ContextMenu>
<model:WidthConverter x:Key="WidthConverter"/>
</Window.Resources>
<Window.InputBindings>
@ -44,7 +28,11 @@
Command="{Binding ExitCmd}"/>
<KeyBinding Modifiers="Ctrl+Shift"
Key="T"
Command="{Binding TopmostCmd}"/>
Command="{Binding TopmostCmd}"
CommandParameter="{Binding ElementName=TopmostBtn, Mode=OneWay}"/>
<KeyBinding Modifiers="Ctrl+Shift"
Key="R"
Command="{Binding ThemeConvertCmd}"/>
<KeyBinding Key="Esc"
Command="{Binding EscCmd}"
CommandParameter="{Binding ElementName=TopmostBtn, Mode=OneWay}"/>
@ -64,19 +52,11 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="5*" />
<RowDefinition Height="5*"/>
<RowDefinition Height="*" />
<RowDefinition Height="7*" />
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<!--tray-->
<tb:TaskbarIcon x:Name="myNotifyIcon"
Visibility="{Binding IsVisibility, Converter={StaticResource BooleanToVisibilityConverter}}"
ToolTipText="STranslate"
ContextMenu="{StaticResource TrayMenu}"
DoubleClickCommand="{Binding InputTranslateCmd}"
IconSource="/Images/translate.ico"/>
<!--header-->
<Grid x:Name="Header">
<Button x:Name="TopmostBtn"
@ -95,7 +75,13 @@
ItemsSource="{Binding TranslationInterface}"
SelectedItem="{Binding SelectedTranslationInterface, Mode=TwoWay, NotifyOnSourceUpdated=True}"
DisplayMemberPath="Name"
HorizontalAlignment="Right"/>
HorizontalAlignment="Right">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectLangChangedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</Grid>
<!--input-->
@ -120,8 +106,13 @@
Visibility="{Binding InputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding SourceSpeakCmd}"/>
<Button Template="{DynamicResource ButtonTemplate}"
Click="Copy_Click"
Visibility="{Binding InputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyInputCmd}"/>
Command="{Binding CopyInputCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制输入内容" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<Border Style="{DynamicResource LanguageMarkBorderStyle}"
Visibility="{Binding IdentifyLanguage, Converter={StaticResource String2VisibilityConverter}}">
<StackPanel Margin="5,2"
@ -137,6 +128,34 @@
</Border>
</Grid>
<!--toast-->
<Border x:Name="Toast"
CornerRadius="12"
Grid.Row="0"
Grid.RowSpan="2"
VerticalAlignment="Top"
Visibility="Visible"
Margin="0,-40"
Width="{Binding ElementName=toastTxt, Path=ActualWidth,Converter={StaticResource WidthConverter}}"
BorderBrush="Transparent"
Background="#65c248">
<WrapPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<TextBlock Text="&#xe632;"
FontSize="16"
Foreground="White"
Padding="5,10"
Style="{StaticResource IconStyle}"/>
<TextBlock x:Name="toastTxt"
Background="Transparent"
Foreground="#fff"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="0,5,10,5"
FontSize="16"/>
</WrapPanel>
</Border>
<!--mid-->
<StackPanel x:Name="MidArea"
Grid.Row="2"
@ -184,27 +203,48 @@
<StackPanel Orientation="Horizontal"
Margin="10,5"
VerticalAlignment="Bottom">
<!--语音-->
<Button Template="{DynamicResource ButtonTemplateSpeak}"
Visibility="{Binding OutputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding TargetSpeakCmd}"/>
Visibility="{Binding OutputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding TargetSpeakCmd}"/>
<!--普通复制-->
<Button Template="{DynamicResource ButtonTemplate}"
Visibility="{Binding OutputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyResultCmd}"/>
Click="Copy_Click"
Visibility="{Binding OutputTxt, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="直接复制结果" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<!--蛇形复制-->
<Button Margin="5,0"
Template="{DynamicResource ButtonTemplateSnakeCopy}"
Visibility="{Binding SnakeRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySnakeResultCmd}"/>
Click="Copy_Click"
Template="{DynamicResource ButtonTemplateSnakeCopy}"
Visibility="{Binding SnakeRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySnakeResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制为蛇形字符串" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<!--小驼峰复制-->
<Button Template="{DynamicResource ButtonTemplateSmallHumpCopy}"
Visibility="{Binding SmallHumpRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySmallHumpResultCmd}"/>
Click="Copy_Click"
Visibility="{Binding SmallHumpRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopySmallHumpResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制为小驼峰字符串" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
<!--大驼峰复制-->
<Button Margin="5,0"
Template="{DynamicResource ButtonTemplateLargeHumpCopy}"
Visibility="{Binding LargeHumpRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyLargeHumpResultCmd}"/>
Click="Copy_Click"
Template="{DynamicResource ButtonTemplateLargeHumpCopy}"
Visibility="{Binding LargeHumpRet, Converter={StaticResource String2VisibilityConverter}}"
Command="{Binding CopyLargeHumpResultCmd}">
<Button.ToolTip>
<ToolTip x:Name="复制为大驼峰字符串" Template="{DynamicResource ToolTipTemplate}"/>
</Button.ToolTip>
</Button>
</StackPanel>
</Grid>
</Border>

@ -1,8 +1,13 @@
using STranslate.Helper;
using STranslate.ViewModel;
using System;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Forms;
using System.Windows.Media.Animation;
using System.Windows.Media;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
namespace STranslate.View
{
@ -11,18 +16,19 @@ namespace STranslate.View
/// </summary>
public partial class MainWindow : Window
{
private MainVM vm = MainVM.Instance;
public MainWindow()
{
//InitializeComponent();
DataContext = vm;
vm.Mainwin = this;
//if (HotKeys.InputTranslate.Conflict || HotKeys.CrosswordTranslate.Conflict || HotKeys.ScreenShotTranslate.Conflict)
//{
// MessageBox.Show("全局快捷键有冲突...");
//}
InitialTray();
Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
}
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
InitIcon();
}
/// <summary>
@ -55,6 +61,142 @@ namespace STranslate.View
{
vm.OpenMainWin();
});
if (ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict
|| ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict
|| ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict
|| ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict)
{
MessageBox.Show("全局快捷键有冲突,请前往软件首选项中修改...");
}
}
private void Copy_Click(object sender, RoutedEventArgs e)
{
var o = sender as System.Windows.Controls.Button;
toastTxt.Text = (o.ToolTip as System.Windows.Controls.ToolTip).Name;
//创建一个一个对象,对两个值在时间线上进行动画处理(移动距离,移动到的位置)
var da = new DoubleAnimation();
//设定动画时间线
da.Duration = new Duration(TimeSpan.FromSeconds(0.8));
//设定移动动画的结束值控件向下移动60个像素向上移动则是-60
da.To = 50;
da.From = 0;
da.AccelerationRatio = 0.2;
da.DecelerationRatio = 0.8;
da.AutoReverse = true;
//btnFlash要进行动画操作的控件名
Toast.RenderTransform = new TranslateTransform();
//开始进行动画处理
Toast.RenderTransform.BeginAnimation(TranslateTransform.YProperty, da);
}
private MainVM vm = MainVM.Instance;
public readonly NotifyIcon NotifyIcon = new NotifyIcon();
#region Initial TrayIcon
private void InitIcon()
{
var stream = Application
.GetResourceStream(new Uri("Images/translate.ico", UriKind.Relative))?.Stream;
if (NotifyIcon.Icon != null)
{
NotifyIcon.Icon.Dispose();
}
if (stream != null)
{
NotifyIcon.Icon = new System.Drawing.Icon(stream);
}
}
private void InitialTray()
{
var app = Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly()?.Location);
NotifyIcon.Text = $@"{app} {SettingsVM.Instance.Version}";
InitIcon();
NotifyIcon.Visible = true;
NotifyIcon.BalloonTipText = $@"{app} already started...";
NotifyIcon.ShowBalloonTip(500);
NotifyIcon.MouseDoubleClick += InputTranslateMenuItem_Click;
var inputTranslateMenuItemBtn = new MenuItem("输入翻译");
inputTranslateMenuItemBtn.Click += InputTranslateMenuItem_Click;
var screenshotTranslateMenuItemBtn = new MenuItem("截图翻译");
screenshotTranslateMenuItemBtn.Click += ScreenshotTranslateMenuItem_Click;
var crossWordTranslateMenuItemBtn = new MenuItem("划词翻译");
//CrossWordTranslateMenuItemBTN.Click += CrossWordTranslateMenuItem_Click;
//当失去焦点后无法从托盘处获取选中文本
crossWordTranslateMenuItemBtn.Enabled = false;
var openMainWinBtn = new MenuItem("显示主界面");
openMainWinBtn.Click += OpenMainWin_Click;
var preferenceBtn = new MenuItem("首选项");
preferenceBtn.Click += Preference_Click;
var exitBtn = new MenuItem("退出");
exitBtn.Click += Exit_Click;
var items = new MenuItem[] {
inputTranslateMenuItemBtn,
screenshotTranslateMenuItemBtn,
crossWordTranslateMenuItemBtn,
openMainWinBtn,
preferenceBtn,
exitBtn,
};
NotifyIcon.ContextMenu = new ContextMenu(items);
}
/// <summary>
/// 设置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Preference_Click(object sender, EventArgs e)
{
SettingsWindow window = null;
foreach (Window item in Application.Current.Windows)
{
if (item is SettingsWindow)
{
window = (SettingsWindow)item;
window.WindowState = WindowState.Normal;
window.Activate();
break;
}
}
if (window == null)
{
window = new SettingsWindow();
window.Show();
window.Activate();
}
}
private void ScreenshotTranslateMenuItem_Click(object sender, EventArgs e)
{
vm.ScreenShotTranslate();
}
private void OpenMainWin_Click(object sender, EventArgs e)
{
vm.OpenMainWin();
}
private void Exit_Click(object sender, EventArgs e)
{
vm.ExitApp(0);
}
private void InputTranslateMenuItem_Click(object sender, EventArgs e)
{
vm.InputTranslate();
}
#endregion
}
}

@ -0,0 +1,383 @@
<Window x:Name="window" x:Class="STranslate.View.SettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:STranslate.View"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
Loaded="window_Loaded"
WindowStartupLocation="CenterScreen"
Icon="/Images/translate.ico"
Title="STranslate 首选项" Height="450" Width="450">
<Window.Resources>
<ControlTemplate x:Key="buttonstyle"
TargetType="Button">
<Border x:Name="border"
CornerRadius="5"
Padding="5"
Background="#dedfde"
MaxHeight="25">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="#c6e6fc"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="border" Property="Background" Value="#cce6f6"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Window.InputBindings>
<KeyBinding Key="Esc"
Command="{Binding EscCmd}"
CommandParameter="{Binding ElementName=window, Mode=OneWay}"/>
</Window.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closed">
<i:InvokeCommandAction Command="{Binding ClosedCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid Margin="20">
<TabControl>
<TabItem Header="常规"
Padding="10,2">
<StackPanel Margin="20">
<GroupBox Header="开机启动">
<WrapPanel Margin="0,5,0,5">
<CheckBox Content="开机启动"
IsChecked="{Binding IsStartup}"
FontWeight="Bold">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding StartupCmd}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding StartupCmd}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</WrapPanel>
</GroupBox>
<GroupBox Header="语种识别(zh-en)"
ToolTip="根据英文字符占所有字符比例判断中英文">
<WrapPanel Margin="0,5,0,5">
<Slider Value="{Binding DataContext.AutoScale, ElementName=window}"
Minimum="0.01"
Maximum="0.99"
MinWidth="200"
TickFrequency="0.01"
TickPlacement="None"
IsSnapToTickEnabled="True">
</Slider>
<TextBlock Text="{Binding AutoScale, StringFormat={}{0}}" Margin="10,0,0,0" />
</WrapPanel>
</GroupBox>
<GroupBox Header="历史记录数量"
ToolTip="记录记录至本地数据库,以便省去重复查询的时间,调整最大历史记录数量">
<WrapPanel Margin="0,5,0,5">
<Slider Value="{Binding DataContext.MaxHistoryCount, ElementName=window}"
Minimum="1"
Maximum="1000"
MinWidth="200"
TickFrequency="10"
TickPlacement="None"
IsSnapToTickEnabled="True">
</Slider>
<TextBlock Text="{Binding MaxHistoryCount, StringFormat={}{0}条}" Margin="10,0,0,0" />
</WrapPanel>
</GroupBox>
<GroupBox Header="取词间隔"
ToolTip="划词翻译实现原理是用户用鼠标划词后模拟Ctrl+C间隔一定时间后程序再从剪切板取词如果电脑反应慢可能会出现取不到词的问题将间隔调大可以适配一些老旧的机器">
<WrapPanel Margin="0,5,0,5">
<Slider Value="{Binding DataContext.WordPickupInterval, ElementName=window}"
Minimum="100"
Maximum="1000"
MinWidth="200"
TickFrequency="100"
TickPlacement="None"
IsSnapToTickEnabled="True">
</Slider>
<TextBlock Text="{Binding WordPickupInterval, StringFormat={}{0}ms}" Margin="10,0,0,0" />
</WrapPanel>
</GroupBox>
</StackPanel>
</TabItem>
<TabItem Header="控制"
Padding="10,2">
<StackPanel Margin="20">
<GroupBox Header="快捷键">
<Grid Margin="20,10,20,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="划词翻译"
VerticalAlignment="Center"
Grid.Row="1"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="CrossWordTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="1"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="CrossWord_KeyUp"/>
<Label x:Name="CrossWordHotKeyConflictLabel"
Grid.Row="1"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red" />
<Label Content="截图翻译"
VerticalAlignment="Center"
Grid.Row="2"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="ScreenshotTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="2"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="Screenshot_KeyUp"/>
<Label x:Name="ScreenshotHotKeyConflictLabel"
Grid.Row="2"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red" />
<Label Content="输入翻译"
VerticalAlignment="Center"
Grid.Row="3"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="InputTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="3"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="Input_KeyUp"/>
<Label x:Name="InputHotKeyConflictLabel"
Grid.Row="3"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red"/>
<Label Content="显示界面"
VerticalAlignment="Center"
Grid.Row="4"
Grid.Column="0"
Margin="0,5,0,0" />
<TextBox x:Name="ShowMainwinTextBox"
Cursor="Arrow"
Width="200"
Grid.Row="4"
Grid.Column="1"
Margin="0,5,0,0"
CaretBrush="Transparent"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
PreviewKeyDown="HotKeyTextBox_PreviewKeyDown"
KeyUp="ShowMainwin_KeyUp"/>
<Label x:Name="ShowMainwinHotKeyConflictLabel"
Grid.Row="4"
Grid.Column="2"
Margin="0,5,0,0"
Content="热键冲突"
VerticalAlignment="Center"
Visibility="Hidden"
Foreground="Red" />
<Button Content="恢复默认"
Template="{StaticResource buttonstyle}"
Width="80"
Grid.Row="5"
Margin="5"
Grid.Column="1"
Click="ResetHoskeys_Click"/>
</Grid>
</GroupBox>
</StackPanel>
</TabItem>
<TabItem Header="服务"
Visibility="Collapsed"
Padding="10,2">
<GroupBox Header="DeepL API">
</GroupBox>
</TabItem>
<TabItem Header="关于"
Padding="10,2">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="20">
<WrapPanel Orientation="Horizontal">
<Image Source="/Images/translate.ico" Width="30"/>
<TextBlock VerticalAlignment="Bottom"
FontSize="18"
Margin="5,0">
<Run Text="STranslate"
FontWeight="Bold"/>
</TextBlock>
<!--<Border BorderBrush="Transparent"
Background="Black"
Margin="20,0,0,0"
Height="20"
CornerRadius="4">
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Right"
Foreground="WhiteSmoke"
Padding="5,0"
Text="Built with WPF"/>
</Border>-->
</WrapPanel>
<WrapPanel Margin="0,10,0,0">
<Label Content="版本"/>
<Label x:Name="Label_Version"
DataContext="https://github.com/zggsong/stranslate/releases"
Cursor="Hand"
Content="{Binding DataContext.Version, ElementName=window}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Version, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
<Button Content="检查更新"
Margin="40,0"
Template="{StaticResource buttonstyle}"
Command="{Binding UpdateCmd}">
</Button>
</WrapPanel>
<WrapPanel>
<Label Content="开源"/>
<Label x:Name="Label_Lic"
Content="MIT License"
DataContext="https://github.com/ZGGSONG/STranslate/blob/main/LICENSE"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Lic, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="版权"/>
<Label x:Name="Label_Ccopyright"
Content="@2022 ZGGSONG"
DataContext="https://github.com/ZGGSONG"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Ccopyright, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="联系"/>
<Label x:Name="Label_Connect"
Content="zggsong@foxmail.com"
DataContext="zggsong@foxmail.com"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Connect, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="源码"/>
<Label x:Name="Label_Source" Content="https://github.com/zggsong/stranslate"
DataContext="https://github.com/ZGGSONG/STranslate"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Source, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
<WrapPanel>
<Label Content="反馈"/>
<Label x:Name="Label_Feedback" Content="https://github.com/zggsong/stranslate/issues"
DataContext="https://github.com/ZGGSONG/STranslate/issues"
Cursor="Hand">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.OpenUrlCmd, ElementName=window}"
CommandParameter="{Binding ElementName=Label_Feedback, Path=DataContext}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</Window>

@ -0,0 +1,187 @@
using STranslate.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace STranslate.View
{
/// <summary>
/// SettingsWindow.xaml 的交互逻辑
/// </summary>
public partial class SettingsWindow : Window
{
public SettingsWindow()
{
InitializeComponent();
#if DEBUG
this.window.Topmost = true;
#endif
DataContext = ViewModel.SettingsVM.Instance;
}
private void window_Loaded(object sender, RoutedEventArgs e)
{
this.InputTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Text;
this.CrossWordTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Text;
this.ScreenshotTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Text;
this.ShowMainwinTextBox.Text = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Text;
HotKeyConflictCheck();
}
private byte _hotkeysModifiers;
private int _hotkeysKey;
private string _hotkeysText = string.Empty;
private void HotKeyTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
_hotkeysModifiers = 0;
_hotkeysKey = 0;
_hotkeysText = "";
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
StringBuilder shortcutText = new StringBuilder();
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0)
{
_hotkeysModifiers += 2;
shortcutText.Append("Ctrl + ");
}
if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0)
{
_hotkeysModifiers += 4;
shortcutText.Append("Shift + ");
}
if ((Keyboard.Modifiers & ModifierKeys.Alt) != 0)
{
_hotkeysModifiers += 1;
shortcutText.Append("Alt + ");
}
if (_hotkeysModifiers == 0 && (key < Key.F1 || key > Key.F12))
{
_hotkeysKey = 0;
shortcutText.Clear();
((System.Windows.Controls.TextBox)sender).Text = _hotkeysText = "";
return;
}
_hotkeysKey = KeyInterop.VirtualKeyFromKey(key);
shortcutText.Append(key.ToString());
((System.Windows.Controls.TextBox)sender).Text = _hotkeysText = shortcutText.ToString();
}
private void CrossWord_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void Input_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void Screenshot_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void ShowMainwin_KeyUp(object sender, KeyEventArgs e)
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin)
{
return;
}
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers = _hotkeysModifiers;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key = _hotkeysKey;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Text = _hotkeysText.ToString();
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void ResetHoskeys_Click(object sender, RoutedEventArgs e)
{
CrossWordTextBox.Text = "Alt + D";
InputTextBox.Text = "Alt + A";
ScreenshotTextBox.Text = "Alt + S";
ShowMainwinTextBox.Text = "Alt + G";
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Key = 68;
ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Text = "Alt + D";
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Key = 65;
ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Text = "Alt + A";
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Key = 83;
ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Text = "Alt + S";
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Modifiers = 1;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Key = 71;
ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Text = "Alt + G";
HotkeysHelper.ReRegisterHotKey();
HotKeyConflictCheck();
}
private void HotKeyConflictCheck()
{
this.CrossWordHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.CrosswordTranslate.Conflict ? Visibility.Visible : Visibility.Hidden;
this.ScreenshotHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.ScreenShotTranslate.Conflict ? Visibility.Visible : Visibility.Hidden;
this.InputHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.InputTranslate.Conflict ? Visibility.Visible : Visibility.Hidden;
this.ShowMainwinHotKeyConflictLabel.Visibility = ViewModel.MainVM.Instance.NHotkeys.OpenMainWindow.Conflict ? Visibility.Visible : Visibility.Hidden;
}
}
}

@ -9,6 +9,7 @@ using System.Text.RegularExpressions;
using STranslate.View;
using STranslate.Model;
using STranslate.Helper;
using System.Windows.Controls;
namespace STranslate.ViewModel
{
@ -16,6 +17,7 @@ namespace STranslate.ViewModel
{
public MainVM()
{
#region Initial
if (!ReadConfig())
{
ExitApp(-1);
@ -23,55 +25,17 @@ namespace STranslate.ViewModel
InputCombo = LanguageEnumDict.Keys.ToList();
OutputCombo = LanguageEnumDict.Keys.ToList();
_sqlHelper = new SqliteHelper();
#endregion
#region 托盘程序
//运行前检查是否开机自启
IsStartup = StartupHelper.IsStartup();
//输入翻译
InputTranslateCmd = new RelayCommand((_) => true, (_) =>
{
InputTranslate();
});
//截图翻译
ScreenShotTranslateCmd = new RelayCommand((_) => true, (_) =>
{
ScreenShotTranslate();
});
//显示主界面
ShowMainWinCmd = new RelayCommand((_) => true, (_) =>
{
OpenMainWin();
});
//开机自启
StartupCmd = new RelayCommand((_) => true, (_) =>
{
if (StartupHelper.IsStartup()) StartupHelper.UnSetStartup();
else StartupHelper.SetStartup();
IsStartup = StartupHelper.IsStartup();
});
//退出App
ExitCmd = new RelayCommand((_) => true, (_) =>
{
ExitApp(0);
});
#region Common
//退出
ExitCmd = new RelayCommand((_) => true, (_) => ExitApp(0));
//置顶
TopmostCmd = new RelayCommand((_) => true, (o) =>
{
var button = o as System.Windows.Controls.Button;
if (IsTopmost)
{
button.SetResourceReference(System.Windows.Controls.Control.TemplateProperty, _UnTopmostTemplateName);
}
else
{
button.SetResourceReference(System.Windows.Controls.Control.TemplateProperty, _TopmostTemplateName);
}
((Button)o).SetResourceReference(Control.TemplateProperty,
IsTopmost ? UnTopmostTemplateName : TopmostTemplateName);
IsTopmost = !IsTopmost;
});
@ -81,8 +45,7 @@ namespace STranslate.ViewModel
//取消置顶
if (IsTopmost)
{
(o as System.Windows.Controls.Button)
.SetResourceReference(System.Windows.Controls.Control.TemplateProperty, _UnTopmostTemplateName);
((Button)o).SetResourceReference(Control.TemplateProperty, UnTopmostTemplateName);
IsTopmost = !IsTopmost;
}
Mainwin.Hide();
@ -91,16 +54,10 @@ namespace STranslate.ViewModel
//切换语言
SelectLangChangedCmd = new RelayCommand((_) => true, (_) =>
{
if (!string.IsNullOrEmpty(InputTxt))
{
IdentifyLanguage = string.Empty;
_ = Translate();
}
if (string.IsNullOrEmpty(InputTxt)) return;
IdentifyLanguage = string.Empty;
_ = Translate();
});
#endregion
#region Common
//移动
MouseLeftDownCmd = new RelayCommand((_) => true, (_) =>
{
@ -109,21 +66,21 @@ namespace STranslate.ViewModel
//失去焦点
DeactivatedCmd = new RelayCommand((_) => true, (_) =>
{
if (!IsTopmost)
{
Speech.SpeakAsyncCancelAll();
Mainwin.Hide();
}
if (IsTopmost) return;
_speech.SpeakAsyncCancelAll();
Mainwin.Hide();
Util.Util.FlushMemory();
});
//source speak
SourceSpeakCmd = new RelayCommand((_) => true, (_) =>
{
Speech.SpeakAsync(InputTxt);
_speech.SpeakAsync(InputTxt);
});
//target speak
TargetSpeakCmd = new RelayCommand((_) => true, (_) =>
{
Speech.SpeakAsync(OutputTxt);
_speech.SpeakAsync(OutputTxt);
});
//复制输入
CopyInputCmd = new RelayCommand((_) => true, (_) =>
@ -156,14 +113,11 @@ namespace STranslate.ViewModel
{
Application.Current.Resources.MergedDictionaries[0].Source =
Application.Current.Resources.MergedDictionaries[0].Source
.ToString() == _ThemeDark ? new Uri(_ThemeDefault) : new Uri(_ThemeDark);
.ToString() == ThemeDark ? new Uri(ThemeDefault) : new Uri(ThemeDark);
});
//翻译
TranslateCmd = new RelayCommand((_) =>
{
return string.IsNullOrEmpty(InputTxt) ? false : true;
}, async (_) =>
TranslateCmd = new RelayCommand((_) => !string.IsNullOrEmpty(InputTxt), async (_) =>
{
await Translate();
});
@ -182,7 +136,8 @@ namespace STranslate.ViewModel
SmallHumpRet = string.Empty;
LargeHumpRet = string.Empty;
IdentifyLanguage = string.Empty;
Util.Util.FlushMemory();
}
/// <summary>
/// 打开主窗口
@ -193,7 +148,7 @@ namespace STranslate.ViewModel
Mainwin.Activate();
//TODO: need to deal with this
//TextBoxInput.Focus();
(Mainwin.FindName("TextBoxInput") as System.Windows.Controls.TextBox).Focus();
((TextBox)Mainwin.FindName("TextBoxInput"))?.Focus();
}
/// <summary>
/// 输入翻译
@ -219,9 +174,23 @@ namespace STranslate.ViewModel
/// </summary>
public void ScreenShotTranslate()
{
var screen = new ScreenShotWindow();
screen.Show();
screen.Activate();
ScreenShotWindow window = null;
foreach (Window item in Application.Current.Windows)
{
if (item is ScreenShotWindow)
{
window = (ScreenShotWindow)item;
window.WindowState = WindowState.Normal;
window.Activate();
break;
}
}
if (window == null)
{
window = new ScreenShotWindow();
window.Show();
window.Activate();
}
}
/// <summary>
/// 截屏翻译Ex
@ -238,10 +207,13 @@ namespace STranslate.ViewModel
/// </summary>
public void ExitApp(int id)
{
//隐藏icon
IsVisibility = false;
Util.Util.FlushMemory();
Mainwin.NotifyIcon.Dispose();
Mainwin.Close();
//关闭数据库
_sqlHelper.Dispose();
//语音合成销毁
Speech.Dispose();
_speech.Dispose();
//注销快捷键
HotkeysHelper.UnRegisterHotKey();
if (id == 0)
@ -260,20 +232,66 @@ namespace STranslate.ViewModel
{
try
{
_GlobalConfig = ConfigHelper.Instance.ReadConfig<ConfigModel>();
_globalConfig = ConfigHelper.Instance.ReadConfig<ConfigModel>();
#region 读取热键
NHotkeys = _globalConfig.Hotkeys ?? new Hotkeys
{
InputTranslate = new InputTranslate
{
Modifiers = 1,
Key = 65,
Text = "Alt + A",
Conflict = false,
},
CrosswordTranslate = new CrosswordTranslate
{
Modifiers = 1,
Key = 68,
Text = "Alt + D",
Conflict = false,
},
ScreenShotTranslate = new ScreenShotTranslate
{
Modifiers = 1,
Key = 83,
Text = "Alt + S",
Conflict = false,
},
OpenMainWindow = new OpenMainWindow
{
Modifiers = 1,
Key = 71,
Text = "Alt + G",
Conflict = false,
},
};
#endregion
//读取历史记录数量
var count = _globalConfig.MaxHistoryCount;
SettingsVM.Instance.MaxHistoryCount = (count <= 0 || count >= 1000) ? 100 : count;
//读取自动识别语种比例
var scale = _globalConfig.AutoScale;
SettingsVM.Instance.AutoScale = (scale <= 0 || scale >= 1) ? 0.8 : scale;
//读取间隔
var tmp = _globalConfig.WordPickupInterval;
SettingsVM.Instance.WordPickupInterval = (tmp == 0 || tmp > 1000 || tmp < 100) ? 200 : tmp;
//配置读取主题
Application.Current.Resources.MergedDictionaries[0].Source = _GlobalConfig.IsBright ? new Uri(_ThemeDefault) : new Uri(_ThemeDark);
Application.Current.Resources.MergedDictionaries[0].Source = _globalConfig.IsBright ? new Uri(ThemeDefault) : new Uri(ThemeDark);
//更新服务
TranslationInterface = _GlobalConfig.Servers.ToList();
TranslationInterface = _globalConfig.Servers.ToList();
if (TranslationInterface.Count < 1) throw new Exception("尚未配置任何翻译接口服务");
try
{
//配置读取接口
SelectedTranslationInterface = TranslationInterface[_GlobalConfig.SelectServer];
SelectedTranslationInterface = TranslationInterface[_globalConfig.SelectServer];
}
catch (Exception ex)
{
@ -281,8 +299,8 @@ namespace STranslate.ViewModel
}
//从配置读取source target
InputComboSelected = _GlobalConfig.SourceLanguage;
OutputComboSelected = _GlobalConfig.TargetLanguage;
InputComboSelected = _globalConfig.SourceLanguage;
OutputComboSelected = _globalConfig.TargetLanguage;
return true;
}
@ -298,11 +316,15 @@ namespace STranslate.ViewModel
{
ConfigHelper.Instance.WriteConfig(new ConfigModel
{
IsBright = Application.Current.Resources.MergedDictionaries[0].Source.ToString() == _ThemeDefault ? true : false,
MaxHistoryCount = SettingsVM.Instance.MaxHistoryCount,
AutoScale = SettingsVM.Instance.AutoScale,
WordPickupInterval = SettingsVM.Instance.WordPickupInterval,
IsBright = Application.Current.Resources.MergedDictionaries[0].Source.ToString() == ThemeDefault ? true : false,
SourceLanguage = InputComboSelected,
TargetLanguage = OutputComboSelected,
SelectServer = TranslationInterface.FindIndex(x => x == SelectedTranslationInterface),
Servers = _GlobalConfig.Servers,
Servers = _globalConfig.Servers,
Hotkeys = NHotkeys,
});
}
catch (Exception ex)
@ -332,9 +354,8 @@ namespace STranslate.ViewModel
var ratio = (double)engStr.Length / text.Length;
//3. 判断英文字符个数占第一步所有字符个数比例,若超过一半则判定原字符串为英文字符串,否则为中文字符串
//TODO: 配置项
if (ratio > 0.8)
//3. 判断英文字符个数占第一步所有字符个数比例,若超过一定比例则判定原字符串为英文字符串,否则为中文字符串
if (ratio > SettingsVM.Instance.AutoScale)
{
return new Tuple<string, string>(LanguageEnum.EN.GetDescription(), LanguageEnum.ZH.GetDescription());
}
@ -348,10 +369,12 @@ namespace STranslate.ViewModel
/// 翻译
/// </summary>
/// <returns></returns>
public async Task Translate()
private async Task Translate()
{
try
{
if (string.IsNullOrEmpty(InputTxt.Trim()))
throw new Exception("输入值为空!");
var isEng = string.Empty;
IdentifyLanguage = string.Empty;
OutputTxt = "翻译中...";
@ -363,24 +386,41 @@ namespace STranslate.ViewModel
//自动选择目标语言
if (OutputComboSelected == LanguageEnum.AUTO.GetDescription())
{
//只有在自动的模式下读取
var resp = _sqlHelper.Query(InputTxt);
if (!string.IsNullOrEmpty(resp))
{
OutputTxt = resp;
return;
}
var autoRet = AutomaticLanguageRecognition(InputTxt);
IdentifyLanguage = autoRet.Item1;
isEng = autoRet.Item2;
translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[autoRet.Item2], LanguageEnumDict[InputComboSelected]);
_translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[autoRet.Item2], LanguageEnumDict[InputComboSelected]);
}
else
{
translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[OutputComboSelected], LanguageEnumDict[InputComboSelected]);
_translateResp = await Util.Util.TranslateDeepLAsync(SelectedTranslationInterface.Api, InputTxt, LanguageEnumDict[OutputComboSelected], LanguageEnumDict[InputComboSelected]);
}
//百度 Api
//var translateResp = await TranslateUtil.TranslateBaiduAsync(config.baidu.appid, config.baidu.secretKey, InputTxt, LanguageEnumDict[OutputComboSelected], LanguageEnumDict[InputComboSelected]);
if (translateResp == string.Empty)
if (_translateResp == string.Empty)
{
OutputTxt = "翻译出错,请稍候再试...";
return;
}
OutputTxt = translateResp;
OutputTxt = _translateResp;
await Task.Run(() =>
{
_sqlHelper.Insert(DateTime.Now,
InputTxt,
OutputTxt,
LanguageEnumDict[string.IsNullOrEmpty(IdentifyLanguage) ? InputComboSelected : IdentifyLanguage],
LanguageEnumDict[string.IsNullOrEmpty(isEng) ? OutputComboSelected : isEng],
SelectedTranslationInterface.Api);
});
//如果目标语言不是英文则不进行转换
//1. 自动判断语种Tuple item2 不为 EN
@ -411,112 +451,99 @@ namespace STranslate.ViewModel
#endregion handle
#region Params
private string translateResp;
public ICommand MouseLeftDownCmd { get; private set; }
public ICommand DeactivatedCmd { get; private set; }
public ICommand SourceSpeakCmd { get; private set; }
public ICommand TargetSpeakCmd { get; private set; }
public ICommand TranslateCmd { get; private set; }
public ICommand CopyInputCmd { get; private set; }
public ICommand CopyResultCmd { get; private set; }
public ICommand CopySnakeResultCmd { get; private set; }
public ICommand CopySmallHumpResultCmd { get; private set; }
public ICommand CopyLargeHumpResultCmd { get; private set; }
public ICommand ThemeConvertCmd { get; private set; }
//托盘程序
public ICommand InputTranslateCmd { get; private set; }
public ICommand ScreenShotTranslateCmd { get; private set; }
public ICommand ShowMainWinCmd { get; private set; }
public ICommand StartupCmd { get; private set; }
public ICommand ExitCmd { get; private set; }
public ICommand TopmostCmd { get; private set; }
public ICommand EscCmd { get; private set; }
public ICommand SelectLangChangedCmd { get; private set; }
/// <summary>
/// 是否开机自启
/// </summary>
private bool _IsStartup;
public bool IsStartup { get => _IsStartup; set => UpdateProperty(ref _IsStartup, value); }
/// <summary>
/// 托盘图标可见
/// </summary>
private bool _IsVisibility = true;
public bool IsVisibility { get => _IsVisibility; set => UpdateProperty(ref _IsVisibility, value); }
private readonly SqliteHelper _sqlHelper;
private string _translateResp;
public ICommand MouseLeftDownCmd { get; set; }
public ICommand DeactivatedCmd { get; set; }
public ICommand SourceSpeakCmd { get; set; }
public ICommand TargetSpeakCmd { get; set; }
public ICommand TranslateCmd { get; set; }
public ICommand CopyInputCmd { get; set; }
public ICommand CopyResultCmd { get; set; }
public ICommand CopySnakeResultCmd { get; set; }
public ICommand CopySmallHumpResultCmd { get; set; }
public ICommand CopyLargeHumpResultCmd { get; set; }
public ICommand ThemeConvertCmd { get; set; }
public ICommand TopmostCmd { get; set; }
public ICommand EscCmd { get; set; }
public ICommand ExitCmd { get; set; }
public ICommand SelectLangChangedCmd { get; set; }
/// <summary>
/// view传递至viewmodel
/// </summary>
public MainWindow Mainwin;
private static MainVM _Instance;
public static MainVM Instance => _Instance ?? (_Instance = new MainVM());
private static Lazy<MainVM> _instance = new Lazy<MainVM>(() => new MainVM());
public static MainVM Instance => _instance.Value;
public bool IsTopmost { get; set; }
private readonly string _TopmostTemplateName = "ButtonTemplateTopmost";
private readonly string _UnTopmostTemplateName = "ButtonTemplateUnTopmost";
public Hotkeys NHotkeys;
private bool IsTopmost { get; set; }
private const string TopmostTemplateName = "ButtonTemplateTopmost";
private const string UnTopmostTemplateName = "ButtonTemplateUnTopmost";
/// <summary>
/// 全局配置文件
/// </summary>
private ConfigModel _GlobalConfig;
private ConfigModel _globalConfig;
/// <summary>
/// 识别语种
/// </summary>
private string _IdentifyLanguage;
public string IdentifyLanguage { get => _IdentifyLanguage; set => UpdateProperty(ref _IdentifyLanguage, value); }
private string _identifyLanguage;
public string IdentifyLanguage { get => _identifyLanguage; set => UpdateProperty(ref _identifyLanguage, value); }
/// <summary>
/// 构造蛇形结果
/// </summary>
private string _SnakeRet;
public string SnakeRet { get => _SnakeRet; set => UpdateProperty(ref _SnakeRet, value); }
private string _snakeRet;
public string SnakeRet { get => _snakeRet; set => UpdateProperty(ref _snakeRet, value); }
/// <summary>
/// 构造驼峰结果
/// </summary>
private string _SmallHumpRet;
public string SmallHumpRet { get => _SmallHumpRet; set => UpdateProperty(ref _SmallHumpRet, value); }
private string _smallHumpRet;
public string SmallHumpRet { get => _smallHumpRet; set => UpdateProperty(ref _smallHumpRet, value); }
/// <summary>
/// 构造驼峰结果
/// </summary>
private string _LargeHumpRet;
public string LargeHumpRet { get => _LargeHumpRet; set => UpdateProperty(ref _LargeHumpRet, value); }
private string _largeHumpRet;
public string LargeHumpRet { get => _largeHumpRet; set => UpdateProperty(ref _largeHumpRet, value); }
private string _InputTxt;
public string InputTxt { get => _InputTxt; set => UpdateProperty(ref _InputTxt, value); }
private string _inputTxt;
public string InputTxt { get => _inputTxt; set => UpdateProperty(ref _inputTxt, value); }
private string _OutputTxt;
public string OutputTxt { get => _OutputTxt; set => UpdateProperty(ref _OutputTxt, value); }
private string _outputTxt;
public string OutputTxt { get => _outputTxt; set => UpdateProperty(ref _outputTxt, value); }
private List<string> _InputCombo;
public List<string> InputCombo { get => _InputCombo; set => UpdateProperty(ref _InputCombo, value); }
private List<string> _inputCombo;
public List<string> InputCombo { get => _inputCombo; set => UpdateProperty(ref _inputCombo, value); }
private string _InputComboSelected;
public string InputComboSelected { get => _InputComboSelected; set => UpdateProperty(ref _InputComboSelected, value); }
private string _inputComboSelected;
public string InputComboSelected { get => _inputComboSelected; set => UpdateProperty(ref _inputComboSelected, value); }
private List<string> _OutputCombo;
public List<string> OutputCombo { get => _OutputCombo; set => UpdateProperty(ref _OutputCombo, value); }
private List<string> _outputCombo;
public List<string> OutputCombo { get => _outputCombo; set => UpdateProperty(ref _outputCombo, value); }
private string _OutputComboSelected;
public string OutputComboSelected { get => _OutputComboSelected; set => UpdateProperty(ref _OutputComboSelected, value); }
private string _outputComboSelected;
public string OutputComboSelected { get => _outputComboSelected; set => UpdateProperty(ref _outputComboSelected, value); }
/// <summary>
/// 目标接口
/// </summary>
private List<Server> _TranslationInterface;
public List<Server> TranslationInterface { get => _TranslationInterface; set => UpdateProperty(ref _TranslationInterface, value); }
private List<Server> _translationInterface;
public List<Server> TranslationInterface { get => _translationInterface; set => UpdateProperty(ref _translationInterface, value); }
private Server _SelectedTranslationInterface;
public Server SelectedTranslationInterface { get => _SelectedTranslationInterface; set => UpdateProperty(ref _SelectedTranslationInterface, value); }
private Server _selectedTranslationInterface;
public Server SelectedTranslationInterface { get => _selectedTranslationInterface; set => UpdateProperty(ref _selectedTranslationInterface, value); }
private static Dictionary<string, LanguageEnum> LanguageEnumDict { get => Util.Util.GetEnumList<LanguageEnum>(); }
/// <summary>
/// 语音
/// </summary>
public readonly SpeechSynthesizer Speech = new SpeechSynthesizer();
private readonly SpeechSynthesizer _speech = new SpeechSynthesizer();
private const string ThemeDark = "pack://application:,,,/STranslate;component/Style/Dark.xaml";
private const string ThemeDefault = "pack://application:,,,/STranslate;component/Style/Default.xaml";
private static readonly string _ThemeDark = "pack://application:,,,/STranslate;component/Style/Dark.xaml";
private static readonly string _ThemeDefault = "pack://application:,,,/STranslate;component/Style/Default.xaml";
#endregion Params
}
}

@ -0,0 +1,147 @@
using STranslate.Helper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace STranslate.ViewModel
{
public class SettingsVM : BaseVM
{
public SettingsVM()
{
IsStartup = ShortcutHelper.IsStartup();
Version = HandleVersion(System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() ?? "1.0.0.0");
ClosedCmd = new RelayCommand((_) => true, (_) =>
{
Util.Util.FlushMemory();
});
//更新
UpdateCmd = new RelayCommand((_) => true, (_) =>
{
try
{
var updaterExePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
"Updater.exe");
var updaterCacheExePath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Updater",
"Updater.exe");
var updateDirPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Updater");
if (!Directory.Exists(updateDirPath))
{
Directory.CreateDirectory(updateDirPath);
}
if (!File.Exists(updaterExePath))
{
MessageBox.Show("升级程序似乎已被删除,请手动前往发布页查看新版本");
return;
}
File.Copy(updaterExePath, updaterCacheExePath, true);
File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Newtonsoft.Json.dll"), Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Updater",
"Newtonsoft.Json.dll"), true);
ProcessHelper.Run(updaterCacheExePath, new string[] { Version });
}
catch (Exception ex)
{
MessageBox.Show($"无法正确启动检查更新程序\n{ex.Message}");
}
});
StartupCmd = new RelayCommand((_) => true, (_) =>
{
if (ShortcutHelper.IsStartup()) ShortcutHelper.UnSetStartup();
else ShortcutHelper.SetStartup();
IsStartup = ShortcutHelper.IsStartup();
});
EscCmd = new RelayCommand((_) => true, (o) =>
{
(o as Window)?.Close();
});
OpenUrlCmd = new RelayCommand((_) => true, (o) =>
{
try
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = o.ToString();
proc.Start();
}
catch (Exception ex)
{
MessageBox.Show($"未找到默认应用\n{ex.Message}");
}
});
}
/// <summary>
/// 同步Github版本命名
/// </summary>
/// <param name="version"></param>
/// <returns></returns>
private static string HandleVersion(string version)
{
var ret = string.Empty;
ret = version.Substring(0, version.Length - 2);
var location = ret.LastIndexOf('.');
ret = ret.Remove(location, 1);
return ret;
}
public ICommand ClosedCmd { get; private set; }
public ICommand OpenUrlCmd { get; private set; }
public ICommand UpdateCmd { get; private set; }
public ICommand StartupCmd { get; private set; }
public ICommand EscCmd { get; private set; }
private static Lazy<SettingsVM> _instance = new Lazy<SettingsVM>(() => new SettingsVM());
public static SettingsVM Instance => _instance.Value;
/// <summary>
/// 是否开机自启
/// </summary>
private bool _isStartup;
public bool IsStartup { get => _isStartup; set => UpdateProperty(ref _isStartup, value); }
/// <summary>
/// 版本
/// </summary>
private string _version;
public string Version { get => _version; set => UpdateProperty(ref _version, value); }
/// <summary>
/// 语种识别比例
/// </summary>
private double _autoScale;
public double AutoScale { get => _autoScale; set => UpdateProperty(ref _autoScale, value); }
/// <summary>
/// 取词间隔
/// </summary>
private double _wordPickupInterval;
public double WordPickupInterval { get => _wordPickupInterval; set => UpdateProperty(ref _wordPickupInterval, value); }
/// <summary>
/// 最大历史记录数量
/// </summary>
private int _maxHistoryCount;
public int MaxHistoryCount { get => _maxHistoryCount; set => UpdateProperty(ref _maxHistoryCount, value); }
}
}

@ -1,8 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Hardcodet.NotifyIcon.Wpf" version="1.1.0" targetFramework="net48" />
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.39" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net48" />
<package id="sqlite-net-pcl" version="1.8.116" targetFramework="net48" />
<package id="SQLitePCLRaw.bundle_green" version="2.0.4" targetFramework="net48" />
<package id="SQLitePCLRaw.core" version="2.0.4" targetFramework="net48" />
<package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.4" targetFramework="net48" />
<package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.4" targetFramework="net48" />
<package id="System.Buffers" version="4.4.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.3" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net48" />
<package id="Tesseract" version="5.2.0" targetFramework="net48" />
<package id="WpfScreenHelper" version="2.1.0" targetFramework="net48" />
</packages>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
</configuration>

@ -0,0 +1,9 @@
<Application x:Class="Updater.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Updater"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Updater
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
private System.Threading.Mutex mutex;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// 阻止多开和用户主动启动
if (e.Args.Length == 0 || IsRuned())
{
Shutdown();
}
Activated += (s, e2) =>
{
var mainWindow = App.Current.MainWindow;
if (mainWindow.DataContext != null)
{
var mainViewModel = mainWindow.DataContext as MainViewModel;
if (string.IsNullOrEmpty(mainViewModel.Version))
{
mainViewModel.Version = e.Args[0];
}
}
};
}
#region 获取当前程序是否已运行
/// <summary>
/// 获取当前程序是否已运行
/// </summary>
private bool IsRuned()
{
bool ret;
mutex = new System.Threading.Mutex(true, System.Reflection.Assembly.GetEntryAssembly().ManifestModule.Name, out ret);
if (!ret)
{
return true;
}
return false;
}
#endregion
}
}

@ -0,0 +1,111 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Updater
{
public class GithubRelease
{
public class VersionInfo
{
/// <summary>
/// 版本标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 版本号
/// </summary>
public string Version { get; set; }
/// <summary>
/// 是否是预览版本
/// </summary>
public bool IsPre { get; set; }
/// <summary>
/// 下载路径
/// </summary>
public string DownloadUrl { get; set; }
/// <summary>
/// 版本更新内容网页链接
/// </summary>
public string HtmlUrl { get; set; }
}
public class GithubModel
{
public string tag_name { get; set; }
public string html_url { get; set; }
public string name { get; set; }
public bool prerelease { get; set; }
public List<GithubAssetsModel> assets { get; set; }
}
public class GithubAssetsModel
{
public string browser_download_url { get; set; }
}
private string githubUrl;
private string nowVersion;
public VersionInfo Info { get; set; }
//public event UpdaterEventHandler RequestCompleteEvent;
//public event UpdaterEventHandler RequestErrorEvent;
//public delegate void UpdaterEventHandler(object sender, object value);
public GithubRelease(string githubUrl, string nowVersion)
{
this.githubUrl = githubUrl;
this.nowVersion = nowVersion;
Info = new VersionInfo();
}
public bool IsCanUpdate()
{
return !(nowVersion == Info.Version);
}
public async Task<VersionInfo> GetRequest()
{
var result = await Task.Run(() =>
{
HttpWebResponse httpWebRespones = null;
try
{
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
HttpWebRequest httpWebRequest = WebRequest.Create(githubUrl) as HttpWebRequest;
httpWebRequest.Timeout = 60 * 1000;
httpWebRequest.ReadWriteTimeout = 60000;
httpWebRequest.AllowAutoRedirect = true;
httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36";
httpWebRespones = (HttpWebResponse)httpWebRequest.GetResponse();
using (Stream stream = httpWebRespones.GetResponseStream())
{
List<byte> lst = new List<byte>();
int nRead = 0;
while ((nRead = stream.ReadByte()) != -1) lst.Add((byte)nRead);
byte[] bodyBytes = lst.ToArray();
string body = Encoding.UTF8.GetString(bodyBytes, 0, bodyBytes.Length);
var data = JsonConvert.DeserializeObject<GithubModel>(body);
Info.IsPre = data.prerelease;
Info.Title = data.name;
Info.Version = data.tag_name;
Info.DownloadUrl = data.assets[0].browser_download_url;
Info.HtmlUrl = data.html_url;
return Info;
}
}
catch (Exception)
{
return null;
}
});
return result;
}
}
}

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Updater
{
public class MainViewModel : INotifyPropertyChanged
{
private double _processValue;
public double ProcessValue { get => _processValue; set => UpdateProperty(ref _processValue, value); }
private string _version;
public string Version { get => _version; set => UpdateProperty(ref _version, value); }
#region notifychanged
public event PropertyChangedEventHandler PropertyChanged;
protected void UpdateProperty<T>(ref T properValue, T newValue, [CallerMemberName] string properName = "")
{
if (object.Equals(properValue, newValue))
return;
properValue = newValue;
NotifyPropertyChanged(properName);
}
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

@ -0,0 +1,57 @@
<Window x:Class="Updater.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Updater"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Icon="update.ico"
Title="STranslate 升级程序" ResizeMode="NoResize" Height="300" Width="420">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel>
<Border Background="#f3f3f3" Padding="10" CornerRadius="2">
<TextBlock x:Name="StatusLabel" Foreground="Gray" TextWrapping="WrapWithOverflow"/>
</Border>
<ProgressBar x:Name="ProgressBar" Height="10" Margin="0,10,0,10" Maximum="100"
Value="{Binding ProcessValue}"/>
<StackPanel x:Name="NewVersionSP" Margin="10">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">
<Run>版本号</Run>
<Run x:Name="Version" Foreground="Gray"/>
</TextBlock>
<Border x:Name="PreTag"
ToolTip="预览版表示开发者没有进行过多的测试相较于正式版可能会多一些bug但也并不是一定"
Background="OrangeRed"
Padding="5,2"
CornerRadius="4"
VerticalAlignment="Center"
Margin="10,0,0,0">
<TextBlock Text="预览版" Foreground="White" FontSize="10" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</StackPanel>
<TextBlock Margin="0,10,0,0" ToolTip="版本简介"><Run x:Name="VersionTitle" Foreground="Gray"/></TextBlock>
<TextBlock Margin="0,10,0,0" ToolTip="在浏览器中打开"><Hyperlink Click="Hyperlink_Click">查看详细更新内容</Hyperlink></TextBlock>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Left">
<Button x:Name="UpdateBtn" Padding="10,8" Margin="0,0,10,0" Click="UpdateBtn_Click">升级到此新版本</Button>
<Button x:Name="ReCheckBtn" Padding="10,8" Click="ReCheckBtn_Click">重新检查</Button>
</StackPanel>
<TextBlock Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Right">
<Run>当前版本号:</Run><Run Text="{Binding Version}"/>
</TextBlock>
</Grid>
</Window>

@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Updater
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
GithubRelease githubRelease;
/// <summary>
/// 新版本保存目录路径
/// </summary>
private string SaveDir = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory);
/// <summary>
/// 新版本保存名字
/// </summary>
private string SaveName = "update.zip";
/// <summary>
/// 新版本下载路径
/// </summary>
private string NewVersionZipURL;
/// <summary>
/// 新版本发布页路径
/// </summary>
private string NewVersionURL;
private MainViewModel _mainViewModel;
public MainWindow()
{
InitializeComponent();
_mainViewModel = new MainViewModel();
DataContext = _mainViewModel;
_mainViewModel.PropertyChanged += MainViewModel_PropertyChanged;
}
private void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(_mainViewModel.Version))
{
githubRelease = new GithubRelease("https://api.github.com/repos/zggsong/stranslate/releases/latest", _mainViewModel.Version);
Check();
}
}
private async void Download()
{
SetStatus("正在下载新版本文件...", false);
UpdateBtn.Visibility = Visibility.Collapsed;
ReCheckBtn.Visibility = Visibility.Collapsed;
ProgressBar.Visibility = Visibility.Visible;
_mainViewModel.ProcessValue = 0;
var res = await Task.Run(() =>
{
try
{
// 确认保存目录
if (!Directory.Exists(SaveDir))
{
Directory.CreateDirectory(SaveDir);
}
Uri uri = new Uri(NewVersionZipURL);
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.Timeout = 120 * 1000;
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
long totalBytes = httpWebResponse.ContentLength;
Stream st = httpWebResponse.GetResponseStream();
Stream so = new FileStream(System.IO.Path.Combine(SaveDir, SaveName), FileMode.Create);
long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte = osize + totalDownloadedByte;
so.Write(by, 0, osize);
osize = st.Read(by, 0, (int)by.Length);
//进度计算
double process = double.Parse(String.Format("{0:F}",
((double)totalDownloadedByte / (double)totalBytes * 100)));
_mainViewModel.ProcessValue = process;
//Debug.WriteLine(ProcessValue);
}
//关闭资源
httpWebResponse.Close();
so.Close();
st.Close();
return true;
}
catch (Exception)
{
return false;
}
});
if (res)
{
// 准备更新
var process = Process.GetProcessesByName("STranslate");
if (process != null && process.Length > 0)
{
process[0].Kill();
}
SetStatus("下载完成,正在解压请勿关闭此窗口...");
string unpath = Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).Parent.FullName;
var unresult = await Task.Run(async () =>
{
await Task.Delay(3000);
return Unzip.ExtractZipFile(System.IO.Path.Combine(SaveDir, SaveName), unpath);
});
if (unresult)
{
SetStatus("更新完成!", false);
Process p = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo(System.IO.Path.Combine(unpath, "STranslate.exe"));
p.StartInfo = startInfo;
p.Start();
}
else
{
SetStatus("解压文件时发生异常,请重试!通常情况可能是因为 STranslate 主程序尚未退出。", false);
UpdateBtn.Visibility = Visibility.Visible;
}
}
else
{
//下载发生异常
SetStatus("下载时发生异常,请重试。", false);
UpdateBtn.Visibility = Visibility.Visible;
}
}
private async void Check()
{
NewVersionSP.Visibility = Visibility.Collapsed;
PreTag.Visibility = Visibility.Collapsed;
SetStatus("正在检查更新");
UpdateBtn.Visibility = Visibility.Collapsed;
ReCheckBtn.IsEnabled = false;
var info = await githubRelease.GetRequest();
if (info != null)
{
if (githubRelease.IsCanUpdate())
{
UpdateBtn.Visibility = Visibility.Visible;
NewVersionSP.Visibility = Visibility.Visible;
Version.Text = info.Version;
VersionTitle.Text = info.Title;
NewVersionZipURL = info.DownloadUrl;
NewVersionURL = info.HtmlUrl;
if (info.IsPre)
{
PreTag.Visibility = Visibility.Visible;
}
SetStatus("检测到新的版本!", false);
}
else
{
SetStatus("目前没有可用的更新。", false);
}
}
else
{
SetStatus("无法获取版本信息,请检查代理或网络。", false);
}
ReCheckBtn.IsEnabled = true;
}
private void SetStatus(string statusText, bool isLoading = true)
{
StatusLabel.Text = statusText;
ProgressBar.IsIndeterminate = isLoading;
if (isLoading)
{
ProgressBar.Visibility = Visibility.Visible;
}
else
{
ProgressBar.Visibility = Visibility.Collapsed;
}
}
private void ReCheckBtn_Click(object sender, RoutedEventArgs e)
{
Check();
}
private void UpdateBtn_Click(object sender, RoutedEventArgs e)
{
Download();
}
private void Hyperlink_Click(object sender, RoutedEventArgs e)
{
Process.Start(new ProcessStartInfo(NewVersionURL));
}
}
}

@ -0,0 +1,56 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Updater")]
[assembly: AssemblyDescription("A ready to use and ready to go translation tool")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ZGGSONG")]
[assembly: AssemblyProduct("Updater")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("ZGGSONG")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Guid("54EA0FD9-3908-4A27-8AF7-B98EDCE7804E")]

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Updater.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Updater.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Updater.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

@ -0,0 +1,85 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
namespace Updater
{
public class Unzip
{
/// <summary>
/// 忽略的文件列表
/// </summary>
static readonly string[] IgnoreFiles = { };
public static bool ExtractZipFile(string zipPath, string extractPath)
{
try
{
if (!extractPath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
extractPath += Path.DirectorySeparatorChar;
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (!IsIgnoreFile(entry.FullName))
{
// Gets the full path to ensure that relative segments are removed.
string destinationPath = Path.GetFullPath(Path.Combine(extractPath, entry.FullName));
if (!IsDir(destinationPath))
{
// 判断路径是否存在
string dir = Path.GetDirectoryName(destinationPath);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (File.Exists(destinationPath))
{
File.Delete(destinationPath);
}
// Ordinal match is safest, case-sensitive volumes can be mounted within volumes that
// are case-insensitive.
Debug.WriteLine($"抽取:{destinationPath}");
if (destinationPath.StartsWith(extractPath, StringComparison.Ordinal))
entry.ExtractToFile(destinationPath);
}
else
{
//创建目录
Directory.CreateDirectory(destinationPath);
}
}
}
return true;
}
}
catch
{
return false;
}
}
/// <summary>
/// 指示文件是否是忽略的
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
static bool IsIgnoreFile(string fileName)
{
return (Array.IndexOf(IgnoreFiles, fileName) != -1);
}
/// <summary>
/// 指示路径是否是目录
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
static bool IsDir(string path)
{
return path.Last() == '\\';
}
}
}

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A49C9514-81CA-4FB6-A586-17477E4F28A8}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Updater</RootNamespace>
<AssemblyName>Updater</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>
    <!-- 阻止默认的 XML 和 PDB 文件复制到 RELEASE 的输出目录. 只有*.allowedextension 扩展名的文件可以被包含, 当然这个扩展的文件并不存在.-->
    .allowedextension
  </AllowedReferenceRelatedFileExtensions>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>update.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Unzip.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="GithubRelease.cs" />
<Compile Include="MainViewModel.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Resource Include="update.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net48" />
</packages>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Loading…
Cancel
Save