Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
11 changes: 6 additions & 5 deletions .where-agent-progress.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Plan: ProtoFlow English User Guide Sync
- [x] Align structure with Chinese guide (learn-first flow)
- [x] Rewrite docs/USER_GUIDE_EN.md with current software behavior
- [x] Verify feature status/commands against implementation
- [x] Finalize delivery notes
# Plan: 全链路 Logo 统一
- [x] 任务栏/安装器图标统一到指定 Logo(ico)
- [x] 桌面运行时应用图标链路统一(AppUserModelID + QApplication/窗口图标)
- [x] 前端侧边栏品牌图标替换为同款 Logo
- [x] 前端 favicon 替换为同款 Logo
- [x] 完成基础验证(py_compile + 前端组件测试)
53 changes: 51 additions & 2 deletions app/main_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
from pathlib import Path
from typing import Optional
import yaml
try:
from PySide6.QtGui import QIcon
except ImportError: # pragma: no cover
from PyQt6.QtGui import QIcon # type: ignore

try:
from PySide6.QtWidgets import QApplication
Expand All @@ -26,6 +30,8 @@
from infra.protocol.protocol_loader import ProtocolLoader
from ui.desktop.web_window import WebWindow

APP_USER_MODEL_ID = "ProtoFlow.Desktop.App"


class _TeeStream:
def __init__(self, primary, file_handle, is_error: bool) -> None:
Expand Down Expand Up @@ -106,6 +112,38 @@ def _ensure_repo_cwd() -> None:
pass


def _set_windows_app_id() -> None:
if sys.platform != "win32":
return
try:
import ctypes
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(APP_USER_MODEL_ID)
except Exception:
logging.getLogger("main_web").warning("Failed to set AppUserModelID", exc_info=True)


def _resolve_app_icon() -> Optional[Path]:
root_dir = Path(__file__).resolve().parents[1]
candidates = [
root_dir / "ui" / "assets" / "icons" / "logo.png",
root_dir / "ui" / "assets" / "icons" / "logo.svg",
root_dir / "installer" / "ProtoFlow.ico",
]
if getattr(sys, "frozen", False):
exe_dir = Path(sys.executable).resolve().parent
candidates = [
exe_dir / "ProtoFlow.ico",
exe_dir / "_internal" / "ProtoFlow.ico",
exe_dir / "ui" / "assets" / "icons" / "logo.png",
exe_dir / "ui" / "assets" / "icons" / "logo.svg",
*candidates,
]
for path in candidates:
if path.exists():
return path
return None


def _detect_d3d11() -> bool:
if sys.platform != "win32":
return False
Expand Down Expand Up @@ -195,21 +233,31 @@ def _proxy_monitor_enabled() -> bool:

def main() -> None:
_ensure_repo_cwd()
_set_windows_app_id()
_setup_run_logging()
flags = _select_webengine_flags()
if flags:
os.environ.setdefault("QTWEBENGINE_CHROMIUM_FLAGS", flags)
logging.getLogger("main_web").info(
"WebEngine flags: %s",
os.environ.get("QTWEBENGINE_CHROMIUM_FLAGS", "<default>"),
)
bus = EventBus()
comm = CommunicationManager(bus)
proxy_enabled = _proxy_monitor_enabled()
proxy_manager = ProxyForwardManager(bus) if proxy_enabled else None
logging.getLogger("main_web").info("Proxy monitor enabled: %s", proxy_enabled)
protocol = ProtocolLoader(bus)
packet_engine = PacketAnalysisEngine(bus)
plugins = PluginManager(bus, protocol=protocol)
plugins.load_all()
plugin_manager = PluginManager(bus, protocol=protocol)
plugin_manager.load_all()

app = QApplication.instance() or QApplication(sys.argv)
icon_path = _resolve_app_icon()
if icon_path is not None:
icon = QIcon(str(icon_path))
if not icon.isNull():
app.setWindowIcon(icon)
_shutdown_done = {"value": False}

def _shutdown_proxy() -> None:
Expand All @@ -228,6 +276,7 @@ def _shutdown_proxy() -> None:
window = WebWindow(
bus=bus,
comm=comm,
plugin_manager=plugin_manager,
proxy_manager=proxy_manager,
proxy_monitor_enabled=proxy_enabled,
)
Expand Down
16 changes: 16 additions & 0 deletions app/plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ def load(self, name: str) -> None:
def list_plugins(self) -> List[str]:
return list(self._plugins.keys())

def list_plugin_items(self) -> List[Dict[str, str]]:
items: List[Dict[str, str]] = []
for name in sorted(self._plugins.keys()):
items.append(
{
"id": name,
"name": name,
"status": "enabled",
}
)
return items

def refresh_all(self) -> None:
self._plugins.clear()
self.load_all()

def reload(self, name: str) -> None:
"""热更新插件。"""
module = self._plugins.get(name)
Expand Down
3 changes: 3 additions & 0 deletions docs/USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
- 能根据模板编写自己的脚本
- 能定位常见错误

相关文档:
- i18n 多语言说明书索引:[`docs/i18n-manual/README.md`](./i18n-manual/README.md)

## 1. 软件定位
ProtoFlow 是一个通信自动化工具,不只是“串口收发器”。
它把通信流程拆成可执行步骤(DSL),用于:
Expand Down
3 changes: 3 additions & 0 deletions docs/USER_GUIDE_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ By the end, you should be able to:
- write your own script from templates
- troubleshoot common errors

Related docs:
- i18n manual index: [`docs/i18n-manual/README.md`](./i18n-manual/README.md)

## 1. What ProtoFlow Is
ProtoFlow is a communication automation tool, not just a serial terminal.
It models communication as executable workflow steps (DSL), and is suitable for:
Expand Down
73 changes: 73 additions & 0 deletions docs/i18n-manual/I18N_MANUAL.ar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# ProtoFlow i18n Manual (ar)

Language Index: [zh-CN](I18N_MANUAL.zh-CN.md) | [en-US](I18N_MANUAL.en-US.md) | [zh-TW](I18N_MANUAL.zh-TW.md) | [ja-JP](I18N_MANUAL.ja-JP.md) | [ko-KR](I18N_MANUAL.ko-KR.md) | [fr-FR](I18N_MANUAL.fr-FR.md) | [de-DE](I18N_MANUAL.de-DE.md) | [es-ES](I18N_MANUAL.es-ES.md) | [pt-BR](I18N_MANUAL.pt-BR.md) | [ru-RU](I18N_MANUAL.ru-RU.md) | **ar** | [hi](I18N_MANUAL.hi.md) | [it-IT](I18N_MANUAL.it-IT.md) | [nl-NL](I18N_MANUAL.nl-NL.md) | [th-TH](I18N_MANUAL.th-TH.md) | [vi-VN](I18N_MANUAL.vi-VN.md) | [id-ID](I18N_MANUAL.id-ID.md) | [tr-TR](I18N_MANUAL.tr-TR.md) | [pl-PL](I18N_MANUAL.pl-PL.md) | [uk-UA](I18N_MANUAL.uk-UA.md)

Current Language: **Arabic**

## 1. Source of Truth

- Aggregator: `ui/frontend/src/i18n/index.ts`
- Locale dictionaries: `ui/frontend/src/i18n/locales/*.ts`
- Default locale: `zh-CN`

## 2. Locale Map

| Locale | Locale File |
|---|---|
| `zh-CN` | ui/frontend/src/i18n/locales/zhCN.ts |
| `en-US` | ui/frontend/src/i18n/locales/enUS.ts |
| `zh-TW` | ui/frontend/src/i18n/locales/zhTW.ts |
| `ja-JP` | ui/frontend/src/i18n/locales/jaJP.ts |
| `ko-KR` | ui/frontend/src/i18n/locales/koKR.ts |
| `fr-FR` | ui/frontend/src/i18n/locales/frFR.ts |
| `de-DE` | ui/frontend/src/i18n/locales/deDE.ts |
| `es-ES` | ui/frontend/src/i18n/locales/esES.ts |
| `pt-BR` | ui/frontend/src/i18n/locales/ptBR.ts |
| `ru-RU` | ui/frontend/src/i18n/locales/ruRU.ts |
| `ar` | ui/frontend/src/i18n/locales/ar.ts |
| `hi` | ui/frontend/src/i18n/locales/hi.ts |
| `it-IT` | ui/frontend/src/i18n/locales/itIT.ts |
| `nl-NL` | ui/frontend/src/i18n/locales/nlNL.ts |
| `th-TH` | ui/frontend/src/i18n/locales/thTH.ts |
| `vi-VN` | ui/frontend/src/i18n/locales/viVN.ts |
| `id-ID` | ui/frontend/src/i18n/locales/idID.ts |
| `tr-TR` | ui/frontend/src/i18n/locales/trTR.ts |
| `pl-PL` | ui/frontend/src/i18n/locales/plPL.ts |
| `uk-UA` | ui/frontend/src/i18n/locales/ukUA.ts |

## 3. Resolution Order

1. `translations[selectedLocale][key]`
2. `translations[DEFAULT_LANGUAGE][key]`
3. Inline fallback text passed to `t(key, fallback)`
4. Final fallback to the key string itself

## 4. Add or Update a Language

1. Create or update locale file in `ui/frontend/src/i18n/locales/`.
2. Export locale object and import it in `ui/frontend/src/i18n/index.ts`.
3. Add locale code to `translations` map.
4. Verify language switch in Settings page.
5. Run frontend build and smoke-check docs button text visibility.

## 5. Required Key Groups

- `nav.*`
- `header.*`
- `action.*`
- `status.*` and `filter.*`
- `settings.*`

## 6. QA Checklist

- No missing labels on primary pages (Manual/Scripts/Protocols/Settings).
- No mojibake in locale files.
- `npm --prefix ui/frontend run build` passes.
- Settings docs button has icon and visible text.

## 7. Related Documents

- [User Guide (ZH)](../USER_GUIDE.md)
- [User Guide (EN)](../USER_GUIDE_EN.md)

Language Index: [zh-CN](I18N_MANUAL.zh-CN.md) | [en-US](I18N_MANUAL.en-US.md) | [zh-TW](I18N_MANUAL.zh-TW.md) | [ja-JP](I18N_MANUAL.ja-JP.md) | [ko-KR](I18N_MANUAL.ko-KR.md) | [fr-FR](I18N_MANUAL.fr-FR.md) | [de-DE](I18N_MANUAL.de-DE.md) | [es-ES](I18N_MANUAL.es-ES.md) | [pt-BR](I18N_MANUAL.pt-BR.md) | [ru-RU](I18N_MANUAL.ru-RU.md) | **ar** | [hi](I18N_MANUAL.hi.md) | [it-IT](I18N_MANUAL.it-IT.md) | [nl-NL](I18N_MANUAL.nl-NL.md) | [th-TH](I18N_MANUAL.th-TH.md) | [vi-VN](I18N_MANUAL.vi-VN.md) | [id-ID](I18N_MANUAL.id-ID.md) | [tr-TR](I18N_MANUAL.tr-TR.md) | [pl-PL](I18N_MANUAL.pl-PL.md) | [uk-UA](I18N_MANUAL.uk-UA.md)
73 changes: 73 additions & 0 deletions docs/i18n-manual/I18N_MANUAL.de-DE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# ProtoFlow i18n Manual (de-DE)

Language Index: [zh-CN](I18N_MANUAL.zh-CN.md) | [en-US](I18N_MANUAL.en-US.md) | [zh-TW](I18N_MANUAL.zh-TW.md) | [ja-JP](I18N_MANUAL.ja-JP.md) | [ko-KR](I18N_MANUAL.ko-KR.md) | [fr-FR](I18N_MANUAL.fr-FR.md) | **de-DE** | [es-ES](I18N_MANUAL.es-ES.md) | [pt-BR](I18N_MANUAL.pt-BR.md) | [ru-RU](I18N_MANUAL.ru-RU.md) | [ar](I18N_MANUAL.ar.md) | [hi](I18N_MANUAL.hi.md) | [it-IT](I18N_MANUAL.it-IT.md) | [nl-NL](I18N_MANUAL.nl-NL.md) | [th-TH](I18N_MANUAL.th-TH.md) | [vi-VN](I18N_MANUAL.vi-VN.md) | [id-ID](I18N_MANUAL.id-ID.md) | [tr-TR](I18N_MANUAL.tr-TR.md) | [pl-PL](I18N_MANUAL.pl-PL.md) | [uk-UA](I18N_MANUAL.uk-UA.md)

Current Language: **German**

## 1. Source of Truth

- Aggregator: `ui/frontend/src/i18n/index.ts`
- Locale dictionaries: `ui/frontend/src/i18n/locales/*.ts`
- Default locale: `zh-CN`

## 2. Locale Map

| Locale | Locale File |
|---|---|
| `zh-CN` | ui/frontend/src/i18n/locales/zhCN.ts |
| `en-US` | ui/frontend/src/i18n/locales/enUS.ts |
| `zh-TW` | ui/frontend/src/i18n/locales/zhTW.ts |
| `ja-JP` | ui/frontend/src/i18n/locales/jaJP.ts |
| `ko-KR` | ui/frontend/src/i18n/locales/koKR.ts |
| `fr-FR` | ui/frontend/src/i18n/locales/frFR.ts |
| `de-DE` | ui/frontend/src/i18n/locales/deDE.ts |
| `es-ES` | ui/frontend/src/i18n/locales/esES.ts |
| `pt-BR` | ui/frontend/src/i18n/locales/ptBR.ts |
| `ru-RU` | ui/frontend/src/i18n/locales/ruRU.ts |
| `ar` | ui/frontend/src/i18n/locales/ar.ts |
| `hi` | ui/frontend/src/i18n/locales/hi.ts |
| `it-IT` | ui/frontend/src/i18n/locales/itIT.ts |
| `nl-NL` | ui/frontend/src/i18n/locales/nlNL.ts |
| `th-TH` | ui/frontend/src/i18n/locales/thTH.ts |
| `vi-VN` | ui/frontend/src/i18n/locales/viVN.ts |
| `id-ID` | ui/frontend/src/i18n/locales/idID.ts |
| `tr-TR` | ui/frontend/src/i18n/locales/trTR.ts |
| `pl-PL` | ui/frontend/src/i18n/locales/plPL.ts |
| `uk-UA` | ui/frontend/src/i18n/locales/ukUA.ts |

## 3. Resolution Order

1. `translations[selectedLocale][key]`
2. `translations[DEFAULT_LANGUAGE][key]`
3. Inline fallback text passed to `t(key, fallback)`
4. Final fallback to the key string itself

## 4. Add or Update a Language

1. Create or update locale file in `ui/frontend/src/i18n/locales/`.
2. Export locale object and import it in `ui/frontend/src/i18n/index.ts`.
3. Add locale code to `translations` map.
4. Verify language switch in Settings page.
5. Run frontend build and smoke-check docs button text visibility.

## 5. Required Key Groups

- `nav.*`
- `header.*`
- `action.*`
- `status.*` and `filter.*`
- `settings.*`

## 6. QA Checklist

- No missing labels on primary pages (Manual/Scripts/Protocols/Settings).
- No mojibake in locale files.
- `npm --prefix ui/frontend run build` passes.
- Settings docs button has icon and visible text.

## 7. Related Documents

- [User Guide (ZH)](../USER_GUIDE.md)
- [User Guide (EN)](../USER_GUIDE_EN.md)

Language Index: [zh-CN](I18N_MANUAL.zh-CN.md) | [en-US](I18N_MANUAL.en-US.md) | [zh-TW](I18N_MANUAL.zh-TW.md) | [ja-JP](I18N_MANUAL.ja-JP.md) | [ko-KR](I18N_MANUAL.ko-KR.md) | [fr-FR](I18N_MANUAL.fr-FR.md) | **de-DE** | [es-ES](I18N_MANUAL.es-ES.md) | [pt-BR](I18N_MANUAL.pt-BR.md) | [ru-RU](I18N_MANUAL.ru-RU.md) | [ar](I18N_MANUAL.ar.md) | [hi](I18N_MANUAL.hi.md) | [it-IT](I18N_MANUAL.it-IT.md) | [nl-NL](I18N_MANUAL.nl-NL.md) | [th-TH](I18N_MANUAL.th-TH.md) | [vi-VN](I18N_MANUAL.vi-VN.md) | [id-ID](I18N_MANUAL.id-ID.md) | [tr-TR](I18N_MANUAL.tr-TR.md) | [pl-PL](I18N_MANUAL.pl-PL.md) | [uk-UA](I18N_MANUAL.uk-UA.md)
73 changes: 73 additions & 0 deletions docs/i18n-manual/I18N_MANUAL.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# ProtoFlow i18n Manual (en-US)

Language Index: [zh-CN](I18N_MANUAL.zh-CN.md) | **en-US** | [zh-TW](I18N_MANUAL.zh-TW.md) | [ja-JP](I18N_MANUAL.ja-JP.md) | [ko-KR](I18N_MANUAL.ko-KR.md) | [fr-FR](I18N_MANUAL.fr-FR.md) | [de-DE](I18N_MANUAL.de-DE.md) | [es-ES](I18N_MANUAL.es-ES.md) | [pt-BR](I18N_MANUAL.pt-BR.md) | [ru-RU](I18N_MANUAL.ru-RU.md) | [ar](I18N_MANUAL.ar.md) | [hi](I18N_MANUAL.hi.md) | [it-IT](I18N_MANUAL.it-IT.md) | [nl-NL](I18N_MANUAL.nl-NL.md) | [th-TH](I18N_MANUAL.th-TH.md) | [vi-VN](I18N_MANUAL.vi-VN.md) | [id-ID](I18N_MANUAL.id-ID.md) | [tr-TR](I18N_MANUAL.tr-TR.md) | [pl-PL](I18N_MANUAL.pl-PL.md) | [uk-UA](I18N_MANUAL.uk-UA.md)

Current Language: **English (US)**

## 1. Source of Truth

- Aggregator: `ui/frontend/src/i18n/index.ts`
- Locale dictionaries: `ui/frontend/src/i18n/locales/*.ts`
- Default locale: `zh-CN`

## 2. Locale Map

| Locale | Locale File |
|---|---|
| `zh-CN` | ui/frontend/src/i18n/locales/zhCN.ts |
| `en-US` | ui/frontend/src/i18n/locales/enUS.ts |
| `zh-TW` | ui/frontend/src/i18n/locales/zhTW.ts |
| `ja-JP` | ui/frontend/src/i18n/locales/jaJP.ts |
| `ko-KR` | ui/frontend/src/i18n/locales/koKR.ts |
| `fr-FR` | ui/frontend/src/i18n/locales/frFR.ts |
| `de-DE` | ui/frontend/src/i18n/locales/deDE.ts |
| `es-ES` | ui/frontend/src/i18n/locales/esES.ts |
| `pt-BR` | ui/frontend/src/i18n/locales/ptBR.ts |
| `ru-RU` | ui/frontend/src/i18n/locales/ruRU.ts |
| `ar` | ui/frontend/src/i18n/locales/ar.ts |
| `hi` | ui/frontend/src/i18n/locales/hi.ts |
| `it-IT` | ui/frontend/src/i18n/locales/itIT.ts |
| `nl-NL` | ui/frontend/src/i18n/locales/nlNL.ts |
| `th-TH` | ui/frontend/src/i18n/locales/thTH.ts |
| `vi-VN` | ui/frontend/src/i18n/locales/viVN.ts |
| `id-ID` | ui/frontend/src/i18n/locales/idID.ts |
| `tr-TR` | ui/frontend/src/i18n/locales/trTR.ts |
| `pl-PL` | ui/frontend/src/i18n/locales/plPL.ts |
| `uk-UA` | ui/frontend/src/i18n/locales/ukUA.ts |

## 3. Resolution Order

1. `translations[selectedLocale][key]`
2. `translations[DEFAULT_LANGUAGE][key]`
3. Inline fallback text passed to `t(key, fallback)`
4. Final fallback to the key string itself

## 4. Add or Update a Language

1. Create or update locale file in `ui/frontend/src/i18n/locales/`.
2. Export locale object and import it in `ui/frontend/src/i18n/index.ts`.
3. Add locale code to `translations` map.
4. Verify language switch in Settings page.
5. Run frontend build and smoke-check docs button text visibility.

## 5. Required Key Groups

- `nav.*`
- `header.*`
- `action.*`
- `status.*` and `filter.*`
- `settings.*`

## 6. QA Checklist

- No missing labels on primary pages (Manual/Scripts/Protocols/Settings).
- No mojibake in locale files.
- `npm --prefix ui/frontend run build` passes.
- Settings docs button has icon and visible text.

## 7. Related Documents

- [User Guide (ZH)](../USER_GUIDE.md)
- [User Guide (EN)](../USER_GUIDE_EN.md)

Language Index: [zh-CN](I18N_MANUAL.zh-CN.md) | **en-US** | [zh-TW](I18N_MANUAL.zh-TW.md) | [ja-JP](I18N_MANUAL.ja-JP.md) | [ko-KR](I18N_MANUAL.ko-KR.md) | [fr-FR](I18N_MANUAL.fr-FR.md) | [de-DE](I18N_MANUAL.de-DE.md) | [es-ES](I18N_MANUAL.es-ES.md) | [pt-BR](I18N_MANUAL.pt-BR.md) | [ru-RU](I18N_MANUAL.ru-RU.md) | [ar](I18N_MANUAL.ar.md) | [hi](I18N_MANUAL.hi.md) | [it-IT](I18N_MANUAL.it-IT.md) | [nl-NL](I18N_MANUAL.nl-NL.md) | [th-TH](I18N_MANUAL.th-TH.md) | [vi-VN](I18N_MANUAL.vi-VN.md) | [id-ID](I18N_MANUAL.id-ID.md) | [tr-TR](I18N_MANUAL.tr-TR.md) | [pl-PL](I18N_MANUAL.pl-PL.md) | [uk-UA](I18N_MANUAL.uk-UA.md)
Loading