Communitygithub.com

asadeisa/arabic-office-skills

为 PDF、Word 和 PowerPoint 生成正确阿拉伯语/RTL 输出的 Agent 技能——附带 PNG 预览用于视觉验证

arabic-office-skills 是什么?

该技能解决了在 PDF 中生成正确阿拉伯语(RTL)文本的难题。Reportlab 等库生成的阿拉伯语常出现字母断开、单词顺序颠倒、段落错位等问题,且这些错误在纯文本提取中不可见,只有通过渲染才能发现。技能提供一个预构建的 `arabic_pdf.py` 脚本,集成了阿拉伯语字符整形(arabic_reshaper)、双向文本处理(python-bidi)、手动换行和括号镜像修复等完整解决方案。支持 table、bullets、heading 等文档元素,并强制要求通过 PNG 预览进行视觉验证。技能明确警告,此方法仅适用于 reportlab/Pillow 环境,不可用于 Word 或 PowerPoint——后者需要完全不同的逻辑顺序 Unicode 输入。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add asadeisa/arabic-office-skills

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

阿拉伯语 / RTL PDF 生成

朴素的 reportlab 代码生成的阿拉伯语存在微妙但彻底的错误:字母看起来断开,单词在一行内反向排列,段落内的行互换位置。这些错误在提取的文本中不可见——仅在渲染中可见。本技能包含一个已经解决了这些问题的构建器。

请使用 scripts/arabic_pdf.py,而不是从头编写整形逻辑。 下面的每种失败模式都是在实际文档中碰到的。

依赖

pip install reportlab arabic-reshaper python-bidi pypdfium2

pypdfium2 仅用于预览,但预览不是可选的——请参见下面的“验证”。

构建文档

通过将 scripts/arabic_pdf.py 复制到生成脚本旁边,或者将该技能的 scripts/ 文件夹添加到 sys.path 来导入构建器:

import pathlib, sys
sys.path.insert(0, str(pathlib.Path.home() / ".claude" / "skills" / "arabic-pdf" / "scripts"))
from arabic_pdf import ArabicPDF, preview

pdf = ArabicPDF("report.pdf", doc_title="عنوان المستند", page_numbers=True)

pdf.title("عنوان المستند")
pdf.subtitle("سطر فرعي")

pdf.heading("أولاً — المقدمة")
pdf.para("فقرة عربية تتضمن مصطلحات لاتينية مثل PostgreSQL و FastAPI.")

pdf.heading("ثانياً — جدول")
pdf.table(
    ["البند", "التفصيل"],                     # 最右列在前
    [["الواجهة الخلفية", "Python — FastAPI"],
     ["قاعدة البيانات", "PostgreSQL — SQLAlchemy"]],
    [5.0, 11.0],                              # 列宽(厘米)
)

pdf.bullets(["نقطة أولى", "نقطة ثانية"])
pdf.save()

preview("report.pdf")     # 每页一张 PNG

如果技能安装在其他位置,请调整路径——构建器中的其他部分不依赖于其安装位置。

方法支持链式调用,因此 pdf.heading(...).para(...) 也可以工作。

方法用途
title / subtitle居中的文档标题
heading右对齐的粗体章节标题
para正文段落
bullets(items, marker="–")每项右对齐的一行
table(header, rows, widths_cm)RTL 表格;自然阅读顺序输入,列顺序反转输出
spacer(pts) / page_break()布局控制
save()写入文件,返回路径

单元格和段落文本中可以使用 \n 强制换行。

验证——始终渲染并查看

在 save() 之后,调用 preview() 并使用阅读工具查看 PNG。文本提取无法捕获 RTL 缺陷,因为所有字符都存在且正确;出错的只是它们的顺序和形状。请特别检查:

  • 每个段落的第一个单词是否位于右上角?
  • 拉丁语术语(PostgreSQL、FastAPI)是否位于句子中应有的位置,而不是跳到行的最左边?
  • 字母是连在一起的,还是像 ا ل س ل ا م 一样分开的?
  • 是否有实心黑色方块?字体缺少这些字形——请选择另一种字体。
  • 括号方向是否正确——(20 فأكثر) 而不是 )20 فأكثر(?
  • 拉丁术语内部的对是否完整——Array<String>、DECIMAL(5,2)?
  • 是否有单个表格行被孤立到下一页?

修复一个你从未查找过的缺陷,在文档已经发送给接收者后,成本要高得多。

正确性如何实现

在调整构建器或调试异常文档时有用。

  1. 整形 — arabic_reshaper 将字符映射到位置呈现形式,使字母连接。
  2. 带有显式基础方向的 Bidi — get_display(..., base_dir="R")。 如果没有 base_dir,方向由第一个强字符推断,因此以拉丁语单词开头的行将按从左到右布局,之后的阿拉伯语会出错。这是“大部分正确但某些行混乱”的最常见原因。
  3. 手动换行 — 整形后的文本是视觉顺序。如果 reportlab 对其换行,它推到下一行的单词在逻辑上是第一个,因此行顺序被打乱。构建器先换行,分别整形每一行,并用 <br/> 连接,这样 reportlab 就不会重新换行。8pt 的安全边距弥补了测量差异;溢出一点的行就可能使其反转。
  4. 镜像 — get_display 会重新排序,但从不应用 bidi 规则 L4,该规则规定以从右到左布局的镜像字符应绘制为其对应的字符。没有它,(20 فأكثر) 会返回两个括号位置交换且使用原始字形,并打印为 )20 فأكثر(。prepare() 首先替换它们,因此重新排序会移动正确的字形。
  5. 拉丁语孤岛 — < 和 > 是镜像字符,但不是 Unicode 配对括号,因此保持 DECIMAL(5,2) 完整的规则不涵盖它们;Array<String> 中的 > 会采用其后阿拉伯语的方向并被扔到最远端。每个拉丁语片段被包裹在 LRI…PDI 中,并在重新排序后再次移除隔离符,因此没有任何不可见的内容到达 PDF。
  6. 整形后进行转义 — reportlab 需要对 &、<、> 进行转义,但先转义会将 &lt; 作为四个字符发送给 bidi 处理,其尾部的 ; 会被排到行的最远端。先整形,再转义。
  7. 反转的表格列 — reportlab 从左到右布局列,因此构建器反转它们,使您可以按自然阅读顺序传递列。
  8. 表格上的 KeepTogether — 防止单行被孤立到新页面上。

第 4-6 点与 arabic-docx 中描述的分割括号运行属于同一类缺陷,只是从相反方向实现:在那里,一对括号不得跨运行分割;在这里,一对括号不得被部分镜像。任何镜像字符都必须与其配对字符一起处理。

字体

register_fonts() 搜索支持阿拉伯语的字体:Windows 上为 Arial 然后是 Tahoma,macOS 上为 Arial,Linux 上为 Noto Naskh Arabic 然后是 DejaVu Sans。要使用特定字体(Amiri 和 Cairo 适合正式文档):

from arabic_pdf import register_fonts
register_fonts("/path/Amiri-Regular.ttf", "/path/Amiri-Bold.ttf")   # 在 ArabicPDF(...) 之前

Reportlab 的内置字体没有阿拉伯语覆盖,因此必须注册 TTF——这就是为什么缺少字体会显示为黑色方块而不是错误。

切勿将此方法用于 Word 或 PowerPoint

这是整个 RTL 技能系列中最重要的界限。

reportlab / PillowWord / PowerPoint
文本引擎无完整的双向引擎
期望最终的视觉顺序字形原始逻辑顺序 Unicode
技术整形 + bidi + 手动换行XML 中的方向标志

预整形在这里是必需的,而在那里是破坏性的:Word 和 PowerPoint 在渲染时整形,因此提供呈现形式会使它们第二次整形——导致字形损坏,并且文本无法再搜索、复制或拼写检查。这两种方法是相反的,而不是变体。

对 .docx 使用 arabic-docx,对 .pptx 使用 arabic-pptx。在没有重新阅读它们为什么不同之前,不要在这三者之间移植代码。

说明

  • 当需要阿拉伯-印度数字时,arabic_digits("38") → "٣٨"。纯装饰性;西方数字在阿拉伯语技术写作中完全正常。
  • 默认情况下保持格式简洁——黑色文本,细线。学术和官方阿拉伯语文档读起来更可信,而且要求“简单”的用户就是这么想的。
  • 同样的机制也适用于波斯语、乌尔都语和希伯来语;只有字体需要覆盖该文字。

是什么让生成的阿拉伯语读起来像机器生成的

不是词汇——而是添加的内容。以下每种习惯都告诉读者一些关于文档是如何编写的信息,而不是其主题;手工编辑的读者会删除所有这些习惯。写句子,而不是写关于如何写句子的描述。

习惯而不是请写
叙述写作行为«الشروط ثلاثة، نذكرها صراحة فيما يلي»«الشروط ثلاثة:»
指向另一个章节«…ونعود إلى هذه النقطة لاحقاً»删除该短语
标题中的版本或状态标签«الخطة (النسخة الثانية — معتمدة)»«الخطة»
针对没人提出的选项进行争论«نحفظ المسار فقط. تخزين الملف كاملاً يضخّم الحجم بلا فائدة.»«نحفظ المسار فقط.»
通过简报未提及的内容来证明选择的合理性«لم يرد ذلك في الطلب، غير أن طبيعة العمل تفرضه.»«طبيعة العمل تفرض ذلك.»
第一人称单数«وأستطيع لاحقاً تحليل الحالات»«ويمكن لاحقاً تحليل الحالات»
重复文档已经给出的事实在另一个部分重复信息删除重复

正式阿拉伯语更喜欢非人称或复数形式而非 «أنا»;单数形式读起来像给自己的笔记,而不是一个文档。

相关技能