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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

## Table of Contents

- [What's new (2026-06-19) — i18n / l10n Testing](#whats-new-2026-06-19--i18n--l10n-testing)
- [What's new (2026-06-19) — Data Quality](#whats-new-2026-06-19--data-quality)
- [What's new (2026-06-19) — SBOM & Suite Sharding](#whats-new-2026-06-19--sbom--suite-sharding)
- [What's new (2026-06-19) — Reactive Observer](#whats-new-2026-06-19--reactive-observer)
Expand Down Expand Up @@ -72,6 +73,14 @@

---

## What's new (2026-06-19) — i18n / l10n Testing

Three pure-stdlib internationalization/localization testing helpers that compound, full stack. Full reference: [`docs/source/Eng/doc/new_features/v20_features_doc.rst`](docs/source/Eng/doc/new_features/v20_features_doc.rst).

- **Pseudo-localization** — `pseudo_localize` / `pseudo_localize_catalog` (`AC_pseudo_localize`, `ac_pseudo_localize`): accent + pad UI strings (placeholders preserved, `⟦…⟧` wrapped) to flush out hardcoded text and pre-stress layout before real translation.
- **Text-overflow detection** — `check_overflow(elements)` (`AC_check_overflow`, `ac_check_overflow`): flag text whose estimated width exceeds its widget bounds (the #1 l10n bug), computed from the a11y bounds AutoControl already reads.
- **Catalog completeness** — `check_catalog(base, target)` (`AC_check_catalog`, `ac_check_catalog`): diff a translation catalog for missing / orphaned / empty keys and placeholder mismatches — a CI gate against blank UI.

## What's new (2026-06-19) — Data Quality

Three pure-stdlib data-quality helpers (the gate between `load_rows`/OCR and downstream entry), full stack. Full reference: [`docs/source/Eng/doc/new_features/v19_features_doc.rst`](docs/source/Eng/doc/new_features/v19_features_doc.rst).
Expand Down
9 changes: 9 additions & 0 deletions README/README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

## 目录

- [本次更新 (2026-06-19) — i18n / l10n 测试](#本次更新-2026-06-19--i18n--l10n-测试)
- [本次更新 (2026-06-19) — 数据质量](#本次更新-2026-06-19--数据质量)
- [本次更新 (2026-06-19) — SBOM 与测试分片](#本次更新-2026-06-19--sbom-与测试分片)
- [本次更新 (2026-06-19) — 反应式观察器](#本次更新-2026-06-19--反应式观察器)
Expand Down Expand Up @@ -71,6 +72,14 @@

---

## 本次更新 (2026-06-19) — i18n / l10n 测试

三项可互相搭配的纯标准库国际化/本地化测试辅助工具,走完整五层。完整参考:[`docs/source/Zh/doc/new_features/v20_features_doc.rst`](../docs/source/Zh/doc/new_features/v20_features_doc.rst)。

- **伪本地化** — `pseudo_localize` / `pseudo_localize_catalog`(`AC_pseudo_localize`、`ac_pseudo_localize`):为 UI 字符串加重音与填充(保留占位符、以 `⟦…⟧` 包裹),在真正翻译前揪出硬编码文本并对版面施压。
- **文本溢出检测** — `check_overflow(elements)`(`AC_check_overflow`、`ac_check_overflow`):标记估计宽度超过控件边界的文本(本地化头号 bug),由 AutoControl 既有读取的 a11y 边界计算。
- **目录完整性** — `check_catalog(base, target)`(`AC_check_catalog`、`ac_check_catalog`):比对翻译目录的缺失/多余/空白键与占位符不一致——防止空白 UI 的 CI 闸。

## 本次更新 (2026-06-19) — 数据质量

三项纯标准库的数据质量辅助工具(介于 `load_rows`/OCR 与下游输入之间的闸),走完整五层。完整参考:[`docs/source/Zh/doc/new_features/v19_features_doc.rst`](../docs/source/Zh/doc/new_features/v19_features_doc.rst)。
Expand Down
9 changes: 9 additions & 0 deletions README/README_zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

## 目錄

- [本次更新 (2026-06-19) — i18n / l10n 測試](#本次更新-2026-06-19--i18n--l10n-測試)
- [本次更新 (2026-06-19) — 資料品質](#本次更新-2026-06-19--資料品質)
- [本次更新 (2026-06-19) — SBOM 與測試分片](#本次更新-2026-06-19--sbom-與測試分片)
- [本次更新 (2026-06-19) — 反應式觀察器](#本次更新-2026-06-19--反應式觀察器)
Expand Down Expand Up @@ -71,6 +72,14 @@

---

## 本次更新 (2026-06-19) — i18n / l10n 測試

三項可互相搭配的純標準庫國際化/在地化測試輔助工具,走完整五層。完整參考:[`docs/source/Zh/doc/new_features/v20_features_doc.rst`](../docs/source/Zh/doc/new_features/v20_features_doc.rst)。

- **偽在地化** — `pseudo_localize` / `pseudo_localize_catalog`(`AC_pseudo_localize`、`ac_pseudo_localize`):為 UI 字串加重音與填充(保留佔位符、以 `⟦…⟧` 包覆),在真正翻譯前揪出寫死文字並對版面施壓。
- **文字溢位偵測** — `check_overflow(elements)`(`AC_check_overflow`、`ac_check_overflow`):標記估計寬度超過元件邊界的文字(在地化頭號 bug),由 AutoControl 既有讀取的 a11y 邊界計算。
- **目錄完整性** — `check_catalog(base, target)`(`AC_check_catalog`、`ac_check_catalog`):比對翻譯目錄的缺漏/多餘/空白鍵與佔位符不一致——防止空白 UI 的 CI 閘。

## 本次更新 (2026-06-19) — 資料品質

三項純標準庫的資料品質輔助工具(介於 `load_rows`/OCR 與下游輸入之間的閘),走完整五層。完整參考:[`docs/source/Zh/doc/new_features/v19_features_doc.rst`](../docs/source/Zh/doc/new_features/v19_features_doc.rst)。
Expand Down
61 changes: 61 additions & 0 deletions docs/source/Eng/doc/new_features/v20_features_doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
==================================================
New Features (2026-06-19) — i18n / l10n Testing
==================================================

Three pure-standard-library internationalization / localization testing
helpers that compound, wired through the full stack (facade, ``AC_*``
executor commands, MCP tools, Script Builder).

.. contents::
:local:
:depth: 2


Pseudo-localization
==================

Accent and pad UI strings (preserving placeholders) to flush out hardcoded
text and pre-stress layout *before* any real translation exists::

from je_auto_control import pseudo_localize, pseudo_localize_catalog

pseudo_localize("Hello {name}") # "⟦Hèllo {name}········⟧"
pseudo_localize_catalog({"save": "Save", "cancel": "Cancel"})

Placeholders (``{name}`` / ``{{x}}`` / ``%s`` / ``%d``) are preserved
verbatim; ``expansion`` controls the padding fraction; the ``⟦…⟧`` brackets
make truncation visible. Exposed as ``AC_pseudo_localize`` /
``ac_pseudo_localize``. Untranslated (un-accented) strings in a screen are a
sign of unexternalized, hardcoded text.


Text-overflow detection
=======================

Flag text whose estimated width exceeds its widget bounds — the #1
localization bug (German/Finnish expand 30–50%). Computed from the
accessibility bounds AutoControl already reads::

from je_auto_control import check_overflow

issues = check_overflow(elements, avg_char_px=7.0)
# [{"text": "...", "width": 40, "required_px": 400.0, "overflow_px": 360.0}]

Width is estimated as ``len(text) * avg_char_px`` (deterministic
heuristic). Exposed as ``AC_check_overflow`` / ``ac_check_overflow`` (uses
the live a11y tree unless ``elements`` are supplied).


Catalog completeness
===================

Diff a translation catalog against a base locale for missing / orphaned /
empty keys and placeholder mismatches — a CI gate against blank UI::

from je_auto_control import check_catalog

report = check_catalog(base_locale, target_locale)
report["missing"] # keys absent in target
report["placeholder_mismatch"] # e.g. "{count}" dropped in the target

Exposed as ``AC_check_catalog`` / ``ac_check_catalog``.
1 change: 1 addition & 0 deletions docs/source/Eng/eng_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Comprehensive guides for all AutoControl features.
doc/new_features/v17_features_doc
doc/new_features/v18_features_doc
doc/new_features/v19_features_doc
doc/new_features/v20_features_doc
doc/ocr_backends/ocr_backends_doc
doc/observability/observability_doc
doc/operations_layer/operations_layer_doc
Expand Down
58 changes: 58 additions & 0 deletions docs/source/Zh/doc/new_features/v20_features_doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
==========================================
新功能 (2026-06-19) — i18n / l10n 測試
==========================================

三項可互相搭配的純標準庫國際化 / 在地化測試輔助工具,走完整五層
(facade、``AC_*`` 執行器指令、MCP 工具、Script Builder)。

.. contents::
:local:
:depth: 2


偽在地化(Pseudo-localization)
==============================

在真正的翻譯出現*之前*,先為 UI 字串加上重音與填充(保留佔位符),以
揪出寫死的字串並預先對版面施壓::

from je_auto_control import pseudo_localize, pseudo_localize_catalog

pseudo_localize("Hello {name}") # "⟦Hèllo {name}········⟧"
pseudo_localize_catalog({"save": "Save", "cancel": "Cancel"})

佔位符(``{name}`` / ``{{x}}`` / ``%s`` / ``%d``)會原樣保留;``expansion``
控制填充比例;``⟦…⟧`` 括號讓截斷一眼可見。對應 ``AC_pseudo_localize`` /
``ac_pseudo_localize``。畫面中未被加重音(未翻譯)的字串,代表它是未外部化
的寫死文字。


文字溢位偵測
============

標記估計寬度超過其元件邊界的文字——在地化的頭號 bug(德文/芬蘭文會膨脹
30–50%)。由 AutoControl 既有讀取的 accessibility 邊界計算::

from je_auto_control import check_overflow

issues = check_overflow(elements, avg_char_px=7.0)
# [{"text": "...", "width": 40, "required_px": 400.0, "overflow_px": 360.0}]

寬度以 ``len(text) * avg_char_px`` 估計(決定性啟發式)。對應
``AC_check_overflow`` / ``ac_check_overflow``(未提供 ``elements`` 時使用
即時 a11y 樹)。


翻譯目錄完整性
==============

把翻譯目錄與基準語系比對:缺漏 / 多餘 / 空白鍵與佔位符不一致——可作為防止
空白 UI 的 CI 閘::

from je_auto_control import check_catalog

report = check_catalog(base_locale, target_locale)
report["missing"] # target 中缺漏的鍵
report["placeholder_mismatch"] # 例如 target 漏掉 "{count}"

對應 ``AC_check_catalog`` / ``ac_check_catalog``。
1 change: 1 addition & 0 deletions docs/source/Zh/zh_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ AutoControl 所有功能的完整使用指南。
doc/new_features/v17_features_doc
doc/new_features/v18_features_doc
doc/new_features/v19_features_doc
doc/new_features/v20_features_doc
doc/ocr_backends/ocr_backends_doc
doc/observability/observability_doc
doc/operations_layer/operations_layer_doc
Expand Down
6 changes: 6 additions & 0 deletions je_auto_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@
from je_auto_control.utils.data_quality import (
extract_fields, mask_rows, validate_rows,
)
# i18n / l10n testing: pseudo-localize, overflow + catalog checks
from je_auto_control.utils.i18n_test import (
check_catalog, check_overflow, pseudo_localize, pseudo_localize_catalog,
)
# Background popup/interrupt watchdog (unattended automation)
from je_auto_control.utils.watchdog import (
PopupWatchdog, WatchdogRule, default_popup_watchdog,
Expand Down Expand Up @@ -577,6 +581,8 @@ def start_autocontrol_gui(*args, **kwargs):
"build_sbom", "write_sbom",
"merge_results", "shard_flows",
"extract_fields", "mask_rows", "validate_rows",
"check_catalog", "check_overflow", "pseudo_localize",
"pseudo_localize_catalog",
# MCP server
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",
Expand Down
28 changes: 28 additions & 0 deletions je_auto_control/gui/script_builder/command_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,7 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
_add_office_specs(specs)
_add_memory_specs(specs)
_add_data_quality_specs(specs)
_add_i18n_specs(specs)
specs.append(CommandSpec(
"AC_wcag_audit", "Accessibility", "WCAG 2.2 Conformance Audit",
fields=(
Expand Down Expand Up @@ -739,6 +740,33 @@ def _add_observer_specs(specs: List[CommandSpec]) -> None:
description="Stop the background observer thread."))


def _add_i18n_specs(specs: List[CommandSpec]) -> None:
specs.append(CommandSpec(
"AC_pseudo_localize", "Data", "Pseudo-Localize",
fields=(
FieldSpec("text", FieldType.STRING, optional=True),
FieldSpec("expansion", FieldType.FLOAT, optional=True,
default=0.4),
),
description="Accent+pad a string (or 'mapping' via JSON view) for "
"i18n stress testing.",
))
specs.append(CommandSpec(
"AC_check_overflow", "Data", "Check Text Overflow",
fields=(
FieldSpec("app_name", FieldType.STRING, optional=True),
FieldSpec("avg_char_px", FieldType.FLOAT, optional=True,
default=7.0),
),
description="Flag text wider than its widget (translation overflow).",
))
specs.append(CommandSpec(
"AC_check_catalog", "Data", "Check Translation Catalog",
description="Diff 'target' vs 'base' catalog (JSON view): missing / "
"empty / placeholder mismatch.",
))


def _add_data_quality_specs(specs: List[CommandSpec]) -> None:
specs.append(CommandSpec(
"AC_validate_rows", "Data", "Validate Rows (schema)",
Expand Down
35 changes: 35 additions & 0 deletions je_auto_control/utils/executor/action_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,38 @@ def _mask_rows(rows: List[Dict[str, Any]],
return {"rows": mask_rows(rows, rules)}


def _pseudo_localize(text: Optional[str] = None,
mapping: Optional[Dict[str, Any]] = None,
expansion: float = 0.4) -> Dict[str, Any]:
"""Adapter: pseudo-localize a string or a whole catalog mapping."""
from je_auto_control.utils.i18n_test import (
pseudo_localize, pseudo_localize_catalog)
if mapping is not None:
return {"catalog": pseudo_localize_catalog(
mapping, expansion=float(expansion))}
return {"text": pseudo_localize(text or "", expansion=float(expansion))}


def _check_overflow(elements: Optional[List[Any]] = None,
avg_char_px: float = 7.0,
app_name: Optional[str] = None) -> Dict[str, Any]:
"""Adapter: flag text wider than its widget (live a11y unless given)."""
from je_auto_control.utils.i18n_test import check_overflow
items = elements
if items is None:
from je_auto_control.utils.accessibility.accessibility_api import (
list_accessibility_elements)
items = list_accessibility_elements(app_name=app_name)
return {"issues": check_overflow(items, avg_char_px=float(avg_char_px))}


def _check_catalog(base: Dict[str, Any],
target: Dict[str, Any]) -> Dict[str, Any]:
"""Adapter: diff a translation catalog against the base locale."""
from je_auto_control.utils.i18n_test import check_catalog
return check_catalog(base, target)


class Executor:
"""
Executor
Expand Down Expand Up @@ -2889,6 +2921,9 @@ def __init__(self):
"AC_validate_rows": _validate_rows,
"AC_extract_fields": _extract_fields,
"AC_mask_rows": _mask_rows,
"AC_pseudo_localize": _pseudo_localize,
"AC_check_overflow": _check_overflow,
"AC_check_catalog": _check_catalog,
"AC_a11y_record_start": _a11y_record_start,
"AC_a11y_record_stop": _a11y_record_stop,
"AC_a11y_record_events": _a11y_record_events,
Expand Down
9 changes: 9 additions & 0 deletions je_auto_control/utils/i18n_test/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Internationalization / localization testing helpers."""
from je_auto_control.utils.i18n_test.i18n_test import (
check_catalog, check_overflow, pseudo_localize, pseudo_localize_catalog,
)

__all__ = [
"check_catalog", "check_overflow", "pseudo_localize",
"pseudo_localize_catalog",
]
Loading
Loading