diff --git a/frappe/boot.py b/frappe/boot.py index 1fe6f957d5..c29a2118e5 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -342,10 +342,7 @@ def get_user_pages_or_reports(parent, cache=False): def load_translations(bootinfo): - from frappe.translate import get_messages_for_boot - bootinfo["lang"] = frappe.lang - bootinfo["__messages"] = get_messages_for_boot() def get_user_info(): diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 1408effc6a..e27968fac2 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -30,7 +30,9 @@ frappe.Application = class Application { this.startup(); } - startup() { + async startup() { + // Wait for translations to be loaded before rendering any UI + if (frappe._translations_loaded) await frappe._translations_loaded; frappe.realtime.init(); frappe.model.init(); diff --git a/frappe/templates/base.html b/frappe/templates/base.html index 8dd3f12a47..56c114277a 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -98,6 +98,13 @@ frappe.boot = {{ frappe.utils.orjson_dumps(boot, default=frappe.json_handler) }} // for backward compatibility of some libs frappe.sys_defaults = frappe.boot.sysdefaults; + frappe._messages = {}; + frappe._translations_loaded = fetch( + `/api/method/frappe.translate.get_boot_translations?v=${window._version_number}&lang=${frappe.boot.lang}`, + {credentials: "same-origin"} + ).then(r => r.json()).then(data => { + frappe._messages = data.message || {}; + }).catch(() => {}); {{ include_script('frappe-web.bundle.js') }} {% endblock %} diff --git a/frappe/translate.py b/frappe/translate.py index 0a2d3cab50..50d5465405 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -132,6 +132,13 @@ def get_messages_for_boot(): return get_all_translations(frappe.local.lang) +@frappe.whitelist(allow_guest=True, methods=["GET"]) +def get_boot_translations(lang=None): + """Return all translations for the current user's language.""" + frappe.local.response_headers["Cache-Control"] = "private, max-age=31536000" + return get_all_translations(lang or frappe.local.lang) + + def get_all_translations(lang: str) -> dict[str, str]: """Load and return the entire translations dictionary for a language from apps + user translations. diff --git a/frappe/www/desk.html b/frappe/www/desk.html index ec4cb99974..b1b40c7258 100644 --- a/frappe/www/desk.html +++ b/frappe/www/desk.html @@ -52,9 +52,22 @@ if (!window.frappe) window.frappe = {}; frappe.boot = {{ frappe.utils.orjson_dumps(boot, default=frappe.json_handler) }}; - frappe._messages = frappe.boot["__messages"]; + frappe._messages = {}; frappe.csrf_token = "{{ csrf_token }}"; + frappe._translations_loaded = fetch( + `/api/method/frappe.translate.get_boot_translations?v=${window._version_number}&lang=${frappe.boot.lang}`, + { + credentials: "same-origin", + headers: { + "X-Frappe-CSRF-Token": frappe.csrf_token, + "Accept": "application/json" + } + } + ).then(r => r.json()).then(data => { + frappe._messages = data.message || {}; + }).catch(() => {}); +