diff --git a/az_locale/hooks.py b/az_locale/hooks.py index 171bd4b..97154d3 100644 --- a/az_locale/hooks.py +++ b/az_locale/hooks.py @@ -52,7 +52,10 @@ after_migrate = "az_locale.install.after_install" # include js in doctype views # doctype_js = {"doctype" : "public/js/doctype.js"} -# doctype_list_js = {"doctype" : "public/js/doctype_list.js"} +doctype_list_js = { + "Supplier Scorecard Standing": "public/js/supplier_scorecard_standing_list.js", + "Supplier Scorecard Variable": "public/js/supplier_scorecard_variable_list.js", +} # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} diff --git a/az_locale/install.py b/az_locale/install.py index 1a82423..b8cf1c2 100644 --- a/az_locale/install.py +++ b/az_locale/install.py @@ -2,6 +2,7 @@ from az_locale.locale.setup_locale import setup_locale from az_locale.locale.setup_chart import setup_chart from az_locale.locale.update_country import update_country from az_locale.locale.update_tax import update_tax +from az_locale.locale.update_doctype import update_doctype def after_install(): @@ -9,3 +10,4 @@ def after_install(): setup_chart() update_country() update_tax() + update_doctype() diff --git a/az_locale/locale/setup_locale.py b/az_locale/locale/setup_locale.py index 0cb82ef..eac6549 100644 --- a/az_locale/locale/setup_locale.py +++ b/az_locale/locale/setup_locale.py @@ -53,12 +53,38 @@ def setup_locale(): print(f"[az_locale] Merged {added} extras into {app_name}/{lang}.po") merged += added + # Frappe's runtime reads compiled .mo files (sites/assets/locale/), + # not the .po we just wrote. Recompile with force=True so our changes + # take effect — the standard build/migrate compile skips by mtime and + # would otherwise keep serving a stale .mo. + _compile_mo(app_name, lang) + print( f"[az_locale] Locale setup complete: {copied} file(s) copied, " f"{merged} extras merged, {skipped} skipped" ) +def _compile_mo(app_name, lang): + """Compile the app's .po into the runtime .mo under sites/assets/locale/. + + Frappe serves translations from compiled .mo files, so a freshly written .po + is invisible until recompiled. We force it because _compile_translation skips + when an older .mo looks newer than the .po by mtime. + """ + try: + from frappe.gettext.translate import _compile_translation + except ImportError as e: + print(f"[az_locale] Error: cannot import compiler ({e}), skipping .mo compile") + return + + try: + _compile_translation(app_name, lang, force=True) + print(f"[az_locale] Compiled {app_name}/{lang}.mo") + except Exception as e: + print(f"[az_locale] Error compiling {app_name}/{lang}.mo: {e}") + + def _merge_extras(dest_file, extras_file): """Overlay msgid/msgstr pairs from `extras_file` onto `dest_file`. diff --git a/az_locale/locale/translations_az/erpnext/extras.po b/az_locale/locale/translations_az/erpnext/extras.po index e2530e8..36eca1f 100644 --- a/az_locale/locale/translations_az/erpnext/extras.po +++ b/az_locale/locale/translations_az/erpnext/extras.po @@ -107,3 +107,92 @@ msgstr "Anbar üzrə Ehtiyat Dəyəri" # === Dashboard parents === msgid "Project" msgstr "Layihə" + +#. Supplier Scorecard Standing names — DocType fixture data (autoname=field:standing_name), +#. translated via Link fields once translated_doctype=1 is forced on the DocType +#. (see az_locale/locale/update_doctype.py). +# === Supplier Scorecard Standings === +msgid "Very Poor" +msgstr "Çox Zəif" + +msgid "Poor" +msgstr "Zəif" + +msgid "Average" +msgstr "Orta" + +msgid "Good" +msgstr "Yaxşı" + +msgid "Very Good" +msgstr "Çox Yaxşı" + +msgid "Excellent" +msgstr "Əla" + +#. Supplier Scorecard Variable labels — DocType fixture data (autoname=field:variable_label), +#. translated via Link fields once translated_doctype=1 is forced on the DocType +#. (see az_locale/locale/update_doctype.py). +# === Supplier Scorecard Variables === +msgid "# of On Time Shipments" +msgstr "Vaxtında Çatdırılmaların Sayı" + +msgid "Cost of Delayed Shipments" +msgstr "Gecikmiş Çatdırılmaların Dəyəri" + +msgid "Cost of On Time Shipments" +msgstr "Vaxtında Çatdırılmaların Dəyəri" + +msgid "RFQ Response Days" +msgstr "Qiymət Sorğusuna Cavab Günləri" + +msgid "RFQ Total Items" +msgstr "Qiymət Sorğusunda Ümumi Elementlər" + +msgid "RFQ Total Number" +msgstr "Qiymət Sorğularının Ümumi Sayı" + +msgid "SQ Total Items" +msgstr "Təchizatçı Təklifində Ümumi Elementlər" + +msgid "SQ Total Number" +msgstr "Təchizatçı Təkliflərinin Ümumi Sayı" + +msgid "Total Accepted Amount" +msgstr "Ümumi Qəbul Edilmiş Məbləğ" + +msgid "Total Accepted Items" +msgstr "Ümumi Qəbul Edilmiş Elementlər" + +msgid "Total Cost of Shipments" +msgstr "Çatdırılmaların Ümumi Dəyəri" + +msgid "Total Days Late" +msgstr "Ümumi Gecikmə Günləri" + +msgid "Total Invoiced" +msgstr "Ümumi Fakturalanmış" + +msgid "Total Item Days" +msgstr "Ümumi Element-Günləri" + +msgid "Total Ordered" +msgstr "Ümumi Sifariş Edilmiş" + +msgid "Total Received Amount" +msgstr "Ümumi Alınmış Məbləğ" + +msgid "Total Received Items" +msgstr "Ümumi Alınmış Elementlər" + +msgid "Total Rejected Amount" +msgstr "Ümumi Rədd Edilmiş Məbləğ" + +msgid "Total Rejected Items" +msgstr "Ümumi Rədd Edilmiş Elementlər" + +msgid "Total Shipments" +msgstr "Ümumi Çatdırılmalar" + +msgid "Total Working Days" +msgstr "Ümumi İş Günləri" diff --git a/az_locale/locale/translations_ru/erpnext/extras.po b/az_locale/locale/translations_ru/erpnext/extras.po index 8779047..c283531 100644 --- a/az_locale/locale/translations_ru/erpnext/extras.po +++ b/az_locale/locale/translations_ru/erpnext/extras.po @@ -107,3 +107,92 @@ msgstr "Стоимость склада по складам" # === Dashboard parents === msgid "Project" msgstr "Проект" + +#. Supplier Scorecard Standing names — DocType fixture data (autoname=field:standing_name), +#. translated via Link fields once translated_doctype=1 is forced on the DocType +#. (see az_locale/locale/update_doctype.py). +# === Supplier Scorecard Standings === +msgid "Very Poor" +msgstr "Очень плохо" + +msgid "Poor" +msgstr "Плохо" + +msgid "Average" +msgstr "Средне" + +msgid "Good" +msgstr "Хорошо" + +msgid "Very Good" +msgstr "Очень хорошо" + +msgid "Excellent" +msgstr "Отлично" + +#. Supplier Scorecard Variable labels — DocType fixture data (autoname=field:variable_label), +#. translated via Link fields once translated_doctype=1 is forced on the DocType +#. (see az_locale/locale/update_doctype.py). +# === Supplier Scorecard Variables === +msgid "# of On Time Shipments" +msgstr "Кол-во своевременных отгрузок" + +msgid "Cost of Delayed Shipments" +msgstr "Стоимость задержанных отгрузок" + +msgid "Cost of On Time Shipments" +msgstr "Стоимость своевременных отгрузок" + +msgid "RFQ Response Days" +msgstr "Дни ответа на запрос коммерческого предложения" + +msgid "RFQ Total Items" +msgstr "Всего позиций в запросах коммерческого предложения" + +msgid "RFQ Total Number" +msgstr "Общее число запросов коммерческого предложения" + +msgid "SQ Total Items" +msgstr "Всего позиций в котировках поставщика" + +msgid "SQ Total Number" +msgstr "Общее число котировок поставщика" + +msgid "Total Accepted Amount" +msgstr "Общая принятая сумма" + +msgid "Total Accepted Items" +msgstr "Всего принятых позиций" + +msgid "Total Cost of Shipments" +msgstr "Общая стоимость отгрузок" + +msgid "Total Days Late" +msgstr "Всего дней опоздания" + +msgid "Total Invoiced" +msgstr "Всего выставлено счетов" + +msgid "Total Item Days" +msgstr "Всего позиций-дней" + +msgid "Total Ordered" +msgstr "Всего заказано" + +msgid "Total Received Amount" +msgstr "Общая полученная сумма" + +msgid "Total Received Items" +msgstr "Всего полученных позиций" + +msgid "Total Rejected Amount" +msgstr "Общая отклонённая сумма" + +msgid "Total Rejected Items" +msgstr "Всего отклонённых позиций" + +msgid "Total Shipments" +msgstr "Всего отгрузок" + +msgid "Total Working Days" +msgstr "Всего рабочих дней" diff --git a/az_locale/locale/update_doctype.py b/az_locale/locale/update_doctype.py new file mode 100644 index 0000000..d83e9b6 --- /dev/null +++ b/az_locale/locale/update_doctype.py @@ -0,0 +1,63 @@ +import json +import os + +from frappe.utils import get_bench_path + +# Доктайпы erpnext, у которых в апстриме не стоит галка 'Translate Link Fields' +# (translated_doctype), но чьи значения-данные (имена записей) нужно переводить. +# Путь указывается относительно apps/erpnext/. +TRANSLATED_DOCTYPES = [ + ( + "erpnext/buying/doctype/supplier_scorecard_standing/supplier_scorecard_standing.json", + "Supplier Scorecard Standing", + ), + ( + "erpnext/buying/doctype/supplier_scorecard_variable/supplier_scorecard_variable.json", + "Supplier Scorecard Variable", + ), +] + + +def update_doctype(): + """Принудительно включаем флаг 'Translate Link Fields' (translated_doctype) + у перечисленных доктайпов erpnext. + + У этих доктайпов в апстриме галка не стоит, поэтому значения их записей + (стандинги, переменные скоркарты) нигде не переводятся. С translated_doctype=1 + доктайп попадает в frappe.boot.translated_doctypes, и любое Link-поле, + ссылающееся на него, прогоняет значение через __() — перевод берётся из + .po/extras.po. + + Правим JSON файлов доктайпов в erpnext. Применится при следующем bench migrate: + Frappe сравнивает migration_hash (хеш содержимого файла) и переимпортирует + доктайп, т.к. содержимое изменилось (см. frappe/modules/import_file.py). + """ + bench_path = get_bench_path() + + for rel_path, doctype in TRANSLATED_DOCTYPES: + file_path = os.path.join(bench_path, "apps", "erpnext", rel_path) + + try: + with open(file_path, "r", encoding="utf-8") as f: + data = json.load(f) + except FileNotFoundError: + print(f"❌ Файл доктайпа не найден: {file_path} (erpnext не установлен?)") + continue + except json.JSONDecodeError: + print(f"❌ Ошибка чтения JSON доктайпа {doctype}.") + continue + + if data.get("translated_doctype") == 1: + print(f"ℹ️ translated_doctype уже включён для {doctype}, пропускаем.") + continue + + data["translated_doctype"] = 1 + + # Тот же формат, что использует экспортёр Frappe: отступ в 1 пробел, + # ключи отсортированы — чтобы diff к апстриму был минимальным. + with open(file_path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=1, sort_keys=True, ensure_ascii=False) + f.write("\n") + + print(f"✅ translated_doctype включён для {doctype} " + "(перевод применится при следующем bench migrate).") diff --git a/az_locale/public/js/supplier_scorecard_standing_list.js b/az_locale/public/js/supplier_scorecard_standing_list.js new file mode 100644 index 0000000..4952bff --- /dev/null +++ b/az_locale/public/js/supplier_scorecard_standing_list.js @@ -0,0 +1,20 @@ +// The "Translate Link Fields" (translated_doctype) flag makes Link references to +// Supplier Scorecard Standing translate, but the doctype's OWN list view shows the +// document `name` as the subject column, and list_view.js only auto-translates +// columns whose df.options is a translated doctype (i.e. Link columns) — not the +// subject. get_subject_text() does apply a registered formatter for the subject +// field though (the subject field here is `name`, since the doctype has no +// title_field), so we translate it ourselves. +frappe.listview_settings["Supplier Scorecard Standing"] = Object.assign( + frappe.listview_settings["Supplier Scorecard Standing"] || {}, + { + formatters: Object.assign( + (frappe.listview_settings["Supplier Scorecard Standing"] || {}).formatters || {}, + { + name(value) { + return __(value); + }, + } + ), + } +); diff --git a/az_locale/public/js/supplier_scorecard_variable_list.js b/az_locale/public/js/supplier_scorecard_variable_list.js new file mode 100644 index 0000000..c21f345 --- /dev/null +++ b/az_locale/public/js/supplier_scorecard_variable_list.js @@ -0,0 +1,18 @@ +// translated_doctype makes Link references to Supplier Scorecard Variable translate, +// but the doctype's OWN list view shows the document `name` as the subject column, +// which list_view.js does not auto-translate. get_subject_text() applies a registered +// formatter for the subject field (here `name`, since the doctype has no title_field), +// so we translate it ourselves. See supplier_scorecard_standing_list.js for details. +frappe.listview_settings["Supplier Scorecard Variable"] = Object.assign( + frappe.listview_settings["Supplier Scorecard Variable"] || {}, + { + formatters: Object.assign( + (frappe.listview_settings["Supplier Scorecard Variable"] || {}).formatters || {}, + { + name(value) { + return __(value); + }, + } + ), + } +);