Skip to content

Commit 599f6e5

Browse files
authored
Bring glossary-searcher to the python-docs-farsi repository (#66)
* Bring glossary-searcher to the python-docs-farsi repository * Update README.md and CONTRIBUTING.md
1 parent 5c3f27a commit 599f6e5

14 files changed

Lines changed: 1032 additions & 18 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
name: اشکال در واژه‌یاب
3+
about: گزارش مشکل یا رفتار نادرست در ابزار واژه‌یاب
4+
title: "[واژه‌یاب] "
5+
labels: bug
6+
assignees: ''
7+
---
8+
9+
## توضیح مشکل
10+
11+
<!--
12+
لطفاً مشکل مشاهده‌شده را به‌طور کامل توضیح دهید.
13+
اگر ممکن است، مراحل لازم برای بازتولید مشکل را نیز بنویسید.
14+
-->
15+
16+
## مراحل بازتولید
17+
18+
<!--
19+
مراحل انجام‌شده برای مشاهده‌ی مشکل را به‌ترتیب وارد کنید.
20+
برای مثال:
21+
1. به صفحه‌ی واژه‌یاب بروید.
22+
2. واژه‌ی خاصی را جست‌وجو کنید.
23+
3. نتیجه‌ی نادرست یا خطا را مشاهده کنید.
24+
-->
25+
26+
## نتیجه‌ی مورد انتظار
27+
28+
<!--
29+
توضیح دهید انتظار داشتید واژه‌یاب چه رفتاری داشته باشد.
30+
-->
31+
32+
## نتیجه‌ی مشاهده‌شده
33+
34+
<!--
35+
توضیح دهید واژه‌یاب در عمل چه رفتاری نشان داد.
36+
-->
37+
38+
## مرورگر و محیط مورد استفاده
39+
40+
<!--
41+
لطفاً اطلاعات مربوط به محیط اجرا را وارد کنید.
42+
برای مثال:
43+
- Firefox نسخه‌ی x
44+
- Chrome نسخه‌ی y
45+
- سیستم‌عامل (در صورت ارتباط)
46+
-->
47+
48+
## اسکرین‌شات یا اطلاعات تکمیلی
49+
50+
<!--
51+
در صورت امکان، تصویر، پیام خطا، یا هر اطلاعات دیگری که به بررسی مشکل کمک می‌کند را درج کنید.
52+
-->
53+
54+
## آیین‌نامه‌ی رفتاری
55+
56+
- [ ] می‌پذیرم که از [آیین‌نامه‌ی رفتاری PSF](https://www.python.org/psf/conduct/) پیروی کنم.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
- [ ] `msgfmt --check` روی پرونده‌های تغییر یافته با موفقیت اجرا شده است
2020
- [ ] `python3 scripts/check_markup.py` روی پرونده‌های تغییر یافته اجرا شده است
2121
- [ ] نشانه‌گذاری‌های Sphinx (`:class:`، `:func:`، کد درون‌خطی) و جای‌گذارها (`%s`، `{name}`) دست‌نخورده مانده‌اند
22-
- [ ] ترجمه‌ها با [واژه‌نامه (GLOSSARY.md)](https://github.com/python/python-docs-fa/blob/3.14/GLOSSARY.md) هماهنگ است
22+
- [ ] ترجمه‌ها با [واژه‌نامه](http://python.github.io/python-docs-fa/glossary-searcher) هماهنگ است
2323
- [ ] رشته‌های `fuzzy` بررسی و در صورت لزوم بازنویسی شده‌اند
2424
- [ ] پرونده [CONTRIBUTING.md](https://github.com/python/python-docs-fa/blob/3.14/CONTRIBUTING.md) با دقت خوانده شده است.
2525
<!-- یادآوری: بررسی‌های خودکار (sphinx-lint ،msgfmt ،check_markup و ساخت کامل) در GitHub Actions روی پول‌ریکوئست اجرا می‌شوند. -->

.github/workflows/build-and-deploy.yml

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ name: Build and Deploy to GitHub Pages
22

33
on:
44
schedule:
5-
- cron: '0 2 * * *'
5+
- cron: '0 2 * * *'
66
push:
77
branches:
88
- 3.14
9+
paths-ignore: []
910
workflow_dispatch:
1011

1112
permissions:
@@ -26,21 +27,17 @@ jobs:
2627
with:
2728
repository: python/cpython
2829
ref: v3.14.7
29-
30+
3031
- name: Set up Python
3132
uses: actions/setup-python@v4
3233
with:
3334
python-version: '3.12'
34-
35+
3536
- name: Setup virtual environment
3637
run: make venv
3738
working-directory: ./Doc
3839

3940
- name: Pin Sphinx to 9.1.0
40-
# make venv may resolve an older Sphinx via requirements.txt; pin
41-
# explicitly so we get the reordered-ref / translated-display-text
42-
# i18n fixes (sphinx-doc/sphinx#14144). Bump this once #14162 lands
43-
# upstream and re-check whether the suppression below is still needed.
4441
run: ./venv/bin/pip install "sphinx==9.1.0"
4542
working-directory: ./Doc
4643

@@ -56,14 +53,39 @@ jobs:
5653

5754
- name: Setup problem matcher
5855
uses: sphinx-doc/github-problem-matcher@v1.1
59-
56+
6057
- name: Build documentation
6158
run: make -e SPHINXERRORHANDLING="" SPHINXOPTS="--color -D language='fa' -D gettext_allow_fuzzy_translations=1 -D html_theme_options.is_rtl=true -D suppress_warnings=i18n.inconsistent_references --keep-going" html
6259
working-directory: ./Doc
63-
60+
61+
# ---- Glossary searcher build starts here ----
62+
- name: Install glossary build dependencies
63+
run: pip install -r glossary-searcher/scripts/requirements.txt
64+
working-directory: Doc/locales/fa/LC_MESSAGES
65+
66+
- name: Build glossary corpus & glossary data
67+
run: |
68+
python glossary-searcher/scripts/build_corpus.py \
69+
--repo-dir . \
70+
--glossary-tsv glossary.tsv \
71+
--out-dir glossary-searcher/data
72+
working-directory: Doc/locales/fa/LC_MESSAGES
73+
74+
- name: Build glossary site
75+
run: |
76+
python glossary-searcher/scripts/build_site.py \
77+
--site-dir glossary-searcher/site \
78+
--data-dir glossary-searcher/data \
79+
--out-dir glossary-searcher/dist
80+
working-directory: Doc/locales/fa/LC_MESSAGES
81+
82+
- name: Merge glossary site into docs build
83+
run: cp -r Doc/locales/fa/LC_MESSAGES/glossary-searcher/dist Doc/build/html/glossary-searcher
84+
# ---- Glossary searcher build ends here ----
85+
6486
- name: Setup Pages
6587
uses: actions/configure-pages@v4
66-
88+
6789
- name: Upload artifact
6890
uses: actions/upload-pages-artifact@v3
6991
with:

CONTRIBUTING.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# راهنمای مشارکت در ترجمه‌ی مستندات پایتون
22

3-
این راهنما مکمل [README.md](README.md) است و جزئیات فنی و فرایندهای پروژه را توضیح می‌دهد. پیش از شروع، حتماً [README.md](README.md) را بخوانید.
3+
این راهنما مکمل [README.md](README.md) است و جزئیات فنی و فرایندهای مربوط به مشارکت در پروژه را توضیح می‌دهد. پیش از شروع مشارکت، حتماً [README.md](README.md) را مطالعه کنید.
4+
5+
همچنین واژه‌نامه‌ی پروژه به‌صورت یک وبگاه از طریق [این پیوند](http://python.github.io/python-docs-fa/glossary-searcher) در دسترس است. با جست‌وجوی واژه‌ی انگلیسی مورد نظر، می‌توانید در صورت وجود آن در واژه‌نامه، معادل فارسی ثبت‌شده‌ی آن را به‌همراه نمونه‌های کاربرد آن در پیکره‌ی مستندات مشاهده کنید.
46

57
تمام مشارکت‌کنندگان موظف‌اند از [آیین‌نامه‌ی رفتاری PSF](https://www.python.org/psf/conduct/) پیروی کنند. این تعهد در همه‌ی ایشیوها و پول‌ریکوئست‌ها به‌صورت یک چک‌باکس ثبت می‌شود.
68

@@ -38,10 +40,11 @@
3840

3941
## انواع ایشیو
4042

41-
پیش از باز کردن ایشیوی جدید، قالب مناسب را از [صفحه‌ی ایشیوهای پروژه](https://github.com/python/python-docs-fa/issues/new/choose) انتخاب کنید. دو قالب موجود است:
43+
پیش از باز کردن ایشیوی جدید، قالب مناسب را از [صفحه‌ی ایشیوهای پروژه](https://github.com/python/python-docs-fa/issues/new/choose) انتخاب کنید. سه قالب موجود است:
4244

4345
- **اشکال در ترجمه:** برای گزارش ترجمه‌ی نادرست یا مشکل‌دار در یک صفحه‌ی منتشرشده. `msgid`، `msgstr` فعلی، و ترجمه‌ی پیشنهادی خود را در قالب وارد کنید.
4446
- **پیشنهاد تغییرات در ترجمه:** برای پیشنهاد تغییر در یک واژه یا شیوه‌ی نگارشِ ثابت‌شده (نه یک اشکال ساده). فرایند بررسی این نوع پیشنهاد در بخش [«پیشنهاد تغییر در واژه یا شیوه‌ی نگارش»](#پیشنهاد-تغییر-در-واژه-یا-شیوهی-نگارش) توضیح داده شده است.
47+
- **گزارش اشکال در واژه‌یاب:** برای گزارش اشکالات در واژه‌یاب، از این قالب استفاده کنید.
4548

4649
## فرایند ترجمه
4750

@@ -52,7 +55,7 @@
5255

5356
3. متن `msgid` را ترجمه کنید و در `msgstr` وارد کنید.
5457

55-
4. برای پیدا کردن ترجمه‌ی مناسب برای کلمات و عبارات تخصصی، از [این](https://sepehr-rs.github.io/python-docs-fa-glossary/) پیوند به واژه‌یاب پایتون رفته و واژه/عبارت موردنظر خود را جست‌جو کنید.
58+
4. برای پیدا کردن ترجمه‌ی مناسب برای کلمات و عبارات تخصصی، از [این پیوند](http://python.github.io/python-docs-fa/glossary-searcher) به واژه‌یاب پایتون رفته و واژه/عبارت موردنظر خود را جست‌جو کنید.
5659

5760
5. **نشانه‌گذاری‌های Sphinx** مثل `` :class:`int` ``، `` :func:`repr` ``، `` :ref:`...` ``، `` ``code`` `` و **جای‌گذارها** مثل `%s` یا `{name}` را دقیقاً بدون تغییر نگه دارید؛ فقط متن اطراف آن‌ها ترجمه می‌شود. در `` :term:`target` ``، اگر عبارت داخل بک‌تیک با شناسه‌ی واژه‌نامه یکی است، می‌توانید آن را به شکل `` :term:`ترجمه <target>` `` بنویسید تا هم متن ترجمه‌شده نمایش داده شود و هم لینک درست کار کند؛ در این حالت فقط بخش نمایشی (پیش از `<`) ترجمه می‌شود و `target` داخل `<>` باید دقیقاً همان شناسه‌ی انگلیسی اصلی (بدون تغییر) باقی بماند، چون تغییر آن لینک را خراب می‌کند.
5861

@@ -190,5 +193,4 @@ python3 scripts/update_python_version.py v3.15.0 --keep-src
190193

191194
پیشنهادهای افزودن واژه‌ی جدید نیز پس از بررسی اولیه‌ی نگهدارندگان، در صورت نیاز از همان فرایند نظرسنجی توضیح داده شده در بالا استفاده خواهند کرد تا درباره‌ی پذیرش یا رد آن تصمیم‌گیری شود.
192195

193-
## گزارش اشکال در واژه‌یاب
194-
لطفا برای گزارش اشکال در واژه‌یاب به مخزن [python-docs-fa-glossary](https://github.com/sepehr-rs/python-docs-fa-glossary) مراجعه کنید.
196+
مشارکت‌ها به واژه‌نامه باید به پرونده‌ی `glossary.tsv` انجام شوند.

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
پیش از شروع، حتماً نگاهی به این پرونده‌ها بیندازید:
2020

2121
- [CONTRIBUTING.md](CONTRIBUTING.md) — راهنمای کامل مشارکت: انواع ایشیو، نکات نگارشی و تایپوگرافی فارسی، سطح رسمیت و لحن نوشتار، اندازه‌ی پول‌ریکوئست، فرایند بازبینی و تأیید پول‌ریکوئست، همگام‌سازی با نسخه‌های جدید پایتون (`scripts/update_python_version.py`)، پاک‌سازی رشته‌های `fuzzy` و نگهداری اعتبار مترجمان در سرآیند پرونده‌های `.po`.
22-
- [GLOSSARY.md](GLOSSARY.md) — واژه‌نامه‌ی معادل‌های فارسی اصطلاحات تخصصی؛ هنگام ترجمه باید به آن پایبند باشید.
22+
23+
- [واژه‌یاب](http://python.github.io/python-docs-fa/glossary-searcher) — ابزار جست‌وجوی واژگان تخصصی مستندات پایتون؛ هنگام ترجمه می‌توانید از آن برای یافتن معادل‌های فارسی ثبت‌شده و مشاهده‌ی نمونه‌های کاربرد واژگان در پیکره‌ی مستندات استفاده کنید.
24+
2325
- [TEAM.md](TEAM.md) — فهرست هماهنگ‌کننده‌ها، بازبین‌ها و مترجمان به‌همراه آمار مشارکت.
26+
2427
- [STATUS.md](STATUS.md) — جدول وضعیت ترجمه‌ی پرونده‌ها که به‌صورت خودکار به‌روزرسانی می‌شود.
2528

2629
### شاخه‌های نسخه

glossary-searcher/assets/logo.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Builds corpus.json and glossary.json from the python/python-docs-fa repository.
4+
5+
corpus.json shape (consumed by the glossary searcher site):
6+
[ { "msgid": "...", "msgstr": "...", "file": "library/functions.po", "line": 123 }, ... ]
7+
8+
glossary.json shape:
9+
[ { "en": "decorator", "fa": "دکوراتور، آراینده" }, ... ]
10+
11+
Usage:
12+
python build_corpus.py --repo-dir ./python-docs-fa --glossary-tsv ./glossary.tsv --out-dir ./data
13+
"""
14+
import argparse
15+
import csv
16+
import json
17+
import os
18+
import sys
19+
20+
try:
21+
import polib
22+
except ImportError:
23+
print("ERROR: polib is required. Install with: pip install polib", file=sys.stderr)
24+
sys.exit(1)
25+
26+
27+
def find_po_files(repo_dir):
28+
po_files = []
29+
for root, _dirs, files in os.walk(repo_dir):
30+
# skip VCS/meta directories
31+
if "/.git" in root or root.endswith("/.git"):
32+
continue
33+
for fname in files:
34+
if fname.endswith(".po"):
35+
full_path = os.path.join(root, fname)
36+
rel_path = os.path.relpath(full_path, repo_dir)
37+
po_files.append((full_path, rel_path))
38+
return sorted(po_files, key=lambda x: x[1])
39+
40+
41+
def parse_po_files(repo_dir):
42+
"""Parse every .po file into flattened msgid/msgstr corpus entries."""
43+
entries = []
44+
skipped = 0
45+
po_files = find_po_files(repo_dir)
46+
47+
if not po_files:
48+
print(f"WARNING: no .po files found under {repo_dir}", file=sys.stderr)
49+
50+
for full_path, rel_path in po_files:
51+
try:
52+
po = polib.pofile(full_path)
53+
except Exception as e:
54+
print(f"WARNING: failed to parse {rel_path}: {e}", file=sys.stderr)
55+
skipped += 1
56+
continue
57+
58+
for entry in po:
59+
# Skip obsolete, fuzzy, or empty-translation entries -- they
60+
# aren't useful corpus results and fuzzy ones are unreviewed.
61+
if entry.obsolete:
62+
continue
63+
if "fuzzy" in entry.flags:
64+
continue
65+
if not entry.msgid or not entry.msgstr:
66+
continue
67+
68+
entries.append(
69+
{
70+
"msgid": entry.msgid,
71+
"msgstr": entry.msgstr,
72+
"file": rel_path,
73+
"line": entry.linenum if hasattr(entry, "linenum") else 0,
74+
}
75+
)
76+
77+
print(
78+
f"Parsed {len(po_files)} .po files ({skipped} skipped), "
79+
f"{len(entries)} translated entries",
80+
file=sys.stderr,
81+
)
82+
return entries
83+
84+
85+
def parse_glossary_tsv(tsv_path):
86+
"""Parse the glossary TSV (English<TAB>Persian) into glossary.json entries."""
87+
entries = []
88+
with open(tsv_path, "r", encoding="utf-8") as f:
89+
reader = csv.reader(f, delimiter="\t")
90+
rows = list(reader)
91+
92+
if not rows:
93+
return entries
94+
95+
# Skip header row if it looks like one
96+
start_idx = 1 if rows[0][:2] == ["English", "Persian"] else 0
97+
98+
for row in rows[start_idx:]:
99+
if len(row) < 2:
100+
continue
101+
en, fa = row[0].strip(), row[1].strip()
102+
if en and fa:
103+
entries.append({"en": en, "fa": fa})
104+
105+
print(f"Parsed {len(entries)} glossary entries", file=sys.stderr)
106+
return entries
107+
108+
109+
def main():
110+
parser = argparse.ArgumentParser(description=__doc__)
111+
parser.add_argument(
112+
"--repo-dir", required=True, help="Path to the cloned python-docs-fa checkout"
113+
)
114+
parser.add_argument(
115+
"--glossary-tsv",
116+
required=True,
117+
help="Path to the glossary TSV file (English<TAB>Persian)",
118+
)
119+
parser.add_argument(
120+
"--out-dir",
121+
required=True,
122+
help="Directory to write corpus.json and glossary.json into",
123+
)
124+
args = parser.parse_args()
125+
126+
os.makedirs(args.out_dir, exist_ok=True)
127+
128+
corpus = parse_po_files(args.repo_dir)
129+
glossary = parse_glossary_tsv(args.glossary_tsv)
130+
131+
corpus_path = os.path.join(args.out_dir, "corpus.json")
132+
glossary_path = os.path.join(args.out_dir, "glossary.json")
133+
134+
with open(corpus_path, "w", encoding="utf-8") as f:
135+
json.dump(corpus, f, ensure_ascii=False, separators=(",", ":"))
136+
137+
with open(glossary_path, "w", encoding="utf-8") as f:
138+
json.dump(glossary, f, ensure_ascii=False, separators=(",", ":"))
139+
140+
print(
141+
f"Wrote {corpus_path} ({os.path.getsize(corpus_path):,} bytes)", file=sys.stderr
142+
)
143+
print(
144+
f"Wrote {glossary_path} ({os.path.getsize(glossary_path):,} bytes)",
145+
file=sys.stderr,
146+
)
147+
148+
149+
if __name__ == "__main__":
150+
main()

0 commit comments

Comments
 (0)