feat: add translated search doctypes to hooks (#16197)

In `search.py` it was hardcoded that **DocType** and **Role** get translated before matching against the search text. This way, a user can type in his local language and still see correct results.

This feature is useful for other DocTypes as well. The criterion would be: there is a small, fairly static number of records, so that the performance impact of translating all names first is not too bad.

This PR adds a hook `translated_search_doctypes` that determines which DocType names get translated before search.

I also added **Country** to `translated_search_doctypes` for frappe. The link to **Country** is frequently used in **Address**, but until now there was no way to use it in the local language. There are ~70% less Countries than DocTypes (including ERPNext), so the performance should be fine.

ERPNext could, for example, add the **Gender** DocType to this hook. As there are very few genders, translating them is fast and improves the UX.

Docs: https://frappeframework.com/docs/v13/user/en/python-api/hooks/edit?wiki_page_patch=b4d7c8d6fc
This commit is contained in:
Raffael Meyer 2022-03-23 11:43:04 +01:00 committed by GitHub
parent 64efc6bd88
commit f80a16ed14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 4 deletions

View file

@ -9,7 +9,6 @@ from frappe import _, is_whitelisted
import re
import wrapt
UNTRANSLATED_DOCTYPES = ["DocType", "Role"]
def sanitize_searchfield(searchfield):
blacklisted_keywords = ['select', 'delete', 'drop', 'update', 'case', 'and', 'or', 'like']
@ -114,6 +113,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
or_filters = []
translated_search_doctypes = frappe.get_hooks("translated_search_doctypes")
# build from doctype
if txt:
search_fields = ["name"]
@ -125,7 +125,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
for f in search_fields:
fmeta = meta.get_field(f.strip())
if (doctype not in UNTRANSLATED_DOCTYPES) and (f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text",
if (doctype not in translated_search_doctypes) and (f == "name" or (fmeta and fmeta.fieldtype in ["Data", "Text", "Small Text", "Long Text",
"Link", "Select", "Read Only", "Text Editor"])):
or_filters.append([doctype, f.strip(), "like", "%{0}%".format(txt)])
@ -160,7 +160,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
ptype = 'select' if frappe.only_has_select_perm(doctype) else 'read'
ignore_permissions = True if doctype == "DocType" else (cint(ignore_user_permissions) and has_permission(doctype, ptype=ptype))
if doctype in UNTRANSLATED_DOCTYPES:
if doctype in translated_search_doctypes:
page_length = None
values = frappe.get_list(doctype,
@ -175,7 +175,7 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
as_list=not as_dict,
strict=False)
if doctype in UNTRANSLATED_DOCTYPES:
if doctype in translated_search_doctypes:
# Filtering the values array so that query is included in very element
values = (
v for v in values

View file

@ -383,3 +383,5 @@ global_search_doctypes = {
{"doctype": "Web Form"}
]
}
translated_search_doctypes = ["DocType", "Role", "Country", "Gender", "Salutation"]

7
frappe/utils/boilerplate.py Executable file → Normal file
View file

@ -333,6 +333,13 @@ app_license = "{app_license}"
# "{app_name}.auth.validate"
# ]
# Translation
# --------------------------------
# Make link fields search translated document names for these DocTypes
# Recommended only for DocTypes which have limited documents with untranslated names
# For example: Role, Gender, etc.
# translated_search_doctypes = []
"""
desktop_template = """from frappe import _