diff --git a/frappe/translate.py b/frappe/translate.py index 0367d33d3b..04d1feea76 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -23,6 +23,35 @@ from frappe.utils import get_bench_path, is_html, strip, strip_html_tags from frappe.query_builder import Field, DocType from pypika.terms import PseudoColumn +TRANSLATE_PATTERN = re.compile( + r"_\(" # starts with literal `_(` work with both python / JS + + # BEGIN: message search + r"([\"']{,3})" # start of message string identifier - allows: ', ", """, '''; 1st capture group + r"(?P((?!\1).)*)" # Keep matching until string closing identifier is met which is same as 1st capture group + r"\1" # match exact string closing identifier + # END: message search + + # BEGIN: python context search + r"(\s*,\s*context\s*=\s*" # capture `context=` with ignoring whitespace + r"([\"'])" # start of context string identifier; 5th capture group + r"(?P((?!\5).)*)" # capture context string till closing id is found + r"\5" # match context string closure + r")*" # match one or more context string (?wat this should be 0 or 1) + # END: python context search + + # BEGIN: JS context search + r"(\s*,\s*(.)*?\s*(,\s*" # skip message format replacements: ["format", ...] | null | [] + r"([\"'])" # start of context string; 11th capture group + r"(?P((?!\11).)*)" # capture context string till closing id is found + r"\11" # match context string closure + r")*" + r")*" # match one or more context string + # END: JS context search + + r"\)" # Closing function call +) + def get_language(lang_list: List = None) -> str: """Set `frappe.local.lang` from HTTP headers at beginning of request @@ -651,9 +680,8 @@ def extract_messages_from_code(code): frappe.clear_last_message() messages = [] - pattern = r"_\(([\"']{,3})(?P((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P((?!\5).)*)\5)*(\s*,\s*(.)*?\s*(,\s*([\"'])(?P((?!\11).)*)\11)*)*\)" - for m in re.compile(pattern).finditer(code): + for m in TRANSLATE_PATTERN.finditer(code): message = m.group('message') context = m.group('py_context') or m.group('js_context') pos = m.start()