Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jobs:
codesign --verify --verbose=2 "$app"
codesign -dv --verbose=2 "$app" 2>&1 | grep -q '^Signature=' \
|| { echo "bundle is unsigned"; exit 1; }
tools/release/audit-macos-bundle.sh "$app"

- uses: tauri-apps/tauri-action@v0
env:
Expand All @@ -83,7 +84,9 @@ jobs:
```

On first run, grant Accessibility permission when prompted, then
add your own Google Cloud Translation API key in Settings.
choose Google, Baidu, or Microsoft Translator in Settings and add
that provider's credentials. Vocabulary Study includes an offline
English to Simplified Chinese starter textbook.

The app is ad-hoc signed, so its code identity changes with every
release. After installing an update, macOS drops the old grant:
Expand Down
48 changes: 32 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

</div>

<div align="center"><a href="README.zh-CN.md">简体中文</a> · English</div>

Highlight a word or a sentence in any application. When you release the mouse, a
small translate button appears beside the selection; click it and the
translation opens right there, without stealing focus from what you were
Expand Down Expand Up @@ -42,8 +44,11 @@ tab.
discovery, downloaded textbooks, and bidirectional practice.
- **Stays out of the way.** Lives in the menu bar with no Dock icon, and can
start at login.
- **Bring your own key.** Your Google Cloud Translation API key is stored in the
system Keychain and never reaches the interface layer.
- **English and Simplified Chinese UI.** Switch immediately from Settings or
the menu-bar menu, with CJK typography tuned for desktop reading.
- **Choose your translation service.** Google Cloud, Baidu Translate, and
Microsoft Translator (global or China cloud) share one provider-neutral
native boundary. Provider credentials stay in isolated system-vault slots.

Languages: English, Chinese (Simplified), Japanese, Korean, French, German and
Spanish, in any direction, plus automatic detection of the source.
Expand All @@ -62,7 +67,8 @@ The study window brings four tools together:
- **My wordbook** keeps the source and translation, language direction, lookup
demand, recall score, pronunciation controls, and provenance-backed
part-of-speech metadata. Entries can be corrected or removed.
- **Downloaded textbooks** provide five Simplified Chinese learning paths,
- **Downloaded textbooks** start with an embedded offline Simplified Chinese
starter and provide five additional learning paths,
including everyday, academic, TOEIC, business, and general-reference
vocabulary. A textbook hit is copied into your personal wordbook.
- **Related words** combines roots and shared meanings across your wordbook and
Expand Down Expand Up @@ -119,7 +125,9 @@ runs natively on both Apple Silicon and Intel Macs.

## Setup

Two things are needed before the first translation.
Two things are needed before the first online translation. Vocabulary Study is
usable immediately because its starter English → Simplified Chinese textbook is
embedded in the app.

**1. Grant Accessibility permission.** The app reads the selected text and its
on-screen position through the macOS Accessibility API. On first launch it will
Expand All @@ -139,17 +147,23 @@ already running, which is why the warning can remain after the switch is on.
> No screen capture is involved and no Screen Recording permission is requested.
> The app reads only the text you selected, only after you finish selecting it.

**2. Add a Google Cloud Translation API key.** Open Settings from the menu-bar
menu and choose *Save API Key*. You will need a key from Google Cloud with the
Cloud Translation API enabled and billing configured.
**2. Choose and configure a translation provider.** Open Settings from the
menu-bar menu, choose a service, and use its native credential prompt:

| Provider | Configuration | Network note |
| --- | --- | --- |
| Baidu Translate | APP ID + secret key | Recommended for users in mainland China |
| Microsoft Translator | Subscription key, cloud profile, optional region | China cloud requires an Azure China account |
| Google Cloud | Cloud Translation API key | Availability depends on the user's network |

> [!TIP]
> Restrict the key to the Cloud Translation API and set a quota or budget in
> Google Cloud. The key is yours and every request is billed to your account.
> Restrict each credential to translation, and set the provider's quota or
> budget. Requests use only the service currently selected in Settings; the app
> never silently falls back to another online provider.

The key is entered in a native secure prompt and stored in the macOS Keychain.
It never passes through the user interface layer, is never written to the
settings file, and is sent only in the `x-goog-api-key` header over HTTPS.
Credentials are entered in native secure prompts and stored in the macOS
Keychain. They never pass through the WebView and are never written to the
settings file.

## Usage

Expand All @@ -161,7 +175,7 @@ settings file, and is sent only in the `x-goog-api-key` header over HTTPS.
| Click the speaker icon | Speaks the text with a system voice |
| Click the menu-bar icon | Opens the quick translate panel for typed text |
| Open Vocabulary Study from the menu-bar menu | Reviews your wordbook, textbooks, connections, and practice queue |
| Menu-bar right-click | Settings, enable/disable, start at login, quit |
| Menu-bar right-click | Settings, UI language, enable/disable, start at login, quit |

Nothing is sent anywhere until you click the translate button. Selections in
password and other secure fields are ignored. Eligible words and short lexical
Expand Down Expand Up @@ -226,10 +240,12 @@ src-tauri/src/
docs/ Platform qualification and development notes
```

The renderer is never given the API key, never reads the selection itself, and
The renderer is never given provider credentials, never reads the selection itself, and
communicates only through a narrow set of validated commands.

## Acknowledgements

Built with [Tauri 2](https://tauri.app), React and Rust. Translation is provided
by the [Google Cloud Translation API](https://cloud.google.com/translate).
Built with [Tauri 2](https://tauri.app), React and Rust. Online translation
adapters support [Google Cloud](https://cloud.google.com/translate),
[Baidu Translate](https://fanyi-api.baidu.com/), and
[Microsoft Translator](https://learn.microsoft.com/azure/ai-services/translator/).
79 changes: 79 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<div align="center">

<img src="src-tauri/icons/icon.png" alt="桌面翻译" width="120" />

# 桌面翻译

**在桌面任意位置选中文字,就地完成翻译。**

[English](README.md) · 简体中文

</div>

桌面翻译是一款轻量的 macOS 菜单栏应用。你在邮件、PDF、终端或浏览器中选中文字后,
应用会在选区旁显示一个小按钮;只有点击按钮后,文本才会发送到你选择的翻译服务。

## 主要功能

- 划词翻译不会抢走当前应用的焦点,也支持菜单栏中的快速输入面板。
- 支持英文和简体中文界面,可从菜单栏或设置窗口即时切换。
- 支持 Google Cloud、百度翻译和微软翻译;微软可选择全球或中国区云环境。
- API 凭据通过原生安全输入框保存到系统钥匙串,不会进入 WebView 或设置文件。
- 原文和译文均可使用系统语音朗读。
- 自动建立本地个人词库,支持词性、发音、相关词、双向测试和记忆分数。
- 内置一册离线的英汉入门词书;无需下载、无需配置 API 即可开始学习。

![个人词库、记忆分数、词性和发音按钮](docs/screenshots/vocabulary-study-wordbook.png)

<table>
<tr>
<td width="50%"><img src="docs/screenshots/vocabulary-study-textbooks.png" alt="简体中文词书书架" /></td>
<td width="50%"><img src="docs/screenshots/vocabulary-study-related.png" alt="相关词与来源标记" /></td>
</tr>
</table>

翻译查询遵循固定顺序:**个人词库 → 当前词书 → 你选择的在线服务**。应用不会在后台
擅自切换在线服务。在线翻译失败时,会显示当前服务的错误,方便你检查网络、配额或凭据。

## 安装

从 [最新 Release](https://github.com/Ldsystem/desktop-translator/releases/latest) 下载 `.dmg`,
将应用拖入“应用程序”文件夹。安装包为通用版本,同时支持 Apple 芯片和 Intel Mac,
并已包含界面、数据库运行库和离线入门词书,不需要安装 Node.js、Python 或 SQLite。

当前 Release 使用 ad-hoc 签名,首次启动前需要执行:

```sh
xattr -dr com.apple.quarantine "/Applications/Desktop Translator.app"
```

## 初次设置

1. 在“系统设置 → 隐私与安全性 → 辅助功能”中允许桌面翻译,然后从菜单栏退出并重新打开。
2. 在设置中选择翻译服务:

| 服务 | 需要配置 | 说明 |
| --- | --- | --- |
| 百度翻译 | APP ID、密钥 | 推荐中国大陆用户优先尝试 |
| 微软翻译 | 订阅密钥、云环境,可选区域 | 中国区需要 Azure 中国账号 |
| Google Cloud | Cloud Translation API 密钥 | 可用性取决于本地网络 |

请在服务商后台限制 API 用途,并设置配额或预算。个人词库、练习结果和下载的词书都保存在
本机,不会同步到云端;句子式文本只会翻译,不会加入词库。

## 开发

需要 Node.js 20+、pnpm 10+ 和稳定版 Rust:

```sh
pnpm install
pnpm tauri dev
```

| 命令 | 用途 |
| --- | --- |
| `pnpm check` | TypeScript 检查、前端测试和构建 |
| `pnpm test:platform` | Rust 单元与集成测试 |
| `pnpm tauri build` | 生成自包含的 `.app` 和 `.dmg` |

详细的架构、平台支持和权限说明请参阅 [英文 README](README.md)。
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "desktop-translator",
"private": true,
"version": "0.2.0",
"version": "0.3.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
28 changes: 27 additions & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "desktop-translator"
version = "0.2.0"
version = "0.3.0"
description = "Lightweight cross-platform selection translator"
authors = ["Desktop Translator Contributors"]
edition = "2021"
Expand All @@ -16,13 +16,14 @@ tauri-build = { version = "2.6.3", features = [] }
async-trait = "0.1.92"
crossbeam-channel = "0.5.16"
html-escape = "0.2.15"
md5 = "0.8.0"
keyring = { version = "4.1.6", default-features = false, features = ["apple-native-keyring-store", "v1", "windows-native-keyring-store"] }
opencc-fmmseg = "0.11.3"
# `system-proxy` and `socks` are part of reqwest's defaults and must be kept
# explicitly: without them the client only honours HTTP_PROXY-style variables,
# which a GUI app launched from Finder never inherits. Users who reach Google
# only through a local proxy would see every request time out.
reqwest = { version = "0.13.4", default-features = false, features = ["json", "rustls", "socks", "system-proxy"] }
reqwest = { version = "0.13.4", default-features = false, features = ["form", "json", "rustls", "socks", "system-proxy"] }
rusqlite = { version = "0.38.0", features = ["bundled"] }
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
Expand All @@ -38,3 +39,10 @@ windows = { version = "0.62.2", features = ["Win32_Foundation", "Win32_Globaliza

[target.'cfg(target_os = "macos")'.dependencies]
apple-native-keyring-store = { version = "1.0.2", features = ["keychain"] }

[profile.release]
codegen-units = 1
lto = "thin"
opt-level = "s"
panic = "abort"
strip = "symbols"
Binary file not shown.
Loading
Loading