diff --git a/az_locale/locale/setup_locale.py b/az_locale/locale/setup_locale.py index 04ddbbd..0cb82ef 100644 --- a/az_locale/locale/setup_locale.py +++ b/az_locale/locale/setup_locale.py @@ -9,6 +9,7 @@ def setup_locale(): locale_dir = os.path.join(bench_path, "apps", "az_locale", "az_locale", "locale") copied = 0 + merged = 0 skipped = 0 for entry in sorted(os.listdir(locale_dir)): @@ -43,5 +44,60 @@ def setup_locale(): except Exception as e: print(f"[az_locale] Error copying to {dest_file}: {e}") skipped += 1 + continue - print(f"[az_locale] Locale setup complete: {copied} file(s) copied, {skipped} skipped") + extras_file = os.path.join(app_dir, "extras.po") + if os.path.exists(extras_file): + added = _merge_extras(dest_file, extras_file) + if added is not None: + print(f"[az_locale] Merged {added} extras into {app_name}/{lang}.po") + merged += added + + print( + f"[az_locale] Locale setup complete: {copied} file(s) copied, " + f"{merged} extras merged, {skipped} skipped" + ) + + +def _merge_extras(dest_file, extras_file): + """Overlay msgid/msgstr pairs from `extras_file` onto `dest_file`. + + Extras wins on conflict and revives any matching obsolete entries + (those marked `#~` by msgmerge after upstream .pot regeneration). + Returns the count of merged messages, or None on error. + """ + try: + from babel.messages.pofile import read_po, write_po + except ImportError as e: + print(f"[az_locale] Error: babel.messages not available ({e}), skipping extras merge") + return None + + try: + with open(dest_file, "rb") as f: + dest = read_po(f) + with open(extras_file, "rb") as f: + extras = read_po(f) + except Exception as e: + print(f"[az_locale] Error reading PO files for merge ({dest_file}): {e}") + return None + + count = 0 + for msg in extras: + if not msg.id: + continue + # Resurrect from obsolete section if upstream pot dropped this msgid. + try: + dest.obsolete.pop(msg.id, None) + except AttributeError: + pass + dest[msg.id] = msg + count += 1 + + try: + with open(dest_file, "wb") as f: + write_po(f, dest, sort_output=True) + except Exception as e: + print(f"[az_locale] Error writing merged PO file {dest_file}: {e}") + return None + + return count diff --git a/az_locale/locale/translations_az/erpnext/extras.po b/az_locale/locale/translations_az/erpnext/extras.po new file mode 100644 index 0000000..e2530e8 --- /dev/null +++ b/az_locale/locale/translations_az/erpnext/extras.po @@ -0,0 +1,109 @@ +msgid "" +msgstr "" +"Project-Id-Version: az_locale extras\n" +"Language: az\n" +"Language-Team: Azerbaijani\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Number Card / Dashboard Chart / Dashboard fixture labels — data, not source code, +#. so not extracted into upstream .pot. Rendered via __() in +#. frappe/public/js/frappe/widgets/base_widget.js:102. + +# === Number Cards === +msgid "Open Opportunity" +msgstr "Açıq Fürsət" + +msgid "Active Customers" +msgstr "Aktiv Müştərilər" + +msgid "Active Suppliers" +msgstr "Aktiv Təchizatçılar" + +msgid "Annual Purchase" +msgstr "İllik Satınalma" + +msgid "Annual Sales" +msgstr "İllik Satış" + +msgid "Average Sales Order Value" +msgstr "Orta Satış Sifarişi Dəyəri" + +msgid "Sales Orders Count" +msgstr "Satış Sifarişlərinin Sayı" + +msgid "Timesheet Working Hours" +msgstr "İş Saatları Cədvəli" + +msgid "Total Incoming Bills" +msgstr "Cəmi Daxil Olan Hesablar" + +msgid "Total Incoming Payment" +msgstr "Cəmi Daxil Olan Ödəniş" + +msgid "Total Outgoing Bills" +msgstr "Cəmi Çıxan Hesablar" + +msgid "Total Outgoing Payment" +msgstr "Cəmi Çıxan Ödəniş" + +# === Dashboard Charts === +msgid "Accounts Payable Ageing" +msgstr "Ödəniləcək Hesabların Yaşlanması" + +msgid "Accounts Receivable Ageing" +msgstr "Alınacaq Hesabların Yaşlanması" + +msgid "Delivery Trends" +msgstr "Çatdırılma Trendləri" + +msgid "Incoming Bills (Purchase Invoice)" +msgstr "Daxil Olan Hesablar (Satınalma Fakturası)" + +msgid "Incoming Leads" +msgstr "Daxil Olan Potensiyal Müştərilər" + +msgid "Item Shortage Summary" +msgstr "Element Çatışmazlığı Xülasəsi" + +msgid "Item-wise Annual Sales" +msgstr "Elementlər üzrə İllik Satış" + +msgid "Location-wise Asset Value" +msgstr "Ərazi üzrə Aktiv Dəyəri" + +msgid "Material Request Analysis" +msgstr "Material Sorğusu Təhlili" + +msgid "Oldest Items" +msgstr "Ən Köhnə Elementlər" + +msgid "Opportunities via Campaigns" +msgstr "Kampaniyalar üzrə Fürsətlər" + +msgid "Opportunity Trends" +msgstr "Fürsət Trendləri" + +msgid "Outgoing Bills (Sales Invoice)" +msgstr "Çıxan Hesablar (Satış Fakturası)" + +msgid "Territory Wise Opportunity Count" +msgstr "Ərazi üzrə Fürsətlərin Sayı" + +msgid "Territory Wise Sales" +msgstr "Ərazi üzrə Satış" + +msgid "Top Customers" +msgstr "Ən Yaxşı Müştərilər" + +msgid "Top Suppliers" +msgstr "Ən Yaxşı Təchizatçılar" + +msgid "Warehouse wise Stock Value" +msgstr "Anbar üzrə Ehtiyat Dəyəri" + +# === Dashboard parents === +msgid "Project" +msgstr "Layihə" diff --git a/az_locale/locale/translations_az/frappe/extras.po b/az_locale/locale/translations_az/frappe/extras.po new file mode 100644 index 0000000..9024875 --- /dev/null +++ b/az_locale/locale/translations_az/frappe/extras.po @@ -0,0 +1,15 @@ +msgid "" +msgstr "" +"Project-Id-Version: az_locale extras\n" +"Language: az\n" +"Language-Team: Azerbaijani\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Hardcoded literal at frappe/public/js/frappe/list/list_filter.js:88 +#. wrapped by __() only at render time (line 162), so not picked up by +#. bench generate-pot-file. Provide translation here so __() finds it. +msgid "Save Current Filter" +msgstr "Cari filtri yadda saxla" diff --git a/az_locale/locale/translations_ru/erpnext/extras.po b/az_locale/locale/translations_ru/erpnext/extras.po new file mode 100644 index 0000000..8779047 --- /dev/null +++ b/az_locale/locale/translations_ru/erpnext/extras.po @@ -0,0 +1,109 @@ +msgid "" +msgstr "" +"Project-Id-Version: az_locale extras\n" +"Language: ru\n" +"Language-Team: Russian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#. Number Card / Dashboard Chart / Dashboard fixture labels — data, not source code, +#. so not extracted into upstream .pot. Rendered via __() in +#. frappe/public/js/frappe/widgets/base_widget.js:102. + +# === Number Cards === +msgid "Open Opportunity" +msgstr "Открытые возможности" + +msgid "Active Customers" +msgstr "Активные клиенты" + +msgid "Active Suppliers" +msgstr "Активные поставщики" + +msgid "Annual Purchase" +msgstr "Годовые закупки" + +msgid "Annual Sales" +msgstr "Годовые продажи" + +msgid "Average Sales Order Value" +msgstr "Средняя сумма заказа на продажу" + +msgid "Sales Orders Count" +msgstr "Количество заказов на продажу" + +msgid "Timesheet Working Hours" +msgstr "Рабочие часы по табелю" + +msgid "Total Incoming Bills" +msgstr "Всего входящих счетов" + +msgid "Total Incoming Payment" +msgstr "Всего входящих платежей" + +msgid "Total Outgoing Bills" +msgstr "Всего исходящих счетов" + +msgid "Total Outgoing Payment" +msgstr "Всего исходящих платежей" + +# === Dashboard Charts === +msgid "Accounts Payable Ageing" +msgstr "Старение кредиторской задолженности" + +msgid "Accounts Receivable Ageing" +msgstr "Старение дебиторской задолженности" + +msgid "Delivery Trends" +msgstr "Тренды доставок" + +msgid "Incoming Bills (Purchase Invoice)" +msgstr "Входящие счета (Счёт на покупку)" + +msgid "Incoming Leads" +msgstr "Входящие лиды" + +msgid "Item Shortage Summary" +msgstr "Сводка по дефициту позиций" + +msgid "Item-wise Annual Sales" +msgstr "Годовые продажи по позициям" + +msgid "Location-wise Asset Value" +msgstr "Стоимость активов по локациям" + +msgid "Material Request Analysis" +msgstr "Анализ заявок на материалы" + +msgid "Oldest Items" +msgstr "Старейшие позиции" + +msgid "Opportunities via Campaigns" +msgstr "Возможности по кампаниям" + +msgid "Opportunity Trends" +msgstr "Тренды возможностей" + +msgid "Outgoing Bills (Sales Invoice)" +msgstr "Исходящие счета (Счёт на продажу)" + +msgid "Territory Wise Opportunity Count" +msgstr "Количество возможностей по территориям" + +msgid "Territory Wise Sales" +msgstr "Продажи по территориям" + +msgid "Top Customers" +msgstr "Топ клиентов" + +msgid "Top Suppliers" +msgstr "Топ поставщиков" + +msgid "Warehouse wise Stock Value" +msgstr "Стоимость склада по складам" + +# === Dashboard parents === +msgid "Project" +msgstr "Проект" diff --git a/az_locale/locale/translations_ru/frappe/extras.po b/az_locale/locale/translations_ru/frappe/extras.po new file mode 100644 index 0000000..db53ace --- /dev/null +++ b/az_locale/locale/translations_ru/frappe/extras.po @@ -0,0 +1,15 @@ +msgid "" +msgstr "" +"Project-Id-Version: az_locale extras\n" +"Language: ru\n" +"Language-Team: Russian\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#. Hardcoded literal at frappe/public/js/frappe/list/list_filter.js:88 +#. wrapped by __() only at render time (line 162), so not picked up by +#. bench generate-pot-file. Provide translation here so __() finds it. +msgid "Save Current Filter" +msgstr "Сохранить текущий фильтр"