Skip to content

Commit b09bccd

Browse files
authored
Merge pull request #320 from Integration-Automation/feat/list-format-batch
Add locale-aware list formatting (CLDR-style and/or/unit)
2 parents 8e8f5d6 + 4cf58c6 commit b09bccd

15 files changed

Lines changed: 281 additions & 1 deletion

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-22) — Locale-Aware List Formatting](#whats-new-2026-06-22--locale-aware-list-formatting)
1617
- [What's new (2026-06-22) — Bidirectional-Text QA (Trojan-Source Scan)](#whats-new-2026-06-22--bidirectional-text-qa-trojan-source-scan)
1718
- [What's new (2026-06-22) — Readability Scoring](#whats-new-2026-06-22--readability-scoring)
1819
- [What's new (2026-06-22) — Confusable / Homoglyph Detection](#whats-new-2026-06-22--confusable--homoglyph-detection)
@@ -164,6 +165,12 @@
164165

165166
---
166167

168+
## What's new (2026-06-22) — Locale-Aware List Formatting
169+
170+
Join items the way a language expects ("A, B, and C"). Full reference: [`docs/source/Eng/doc/new_features/v112_features_doc.rst`](docs/source/Eng/doc/new_features/v112_features_doc.rst).
171+
172+
- **`format_list`** (`AC_format_list`): a naive `", ".join` gives "A, B, C" with no "and"/"or" and no localisation. This implements the CLDR list-pattern composition with conjunction / disjunction / unit styles and per-locale conjunction words + serial-comma rule (`en`/`es`/`fr`/`de`/`pt`) — `format_list(["a","b","c"])` → "a, b, and c", `locale="es"` → "a, b y c". Pure-stdlib, deterministic.
173+
167174
## What's new (2026-06-22) — Bidirectional-Text QA (Trojan-Source Scan)
168175

169176
Catch invisible Unicode directional formatting (RTL QA + Trojan-source). Full reference: [`docs/source/Eng/doc/new_features/v111_features_doc.rst`](docs/source/Eng/doc/new_features/v111_features_doc.rst).

README/README_zh-CN.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-22) — 区域感知列表格式化](#本次更新-2026-06-22--区域感知列表格式化)
1516
- [本次更新 (2026-06-22) — 双向文字 QA(Trojan-Source 扫描)](#本次更新-2026-06-22--双向文字-qatrojan-source-扫描)
1617
- [本次更新 (2026-06-22) — 可读性评分](#本次更新-2026-06-22--可读性评分)
1718
- [本次更新 (2026-06-22) — 易混淆字符 / 同形异义字检测](#本次更新-2026-06-22--易混淆字符--同形异义字检测)
@@ -167,6 +168,12 @@
167168

168169
平滑噪声值序列。完整参考:[`docs/source/Zh/doc/new_features/v102_features_doc.rst`](../docs/source/Zh/doc/new_features/v102_features_doc.rst)
169170

171+
## 本次更新 (2026-06-22) — 区域感知列表格式化
172+
173+
依某语言的期望串接项目(「A、B and C」)。完整参考:[`docs/source/Zh/doc/new_features/v112_features_doc.rst`](../docs/source/Zh/doc/new_features/v112_features_doc.rst)
174+
175+
- **`format_list`**(`AC_format_list`):直接 `", ".join` 只会得到「A, B, C」,没有「and/or」也没有在地化。本功能实作 CLDR 列表样式组合,支援连接(and)/选择(or)/单位(unit)样式,并依区域提供连接词与序列逗号规则(`en`/`es`/`fr`/`de`/`pt`)——`format_list(["a","b","c"])` → 「a, b, and c」,`locale="es"` → 「a, b y c」。纯标准库、确定。
176+
170177
## 本次更新 (2026-06-22) — 双向文字 QA(Trojan-Source 扫描)
171178

172179
抓出隐形的 Unicode 方向格式控制(RTL QA + Trojan-source)。完整参考:[`docs/source/Zh/doc/new_features/v111_features_doc.rst`](../docs/source/Zh/doc/new_features/v111_features_doc.rst)

README/README_zh-TW.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-22) — 地區感知清單格式化](#本次更新-2026-06-22--地區感知清單格式化)
1516
- [本次更新 (2026-06-22) — 雙向文字 QA(Trojan-Source 掃描)](#本次更新-2026-06-22--雙向文字-qatrojan-source-掃描)
1617
- [本次更新 (2026-06-22) — 可讀性評分](#本次更新-2026-06-22--可讀性評分)
1718
- [本次更新 (2026-06-22) — 易混淆字元 / 同形異義字偵測](#本次更新-2026-06-22--易混淆字元--同形異義字偵測)
@@ -167,6 +168,12 @@
167168

168169
平滑雜訊值序列。完整參考:[`docs/source/Zh/doc/new_features/v102_features_doc.rst`](../docs/source/Zh/doc/new_features/v102_features_doc.rst)
169170

171+
## 本次更新 (2026-06-22) — 地區感知清單格式化
172+
173+
依某語言的期望串接項目(「A、B and C」)。完整參考:[`docs/source/Zh/doc/new_features/v112_features_doc.rst`](../docs/source/Zh/doc/new_features/v112_features_doc.rst)
174+
175+
- **`format_list`**(`AC_format_list`):直接 `", ".join` 只會得到「A, B, C」,沒有「and/or」也沒有在地化。本功能實作 CLDR 清單樣式組合,支援連接(and)/選擇(or)/單位(unit)樣式,並依地區提供連接詞與序列逗號規則(`en`/`es`/`fr`/`de`/`pt`)——`format_list(["a","b","c"])` → 「a, b, and c」,`locale="es"` → 「a, b y c」。純標準函式庫、具決定性。
176+
170177
## 本次更新 (2026-06-22) — 雙向文字 QA(Trojan-Source 掃描)
171178

172179
抓出隱形的 Unicode 方向格式控制(RTL QA + Trojan-source)。完整參考:[`docs/source/Zh/doc/new_features/v111_features_doc.rst`](../docs/source/Zh/doc/new_features/v111_features_doc.rst)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Locale-Aware List Formatting
2+
============================
3+
4+
``locale_parse`` formats numbers and dates, but joining a list of items the way a
5+
language expects — the conjunction word, whether there is a serial/Oxford comma,
6+
the two-item special case — is its own small problem. A naive ``", ".join`` gives
7+
``"A, B, C"`` with no "and"/"or" and no localisation.
8+
9+
This implements the CLDR list-pattern composition (start/middle/end plus a
10+
two-item pattern) for a handful of locales and the conjunction / disjunction /
11+
unit styles. Pure standard library; imports no ``PySide6``. Every function is
12+
pure, so it is fully deterministic in CI.
13+
14+
Headless API
15+
------------
16+
17+
.. code-block:: python
18+
19+
from je_auto_control import format_list
20+
21+
format_list(["apple", "pear", "grape"]) # 'apple, pear, and grape'
22+
format_list(["apple", "pear", "grape"], style="or") # 'apple, pear, or grape'
23+
format_list(["apple", "pear"], style="unit") # 'apple, pear'
24+
format_list(["manzana", "pera", "uva"], locale="es") # 'manzana, pera y uva'
25+
format_list(["A", "B", "C", "D"], locale="fr") # 'A, B, C et D'
26+
27+
``style`` is ``"and"`` (conjunction), ``"or"`` (disjunction) or ``"unit"``
28+
(comma-separated, no conjunction). ``locale`` selects the conjunction word and
29+
the serial-comma rule (``en`` / ``es`` / ``fr`` / ``de`` / ``pt``; English uses
30+
the Oxford comma, the others do not; an unknown locale falls back to English).
31+
One and two element lists, and the empty list, are handled as special cases.
32+
``ValueError`` is raised for an unknown ``style``.
33+
34+
Executor commands
35+
-----------------
36+
37+
``AC_format_list`` takes a JSON array and returns ``{text}``, accepting ``style``
38+
and ``locale``. It is exposed as the MCP tool ``ac_format_list`` and as a Script
39+
Builder command under **Data**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ Comprehensive guides for all AutoControl features.
134134
doc/new_features/v109_features_doc
135135
doc/new_features/v110_features_doc
136136
doc/new_features/v111_features_doc
137+
doc/new_features/v112_features_doc
137138
doc/ocr_backends/ocr_backends_doc
138139
doc/observability/observability_doc
139140
doc/operations_layer/operations_layer_doc
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
地區感知清單格式化
2+
==================
3+
4+
``locale_parse`` 能格式化數字與日期,但依某語言的期望把一串項目串接起來——連接詞、是否有序列(牛津)逗號、
5+
兩項的特例——本身是個獨立的小問題。直接 ``", ".join`` 只會得到 ``"A, B, C"``,沒有「and/or」也沒有在地化。
6+
7+
本功能為少數幾個地區實作 CLDR 的清單樣式組合(start/middle/end 加上兩項樣式),並支援連接(and)/選擇(or)/
8+
單位(unit)樣式。純標準函式庫;不匯入 ``PySide6``。每個函式皆為純函式,因此在 CI 中完全具決定性。
9+
10+
無頭 API
11+
--------
12+
13+
.. code-block:: python
14+
15+
from je_auto_control import format_list
16+
17+
format_list(["apple", "pear", "grape"]) # 'apple, pear, and grape'
18+
format_list(["apple", "pear", "grape"], style="or") # 'apple, pear, or grape'
19+
format_list(["apple", "pear"], style="unit") # 'apple, pear'
20+
format_list(["manzana", "pera", "uva"], locale="es") # 'manzana, pera y uva'
21+
format_list(["A", "B", "C", "D"], locale="fr") # 'A, B, C et D'
22+
23+
``style`` 為 ``"and"``(連接)、``"or"``(選擇)或 ``"unit"``(僅以逗號分隔、無連接詞)。``locale`` 選擇連接詞與
24+
序列逗號規則(``en`` / ``es`` / ``fr`` / ``de`` / ``pt``;英文使用牛津逗號,其餘不使用;未知地區回退為英文)。
25+
一項、兩項與空清單皆以特例處理。未知的 ``style`` 會拋出 ``ValueError``。
26+
27+
執行器命令
28+
----------
29+
30+
``AC_format_list`` 接受 JSON 陣列並回傳 ``{text}``,可帶 ``style`` 與 ``locale``。它以 MCP 工具
31+
``ac_format_list`` 以及 Script Builder 中 **Data** 分類下的命令提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ AutoControl 所有功能的完整使用指南。
134134
doc/new_features/v109_features_doc
135135
doc/new_features/v110_features_doc
136136
doc/new_features/v111_features_doc
137+
doc/new_features/v112_features_doc
137138
doc/ocr_backends/ocr_backends_doc
138139
doc/observability/observability_doc
139140
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@
235235
is_trojan_source, strip_bidi_controls,
236236
)
237237
from je_auto_control.utils.bidi_check import is_balanced as is_bidi_balanced
238+
# Locale-aware list formatting ("A, B, and C") in the style of CLDR
239+
from je_auto_control.utils.list_format import format_list
238240
# CI workflow annotations (GitHub Actions)
239241
from je_auto_control.utils.ci_annotations import (
240242
emit_annotations, format_annotation,
@@ -988,6 +990,7 @@ def start_autocontrol_gui(*args, **kwargs):
988990
"is_bidi_balanced",
989991
"is_trojan_source",
990992
"strip_bidi_controls",
993+
"format_list",
991994
"emit_annotations", "format_annotation",
992995
"ClipboardHistory", "default_clipboard_history",
993996
"analyze_heal_log", "heal_stats", "scan_secrets",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,6 +2127,18 @@ def _add_resilience_specs(specs: List[CommandSpec]) -> None:
21272127
),
21282128
description="Remove all bidirectional control characters from a string.",
21292129
))
2130+
specs.append(CommandSpec(
2131+
"AC_format_list", "Data", "Text: Format List",
2132+
fields=(
2133+
FieldSpec("items", FieldType.STRING,
2134+
placeholder='["apple", "pear", "grape"]'),
2135+
FieldSpec("style", FieldType.STRING, optional=True,
2136+
placeholder="and | or | unit"),
2137+
FieldSpec("locale", FieldType.STRING, optional=True,
2138+
placeholder="en | es | fr | de | pt"),
2139+
),
2140+
description="Join items into a localised list ('A, B, and C').",
2141+
))
21302142
specs.append(CommandSpec(
21312143
"AC_diff_rows", "Data", "Dataset Diff: Rows by Key",
21322144
fields=(

je_auto_control/utils/executor/action_executor.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3011,6 +3011,16 @@ def _bidi_strip(text: str) -> Dict[str, Any]:
30113011
return {"text": strip_bidi_controls(text)}
30123012

30133013

3014+
def _format_list(items: Any, style: str = "and",
3015+
locale: str = "en") -> Dict[str, Any]:
3016+
"""Adapter: join items into a localised list string."""
3017+
import json
3018+
from je_auto_control.utils.list_format import format_list
3019+
if isinstance(items, str):
3020+
items = json.loads(items)
3021+
return {"text": format_list(list(items), style=style, locale=locale)}
3022+
3023+
30143024
def _cas_put(name: str, key: str, value: Any,
30153025
expected_version: Any = None) -> Dict[str, Any]:
30163026
"""Adapter: optimistic put into a named versioned store."""
@@ -4700,6 +4710,7 @@ def __init__(self):
47004710
"AC_readability_report": _readability_report,
47014711
"AC_bidi_check": _bidi_check,
47024712
"AC_bidi_strip": _bidi_strip,
4713+
"AC_format_list": _format_list,
47034714
"AC_detect_drift": _detect_drift,
47044715
"AC_categorical_drift": _categorical_drift,
47054716
"AC_diff_rows": _diff_rows,

0 commit comments

Comments
 (0)