Skip to content

Commit 0fcc267

Browse files
committed
Fix virgules in code patterns
- Replace Virgules (،) with commas (,) in code patterns: - Function calls and parameters - List literals - Function definitions - Class definitions - Dictionary literals - Preserve virgules in regular translated text - Add script to detect and fix comma issues in .po files
1 parent fc7fa2d commit 0fcc267

16 files changed

Lines changed: 678 additions & 570 deletions

library/functions.po

Lines changed: 60 additions & 60 deletions
Large diffs are not rendered by default.

library/stdtypes.po

Lines changed: 130 additions & 130 deletions
Large diffs are not rendered by default.

scripts/fix_commas.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import polib
2+
import re
3+
import sys
4+
import os
5+
import glob
6+
7+
def is_code_pattern(text: str) -> bool:
8+
"""
9+
Check if the text matches common code patterns where virgules should be converted to commas.
10+
"""
11+
code_patterns = [
12+
r'\([^)]*،[^)]*\)', # Function calls with params: foo(a، b)
13+
r'\[[^]]*،[^]]*\]', # List literals: [1، 2، 3]
14+
r'def\s+\w+\s*\([^)]*،[^)]*\)', # Function definitions
15+
r'class\s+\w+\s*\([^)]*،[^)]*\)', # Class definitions
16+
r'\{[^}]*،[^}]*\}', # Dict literals
17+
]
18+
19+
return any(re.search(pattern, text) for pattern in code_patterns)
20+
21+
def fix_virgules_in_code(entry):
22+
"""
23+
Fix virgules in code sections while preserving them in regular text.
24+
Returns True if any changes were made.
25+
"""
26+
if not isinstance(entry.msgstr, str):
27+
return False
28+
29+
modified = False
30+
31+
# If the text appears to be code, replace virgules
32+
if is_code_pattern(entry.msgstr):
33+
new_text = entry.msgstr
34+
35+
# Handle parentheses content
36+
def replace_in_parens(match):
37+
return match.group().replace('،', ',')
38+
39+
# Replace virgules in various code patterns
40+
patterns_and_replacements = [
41+
(r'\([^)]+\)', replace_in_parens), # Function params
42+
(r'\[[^]]+\]', replace_in_parens), # List literals
43+
(r'\'[^\']+\'', replace_in_parens), # Single quoted strings
44+
(r'"[^"]+"', replace_in_parens), # Double quoted strings
45+
(r'\{[^}]+\}', replace_in_parens), # Dict literals
46+
]
47+
48+
for pattern, replacement in patterns_and_replacements:
49+
new_text = re.sub(pattern, replacement, new_text)
50+
51+
if new_text != entry.msgstr:
52+
entry.msgstr = new_text
53+
modified = True
54+
55+
return modified
56+
57+
def process_po_file(po_file):
58+
"""Process a single PO file."""
59+
try:
60+
po = polib.pofile(po_file)
61+
fixed_entries = 0
62+
63+
for entry in po:
64+
if fix_virgules_in_code(entry):
65+
fixed_entries += 1
66+
67+
if fixed_entries > 0:
68+
po.save()
69+
print(f"Fixed {fixed_entries} entries in {po_file}")
70+
71+
except Exception as e:
72+
print(f"Error processing {po_file}: {e}")
73+
74+
def collect_po_files(path):
75+
"""
76+
Given a path (wildcard, file, or directory), return a list of .po files.
77+
"""
78+
files = []
79+
if os.path.isfile(path) and path.endswith('.po'):
80+
files.append(path)
81+
elif os.path.isdir(path):
82+
for root, _, filenames in os.walk(path):
83+
for filename in filenames:
84+
if filename.endswith('.po'):
85+
files.append(os.path.join(root, filename))
86+
else:
87+
# Handle wildcards
88+
for p in glob.glob(path, recursive=True):
89+
if os.path.isfile(p) and p.endswith('.po'):
90+
files.append(p)
91+
return files
92+
93+
def main(paths):
94+
processed_files = set()
95+
for path in paths:
96+
for po_file in collect_po_files(path):
97+
if po_file not in processed_files:
98+
process_po_file(po_file)
99+
processed_files.add(po_file)
100+
101+
if not processed_files:
102+
print("No PO files found.")
103+
104+
if __name__ == "__main__":
105+
if len(sys.argv) < 2:
106+
print("Usage: python fix_code_virgules.py <po-file|directory|glob-pattern> [additional paths...]")
107+
sys.exit(1)
108+
main(sys.argv[1:])

tutorial/appendix.po

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ msgstr ""
100100
"کند. در حالت تعاملی، سپس به اعلان اولیه باز می گردد. هنگامی که ورودی از یک "
101101
"فایل می آید، پس از چاپ ردیابی پشته، با وضعیت خروج غیر صفر خارج می شود. "
102102
"(استثناهایی که توسط یک بند :keyword:`except` در دستور :keyword:`try` استفاده"
103-
" می شود، در این زمینه خطا نیستند.) برخی از خطاها بدون قید و شرط کشنده هستند "
103+
" می شود, در این زمینه خطا نیستند.) برخی از خطاها بدون قید و شرط کشنده هستند "
104104
"و باعث خروجی با وضعیت خروج غیر صفر می شوند. این در مورد ناهماهنگی های داخلی "
105105
"و برخی موارد تمام شدن حافظه صدق می کند. همه پیام های خطا در جریان خطای "
106106
"استاندارد نوشته می شوند. خروجی عادی از دستورات اجرا شده در خروجی استاندارد "

tutorial/classes.po

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ msgstr ""
8383
"کلاس ها خود شی هستند. این امر معنایی را برای وارد کردن و تغییر نام فراهم می"
8484
" کند. برخلاف C++ و Modula-3، انواع داخلی می توانند به عنوان کلاس های پایه "
8585
"برای توسعه توسط کاربر استفاده شوند. همچنین، مانند C++، اکثر عملگرهای داخلی "
86-
"با نحو خاص (عملگرهای حسابی، اشتراک و غیره) می‌توانند برای نمونه‌های کلاس "
86+
"با نحو خاص (عملگرهای حسابی, اشتراک و غیره) می‌توانند برای نمونه‌های کلاس "
8787
"دوباره تعریف شوند."
8888

8989
#: tutorial/classes.rst:34
@@ -94,9 +94,9 @@ msgid ""
9494
"since its object-oriented semantics are closer to those of Python than C++, "
9595
"but I expect that few readers have heard of it.)"
9696
msgstr ""
97-
"(به دلیل نداشتن اصطلاحات پذیرفته شده جهانی برای صحبت در مورد کلاس ها، من "
97+
"(به دلیل نداشتن اصطلاحات پذیرفته شده جهانی برای صحبت در مورد کلاس ها, من "
9898
"گهگاه از اصطلاحات Smalltalk و C++ استفاده می کنم. از اصطلاحات Modula-3 "
99-
"استفاده می کنم، زیرا معنایی شی گرا آن به زبان پایتون نزدیکتر از C++ است، اما"
99+
"استفاده می کنم, زیرا معنایی شی گرا آن به زبان پایتون نزدیکتر از C++ است, اما"
100100
" انتظار دارم که تعداد کمی از خوانندگان درباره آن چیزی شنیده باشند.)"
101101

102102
#: tutorial/classes.rst:43
@@ -123,7 +123,7 @@ msgstr ""
123123
"اشیاء دارای فردیت هستند و نام های متعدد (در حوزه های متعدد) را می توان به یک"
124124
" شی محدود کرد. این در زبان های دیگر به نام مستعار شناخته می شود. معمولاً "
125125
"در نگاه اول پایتون به این موضوع توجهی نمی‌شود، و می‌توان با خیال راحت از "
126-
"انواع اولیه تغییرناپذیر (اعداد، رشته‌ها، تاپل‌ها) صرف نظر کرد. با این حال، "
126+
"انواع اولیه تغییرناپذیر (اعداد, رشته‌ها, تاپل‌ها) صرف نظر کرد. با این حال، "
127127
"نام مستعار یک اثر احتمالاً شگفت‌انگیز بر معنایی کد پایتون شامل اشیاء قابل "
128128
"تغییر مانند فهرست‌ها، دیکشنری‌ها و بسیاری از انواع دیگر دارد. این معمولاً به"
129129
" نفع برنامه استفاده می شود، زیرا نام مستعار در برخی موارد مانند اشاره گر عمل"
@@ -253,7 +253,7 @@ msgid ""
253253
msgstr ""
254254
"فضای نام محلی برای یک تابع هنگام فراخوانی تابع ایجاد می‌شود و زمانی که تابع "
255255
"استثنایی را که در تابع مدیریت نمی‌شود برمی‌گرداند یا ایجاد می‌کند، حذف "
256-
"می‌شود. (در واقع، فراموش کردن راه بهتری برای توصیف آنچه در واقع اتفاق "
256+
"می‌شود. (در واقع, فراموش کردن راه بهتری برای توصیف آنچه در واقع اتفاق "
257257
"می‌افتد خواهد بود.) البته، فراخوان‌های بازگشتی هر کدام فضای نام محلی خود را "
258258
"دارند."
259259

@@ -354,7 +354,7 @@ msgstr ""
354354
"نام مستعار تابع نامیده می شود. از سوی دیگر، جستجوی واقعی نام ها به صورت "
355355
"پویا و در زمان اجرا انجام می شود --- با این حال، تعریف زبان به سمت وضوح نام "
356356
"ثابت در زمان \"کامپایل\" در حال تکامل است، بنابراین به وضوح نام پویا تکیه "
357-
"نکنید! (در واقع، متغیرهای محلی قبلاً به صورت ایستا تعیین شده اند.)"
357+
"نکنید! (در واقع, متغیرهای محلی قبلاً به صورت ایستا تعیین شده اند.)"
358358

359359
#: tutorial/classes.rst:146
360360
#, fuzzy
@@ -446,14 +446,14 @@ msgstr ""
446446
"\n"
447447
" هرزنامه = \"تست اسپم\"\n"
448448
" do_local()\n"
449-
" چاپ (\"پس از انتساب محلی:\"، هرزنامه)\n"
449+
" چاپ (\"پس از انتساب محلی:\", هرزنامه)\n"
450450
" do_nonlocal()\n"
451-
" چاپ (\"پس از انتساب غیر محلی:\"، هرزنامه)\n"
451+
" چاپ (\"پس از انتساب غیر محلی:\", هرزنامه)\n"
452452
" do_global()\n"
453-
" چاپ (\"پس از انتساب جهانی:\"، هرزنامه)\n"
453+
" چاپ (\"پس از انتساب جهانی:\", هرزنامه)\n"
454454
"\n"
455455
"scope_test()\n"
456-
"چاپ (\"در محدوده جهانی:\"، هرزنامه)"
456+
"چاپ (\"در محدوده جهانی:\", هرزنامه)"
457457

458458
#: tutorial/classes.rst:191
459459
#, fuzzy
@@ -739,9 +739,9 @@ msgstr ""
739739
"... self.r = realpart\n"
740740
"... self.i = imagpart\n"
741741
"...\n"
742-
">>> x = پیچیده (3.0، -4.5)\n"
742+
">>> x = پیچیده (3.0, -4.5)\n"
743743
">>> x.r، x.i\n"
744-
"(3.0، -4.5)"
744+
"(3.0, -4.5)"
745745

746746
#: tutorial/classes.rst:322
747747
#, fuzzy
@@ -949,7 +949,7 @@ msgstr ""
949949
"\n"
950950
" نوع = 'canine' # متغیر کلاس به اشتراک گذاشته شده توسط همه نمونه ها\n"
951951
"\n"
952-
" def __init__(خود، نام):\n"
952+
" def __init__(خود, نام):\n"
953953
" self.name = نام # متغیر نمونه منحصر به فرد برای هر نمونه\n"
954954
"\n"
955955
">>> d = سگ ('Fido')\n"
@@ -1002,7 +1002,7 @@ msgstr ""
10021002
"\n"
10031003
" tricks = [] # استفاده اشتباه از متغیر کلاس\n"
10041004
"\n"
1005-
" def __init__(خود، نام):\n"
1005+
" def __init__(خود, نام):\n"
10061006
" self.name = نام\n"
10071007
"\n"
10081008
" def add_trick(self, trick):\n"
@@ -1013,7 +1013,7 @@ msgstr ""
10131013
">>> d.add_trick ('roll over')\n"
10141014
">>> e.add_trick ('play dead')\n"
10151015
">>> d.tricks # به طور غیرمنتظره توسط همه سگ ها به اشتراک گذاشته شد\n"
1016-
"['غلت کردن'، 'مرده بازی']"
1016+
"['غلت کردن', 'مرده بازی']"
10171017

10181018
#: tutorial/classes.rst:445
10191019
#, fuzzy
@@ -1043,7 +1043,7 @@ msgid ""
10431043
msgstr ""
10441044
"سگ کلاس:\n"
10451045
"\n"
1046-
" def __init__(خود، نام):\n"
1046+
" def __init__(خود, نام):\n"
10471047
" self.name = نام\n"
10481048
" self.tricks = [] # یک لیست خالی جدید برای هر سگ ایجاد می کند\n"
10491049
"\n"
@@ -1093,11 +1093,11 @@ msgstr ""
10931093
"... منطقه = \"غرب\"\n"
10941094
"...\n"
10951095
">>> w1 = انبار()\n"
1096-
">>> چاپ (w1.purpose، w1.region)\n"
1096+
">>> چاپ (w1.purpose, w1.region)\n"
10971097
"انباری غرب\n"
10981098
">>> w2 = انبار()\n"
10991099
">>> w2.region = 'شرق'\n"
1100-
">>> چاپ (w2.purpose، w2.region)\n"
1100+
">>> چاپ (w2.purpose, w2.region)\n"
11011101
"ذخیره سازی شرق"
11021102

11031103
#: tutorial/classes.rst:488
@@ -1115,7 +1115,7 @@ msgstr ""
11151115
" یک شی ارجاع داده شوند. به عبارت دیگر، کلاس ها برای پیاده سازی انواع داده "
11161116
"های انتزاعی خالص قابل استفاده نیستند. در واقع، هیچ چیز در پایتون امکان "
11171117
"اعمال مخفی کردن داده ها را فراهم نمی کند --- همه اینها بر اساس قرارداد است."
1118-
" (از سوی دیگر، پیاده‌سازی پایتون که به زبان C نوشته شده است، می‌تواند "
1118+
" (از سوی دیگر, پیاده‌سازی پایتون که به زبان C نوشته شده است, می‌تواند "
11191119
"جزئیات پیاده‌سازی را کاملاً مخفی کند و در صورت لزوم دسترسی به یک شی را کنترل"
11201120
" کند؛ این می‌تواند توسط پسوندهای پایتون نوشته شده در C استفاده شود.)"
11211121

@@ -1192,7 +1192,7 @@ msgid ""
11921192
" h = g"
11931193
msgstr ""
11941194
"# تابعی که خارج از کلاس تعریف شده است\n"
1195-
"def f1 (خود، x، y):\n"
1195+
"def f1 (خود, x, y):\n"
11961196
" بازگشت حداقل (x, x+y)\n"
11971197
"\n"
11981198
"کلاس C:\n"
@@ -1514,7 +1514,7 @@ msgstr ""
15141514
"بیش از یک بار، الگوریتم پویا ترتیب جستجو را به گونه ای خطی می کند که ترتیب "
15151515
"چپ به راست مشخص شده در هر کلاس را حفظ می کند، که هر والد را فقط یک بار "
15161516
"فراخوانی می کند، و این یکنواخت است (به این معنی که یک کلاس می تواند بدون "
1517-
"تأثیر بر ترتیب اولویت والدینش، زیر طبقه بندی شود). در مجموع، این ویژگی ها "
1517+
"تأثیر بر ترتیب اولویت والدینش, زیر طبقه بندی شود). در مجموع، این ویژگی ها "
15181518
"طراحی کلاس های قابل اعتماد و توسعه پذیر با ارث چندگانه را ممکن می سازد. "
15191519
"برای جزئیات بیشتر، به :ref:`python_2.3_mro` مراجعه کنید."
15201520

@@ -1536,7 +1536,7 @@ msgstr ""
15361536
"متغیرهای نمونه \"خصوصی\" که جز از داخل یک شی قابل دسترسی نیستند، در پایتون "
15371537
"وجود ندارند. با این حال، قراردادی وجود دارد که اکثر کدهای پایتون از آن "
15381538
"پیروی می کنند: نامی که پیشوند آن زیرخط است (مثلاً ``_spam``) باید به عنوان "
1539-
"بخشی غیرعمومی از API در نظر گرفته شود (خواه یک تابع، یک متد یا یک عضو داده "
1539+
"بخشی غیرعمومی از API در نظر گرفته شود (خواه یک تابع, یک متد یا یک عضو داده "
15401540
"باشد). باید جزییات اجرایی در نظر گرفته شود و بدون اطلاع قبلی قابل تغییر "
15411541
"باشد."
15421542

@@ -1555,7 +1555,7 @@ msgstr ""
15551555
"از آنجایی که یک مورد استفاده معتبر برای اعضای کلاس خصوصی وجود دارد (یعنی "
15561556
"برای جلوگیری از تداخل نام نام‌ها با نام‌هایی که توسط کلاس‌های فرعی تعریف "
15571557
"شده‌اند)، پشتیبانی محدودی از چنین مکانیزمی به نام :dfn:`name mangling` وجود "
1558-
"دارد. هر شناسه ای از فرم ``__spam`` (حداقل دو زیرخط اصلی، حداکثر یک زیرخط "
1558+
"دارد. هر شناسه ای از فرم ``__spam`` (حداقل دو زیرخط اصلی, حداکثر یک زیرخط "
15591559
"آخر) به صورت متنی با ``_classname__spam`` جایگزین می شود، که در آن "
15601560
"``classname`` نام کلاس فعلی با زیرخط(های) ابتدایی حذف شده است. این اختلاط "
15611561
"بدون توجه به موقعیت نحوی شناسه انجام می شود، تا زمانی که در تعریف یک کلاس رخ"
@@ -1602,22 +1602,22 @@ msgid ""
16021602
" self.items_list.append(item)"
16031603
msgstr ""
16041604
"نقشه برداری کلاس:\n"
1605-
" def __init__(خود، قابل تکرار):\n"
1605+
" def __init__(خود, قابل تکرار):\n"
16061606
" self.items_list = []\n"
16071607
" self.__update (قابل تکرار)\n"
16081608
"\n"
1609-
" به روز رسانی def (خود، قابل تکرار):\n"
1609+
" به روز رسانی def (خود, قابل تکرار):\n"
16101610
" برای مورد در تکرارپذیر:\n"
16111611
" self.items_list.append(item)\n"
16121612
"\n"
16131613
" __update = به روز رسانی # کپی خصوصی روش اصلی () update\n"
16141614
"\n"
16151615
"کلاس MappingSubclass(Mapping):\n"
16161616
"\n"
1617-
" به روز رسانی def (خود، کلیدها، مقادیر):\n"
1617+
" به روز رسانی def (خود, کلیدها, مقادیر):\n"
16181618
" # امضای جدیدی برای به‌روزرسانی () ارائه می‌کند\n"
16191619
" # اما نمی شکند __init__()\n"
1620-
" برای مورد در zip (کلیدها، مقادیر):\n"
1620+
" برای مورد در zip (کلیدها, مقادیر):\n"
16211621
" self.items_list.append(item)"
16221622

16231623
#: tutorial/classes.rst:718
@@ -1703,7 +1703,7 @@ msgid ""
17031703
">>> john.salary\n"
17041704
"1000"
17051705
msgstr ""
1706-
">>> جان = کارمند ('جان'، 'آزمایشگاه کامپیوتر'، 1000)\n"
1706+
">>> جان = کارمند ('جان', 'آزمایشگاه کامپیوتر', 1000)\n"
17071707
">>> john.dept\n"
17081708
"\"آزمایشگاه کامپیوتر\"\n"
17091709
">>> john.salary\n"
@@ -1767,16 +1767,16 @@ msgid ""
17671767
"for line in open(\"myfile.txt\"):\n"
17681768
" print(line, end='')"
17691769
msgstr ""
1770-
"برای عنصر در [1، 2، 3]:\n"
1770+
"برای عنصر در [1, 2, 3]:\n"
17711771
" چاپ (عنصر)\n"
1772-
"برای عنصر در (1، 2، 3):\n"
1772+
"برای عنصر در (1, 2, 3):\n"
17731773
" چاپ (عنصر)\n"
17741774
"برای کلید در {'one':1, 'two':2}:\n"
17751775
" چاپ (کلید)\n"
17761776
"برای کاراکتر در \"123\":\n"
17771777
" چاپ (کاراکتر)\n"
17781778
"برای خط در open (\"myfile.txt\"):\n"
1779-
" چاپ (خط، پایان='')"
1779+
" چاپ (خط, پایان='')"
17801780

17811781
#: tutorial/classes.rst:798
17821782
#, fuzzy
@@ -1870,7 +1870,7 @@ msgid ""
18701870
msgstr ""
18711871
"کلاس معکوس:\n"
18721872
" \"\"\"تکرار کننده برای حلقه زدن روی یک دنباله به عقب.\"\"\"\n"
1873-
" def __init__(خود، داده):\n"
1873+
" def __init__(خود, داده):\n"
18741874
" self.data = داده\n"
18751875
" self.index = len(داده)\n"
18761876
"\n"
@@ -2054,11 +2054,11 @@ msgstr ""
20542054
"\n"
20552055
">>> unique_words = set( کلمه به خط در صفحه به کلمه در line.split())\n"
20562056
"\n"
2057-
">>> valedictorian = حداکثر ((student.gpa، student.name) برای دانش آموزان فارغ التحصیل)\n"
2057+
">>> valedictorian = حداکثر ((student.gpa, student.name) برای دانش آموزان فارغ التحصیل)\n"
20582058
"\n"
20592059
">>> داده = \"گلف\"\n"
20602060
">>> لیست(داده[i] برای i در محدوده(len(داده)-1، -1، -1))\n"
2061-
"['f'، 'l'، 'o'، 'g']"
2061+
"['f', 'l', 'o', 'g']"
20622062

20632063
#: tutorial/classes.rst:932
20642064
#, fuzzy

0 commit comments

Comments
 (0)