(cherry picked from commit b01929405d
)
# Conflicts:
# frappe/contacts/doctype/gender/gender.json
# frappe/contacts/doctype/salutation/salutation.json
version-14
@@ -26,48 +26,31 @@ context("Control Link", () => { | |||
}); | |||
} | |||
function get_dialog_with_user_link() { | |||
function get_dialog_with_gender_link() { | |||
return cy.dialog({ | |||
title: "Link", | |||
fields: [ | |||
{ | |||
label: "Select User", | |||
fieldname: "link", | |||
fieldtype: "Link", | |||
options: "User", | |||
}, | |||
], | |||
'label': 'Select Gender', | |||
'fieldname': 'link', | |||
'fieldtype': 'Link', | |||
'options': 'Gender', | |||
} | |||
] | |||
}); | |||
} | |||
it("should set the valid value", () => { | |||
get_dialog_with_link().as("dialog"); | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "User", | |||
property: "translate_link_fields", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "0", | |||
}, | |||
true | |||
); | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "ToDo", | |||
property: "show_title_field_in_link", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "0", | |||
}, | |||
true | |||
); | |||
cy.insert_doc("Property Setter", { | |||
"doctype": "Property Setter", | |||
"doc_type": "ToDo", | |||
"property": "show_title_field_in_link", | |||
"property_type": "Check", | |||
"doctype_or_field": "DocType", | |||
"value": "0" | |||
}, true); | |||
cy.intercept("POST", "/api/method/frappe.desk.search.search_link").as("search_link"); | |||
@@ -132,32 +115,15 @@ context("Control Link", () => { | |||
}); | |||
}); | |||
it("show title field in link", () => { | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "User", | |||
property: "translate_link_fields", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "0", | |||
}, | |||
true | |||
); | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "ToDo", | |||
property: "show_title_field_in_link", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "1", | |||
}, | |||
true | |||
); | |||
it('show title field in link', () => { | |||
cy.insert_doc("Property Setter", { | |||
"doctype": "Property Setter", | |||
"doc_type": "ToDo", | |||
"property": "show_title_field_in_link", | |||
"property_type": "Check", | |||
"doctype_or_field": "DocType", | |||
"value": "1" | |||
}, true); | |||
cy.clear_cache(); | |||
cy.wait(500); | |||
@@ -275,153 +241,92 @@ context("Control Link", () => { | |||
); | |||
}); | |||
it("show translated text for link with show_title_field_in_link enabled", () => { | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "ToDo", | |||
property: "translate_link_fields", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "1", | |||
}, | |||
true | |||
); | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "ToDo", | |||
property: "show_title_field_in_link", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "1", | |||
}, | |||
true | |||
); | |||
cy.window() | |||
.its("frappe") | |||
.then((frappe) => { | |||
cy.insert_doc("Translation", { | |||
doctype: "Translation", | |||
language: frappe.boot.lang, | |||
source_text: "this is a test todo for link", | |||
translated_text: "this is a translated test todo for link", | |||
}); | |||
it('show translated text for Gender link field with language de with input in de', () => { | |||
cy.call('frappe.tests.ui_test_helpers.insert_translations').then(() => { | |||
cy.window().its('frappe').then(frappe => { | |||
cy.set_value('User', frappe.user.name, {language: 'de'}); | |||
}); | |||
cy.clear_cache(); | |||
cy.wait(500); | |||
cy.clear_cache(); | |||
cy.wait(500); | |||
get_dialog_with_gender_link().as('dialog'); | |||
cy.intercept('POST', '/api/method/frappe.desk.search.search_link').as('search_link'); | |||
cy.get('.frappe-control[data-fieldname=link] input').focus().as('input'); | |||
cy.wait('@search_link'); | |||
cy.get('@input').type('Sonstiges', { delay: 100 }); | |||
cy.wait('@search_link'); | |||
cy.get('.frappe-control[data-fieldname=link] ul').should('be.visible'); | |||
cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 }); | |||
cy.get('.frappe-control[data-fieldname=link] input').blur(); | |||
cy.get('@dialog').then(dialog => { | |||
let field = dialog.get_field('link'); | |||
let value = field.get_value(); | |||
let label = field.get_label_value(); | |||
cy.window() | |||
.its("frappe") | |||
.then((frappe) => { | |||
if (!frappe.boot) { | |||
frappe.boot = { | |||
link_title_doctypes: ["ToDo"], | |||
translatable_doctypes: ["ToDo"], | |||
}; | |||
} else { | |||
frappe.boot.link_title_doctypes = ["ToDo"]; | |||
frappe.boot.translatable_doctypes = ["ToDo"]; | |||
} | |||
expect(value).to.eq('Other'); | |||
expect(label).to.eq('Sonstiges'); | |||
}); | |||
}); | |||
}); | |||
get_dialog_with_link().as("dialog"); | |||
cy.intercept("POST", "/api/method/frappe.desk.search.search_link").as("search_link"); | |||
it('show translated text for Gender link field with language de with input in en', () => { | |||
cy.call('frappe.tests.ui_test_helpers.insert_translations').then(() => { | |||
cy.window().its('frappe').then(frappe => { | |||
cy.set_value('User', frappe.user.name, {language: 'de'}); | |||
}); | |||
cy.get(".frappe-control[data-fieldname=link] input").focus().as("input"); | |||
cy.wait("@search_link"); | |||
cy.get("@input").type("todo for link", { delay: 100 }); | |||
cy.wait("@search_link"); | |||
cy.get(".frappe-control[data-fieldname=link] ul").should("be.visible"); | |||
cy.get(".frappe-control[data-fieldname=link] input").type("{enter}", { delay: 100 }); | |||
cy.get(".frappe-control[data-fieldname=link] input").blur(); | |||
cy.get("@dialog").then((dialog) => { | |||
cy.get("@todos").then((todos) => { | |||
let field = dialog.get_field("link"); | |||
cy.clear_cache(); | |||
cy.wait(500); | |||
get_dialog_with_gender_link().as('dialog'); | |||
cy.intercept('POST', '/api/method/frappe.desk.search.search_link').as('search_link'); | |||
cy.get('.frappe-control[data-fieldname=link] input').focus().as('input'); | |||
cy.wait('@search_link'); | |||
cy.get('@input').type('Other', { delay: 100 }); | |||
cy.wait('@search_link'); | |||
cy.get('.frappe-control[data-fieldname=link] ul').should('be.visible'); | |||
cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 }); | |||
cy.get('.frappe-control[data-fieldname=link] input').blur(); | |||
cy.get('@dialog').then(dialog => { | |||
let field = dialog.get_field('link'); | |||
let value = field.get_value(); | |||
let label = field.get_label_value(); | |||
expect(value).to.eq(todos[0]); | |||
expect(label).to.eq("this is a translated test todo for link"); | |||
expect(value).to.eq('Other'); | |||
expect(label).to.eq('Sonstiges'); | |||
}); | |||
}); | |||
}); | |||
it("show translated text for link with show_title_field_in_link disabled", () => { | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "User", | |||
property: "translate_link_fields", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "1", | |||
}, | |||
true | |||
); | |||
cy.insert_doc( | |||
"Property Setter", | |||
{ | |||
doctype: "Property Setter", | |||
doc_type: "ToDo", | |||
property: "show_title_field_in_link", | |||
property_type: "Check", | |||
doctype_or_field: "DocType", | |||
value: "0", | |||
}, | |||
true | |||
); | |||
cy.window() | |||
.its("frappe") | |||
.then((frappe) => { | |||
cy.insert_doc("Translation", { | |||
doctype: "Translation", | |||
language: frappe.boot.lang, | |||
source_text: "test@erpnext.com", | |||
translated_text: "translatedtest@erpnext.com", | |||
}); | |||
}); | |||
it('show text for Gender link field with language en', () => { | |||
cy.window().its('frappe').then(frappe => { | |||
cy.set_value('User', frappe.user.name, {language: 'en'}); | |||
}); | |||
cy.clear_cache(); | |||
cy.wait(500); | |||
cy.window() | |||
.its("frappe") | |||
.then((frappe) => { | |||
if (!frappe.boot) { | |||
frappe.boot = { | |||
translatable_doctypes: ["User"], | |||
}; | |||
} else { | |||
frappe.boot.translatable_doctypes = ["User"]; | |||
} | |||
}); | |||
get_dialog_with_user_link().as("dialog"); | |||
cy.intercept("POST", "/api/method/frappe.desk.search.search_link").as("search_link"); | |||
cy.get(".frappe-control[data-fieldname=link] input").focus().as("input"); | |||
cy.wait("@search_link"); | |||
cy.get("@input").type("test@erpnext.com", { delay: 100 }); | |||
cy.wait("@search_link"); | |||
cy.get(".frappe-control[data-fieldname=link] ul").should("be.visible"); | |||
cy.get(".frappe-control[data-fieldname=link] input").type("{enter}", { delay: 100 }); | |||
cy.get(".frappe-control[data-fieldname=link] input").blur(); | |||
cy.get("@dialog").then((dialog) => { | |||
let field = dialog.get_field("link"); | |||
get_dialog_with_gender_link().as('dialog'); | |||
cy.intercept('POST', '/api/method/frappe.desk.search.search_link').as('search_link'); | |||
cy.get('.frappe-control[data-fieldname=link] input').focus().as('input'); | |||
cy.wait('@search_link'); | |||
cy.get('@input').type('Non-Conforming', { delay: 100 }); | |||
cy.wait('@search_link'); | |||
cy.get('.frappe-control[data-fieldname=link] ul').should('be.visible'); | |||
cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 }); | |||
cy.get('.frappe-control[data-fieldname=link] input').blur(); | |||
cy.get('@dialog').then(dialog => { | |||
let field = dialog.get_field('link'); | |||
let value = field.get_value(); | |||
let label = field.get_label_value(); | |||
expect(value).to.eq("test@erpnext.com"); | |||
expect(label).to.eq("translatedtest@erpnext.com"); | |||
expect(value).to.eq('Non-Conforming'); | |||
expect(label).to.eq('Non-Conforming'); | |||
}); | |||
}); | |||
}); |
@@ -19,7 +19,7 @@ from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_p | |||
from frappe.social.doctype.energy_point_settings.energy_point_settings import ( | |||
is_energy_point_enabled, | |||
) | |||
from frappe.translate import get_lang_dict, get_messages_for_boot | |||
from frappe.translate import get_lang_dict, get_messages_for_boot, get_translated_doctypes | |||
from frappe.utils import add_user_info, cstr, get_time_zone | |||
from frappe.utils.change_log import get_versions | |||
from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabled | |||
@@ -100,7 +100,7 @@ def get_bootinfo(): | |||
bootinfo.desk_settings = get_desk_settings() | |||
bootinfo.app_logo_url = get_app_logo() | |||
bootinfo.link_title_doctypes = get_link_title_doctypes() | |||
bootinfo.translatable_doctypes = get_translatable_doctypes() | |||
bootinfo.translated_doctypes = get_translated_doctypes() | |||
return bootinfo | |||
@@ -173,7 +173,10 @@ def get_user_pages_or_reports(parent, cache=False): | |||
.from_(hasRole) | |||
.from_(parentTable) | |||
.select( | |||
customRole[parent.lower()].as_("name"), customRole.modified, customRole.ref_doctype, *columns | |||
customRole[parent.lower()].as_("name"), | |||
customRole.modified, | |||
customRole.ref_doctype, | |||
*columns | |||
) | |||
.where( | |||
(hasRole.parent == customRole.name) | |||
@@ -336,7 +339,9 @@ def get_success_action(): | |||
def get_link_preview_doctypes(): | |||
from frappe.utils import cint | |||
link_preview_doctypes = [d.name for d in frappe.db.get_all("DocType", {"show_preview_popup": 1})] | |||
link_preview_doctypes = [ | |||
d.name for d in frappe.db.get_all("DocType", {"show_preview_popup": 1}) | |||
] | |||
customizations = frappe.get_all( | |||
"Property Setter", fields=["doc_type", "value"], filters={"property": "show_preview_popup"} | |||
) | |||
@@ -399,14 +404,6 @@ def set_time_zone(bootinfo): | |||
} | |||
def get_translatable_doctypes(): | |||
dts = frappe.get_all("DocType", {"translate_link_fields": 1}, pluck="name") | |||
custom_dts = frappe.get_all( | |||
"Property Setter", {"property": "translate_link_fields", "value": "1"}, pluck="doc_type" | |||
) | |||
return dts + custom_dts | |||
def load_country_doc(bootinfo): | |||
country = frappe.db.get_default("country") | |||
if not country: | |||
@@ -43,6 +43,7 @@ | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
<<<<<<< HEAD | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
@@ -60,6 +61,15 @@ | |||
"name": "Gender", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
======= | |||
], | |||
"links": [], | |||
"modified": "2022-08-05 18:33:28.043370", | |||
"modified_by": "Administrator", | |||
"module": "Contacts", | |||
"name": "Gender", | |||
"owner": "Administrator", | |||
>>>>>>> b01929405d (refactor: translatable doctypes) | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
@@ -101,6 +111,7 @@ | |||
"submit": 0, | |||
"write": 0 | |||
} | |||
<<<<<<< HEAD | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
@@ -110,4 +121,12 @@ | |||
"sort_order": "DESC", | |||
"track_changes": 1, | |||
"track_seen": 0 | |||
======= | |||
], | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"track_changes": 1, | |||
"translated_doctype": 1 | |||
>>>>>>> b01929405d (refactor: translatable doctypes) | |||
} |
@@ -42,6 +42,7 @@ | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
<<<<<<< HEAD | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
@@ -59,6 +60,15 @@ | |||
"name": "Salutation", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
======= | |||
], | |||
"links": [], | |||
"modified": "2022-08-05 18:33:28.196387", | |||
"modified_by": "Administrator", | |||
"module": "Contacts", | |||
"name": "Salutation", | |||
"owner": "Administrator", | |||
>>>>>>> b01929405d (refactor: translatable doctypes) | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
@@ -120,6 +130,7 @@ | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
<<<<<<< HEAD | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
@@ -130,3 +141,12 @@ | |||
"track_changes": 1, | |||
"track_seen": 0 | |||
} | |||
======= | |||
], | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"states": [], | |||
"track_changes": 1, | |||
"translated_doctype": 1 | |||
} | |||
>>>>>>> b01929405d (refactor: translatable doctypes) |
@@ -47,7 +47,7 @@ | |||
"view_settings", | |||
"title_field", | |||
"show_title_field_in_link", | |||
"translate_link_fields", | |||
"translated_doctype", | |||
"search_fields", | |||
"default_print_format", | |||
"sort_field", | |||
@@ -595,7 +595,7 @@ | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "translate_link_fields", | |||
"fieldname": "translated_doctype", | |||
"fieldtype": "Check", | |||
"label": "Translate Link Fields" | |||
} | |||
@@ -680,7 +680,7 @@ | |||
"link_fieldname": "reference_doctype" | |||
} | |||
], | |||
"modified": "2022-02-28 21:56:52.116915", | |||
"modified": "2022-08-05 18:33:27.315351", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "DocType", | |||
@@ -716,5 +716,5 @@ | |||
"sort_order": "DESC", | |||
"states": [], | |||
"track_changes": 1, | |||
"translate_link_fields": 1 | |||
"translated_doctype": 1 | |||
} |
@@ -148,7 +148,7 @@ | |||
"idx": 1, | |||
"index_web_pages_for_search": 1, | |||
"links": [], | |||
"modified": "2022-01-12 20:18:18.496230", | |||
"modified": "2022-08-05 18:33:27.694065", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"name": "Role", | |||
@@ -171,5 +171,6 @@ | |||
"sort_field": "modified", | |||
"sort_order": "ASC", | |||
"states": [], | |||
"track_changes": 1 | |||
"track_changes": 1, | |||
"translated_doctype": 1 | |||
} |
@@ -29,7 +29,7 @@ | |||
"view_settings_section", | |||
"title_field", | |||
"show_title_field_in_link", | |||
"translate_link_fields", | |||
"translated_doctype", | |||
"image_field", | |||
"default_print_format", | |||
"column_break_29", | |||
@@ -315,7 +315,7 @@ | |||
}, | |||
{ | |||
"default": "0", | |||
"fieldname": "translate_link_fields", | |||
"fieldname": "translated_doctype", | |||
"fieldtype": "Check", | |||
"label": "Translate Link Fields" | |||
} | |||
@@ -326,7 +326,7 @@ | |||
"index_web_pages_for_search": 1, | |||
"issingle": 1, | |||
"links": [], | |||
"modified": "2022-05-13 15:36:16.772277", | |||
"modified": "2022-08-04 15:36:16.772277", | |||
"modified_by": "Administrator", | |||
"module": "Custom", | |||
"name": "Customize Form", | |||
@@ -585,7 +585,7 @@ doctype_properties = { | |||
"naming_rule": "Data", | |||
"autoname": "Data", | |||
"show_title_field_in_link": "Check", | |||
"translate_link_fields": "Check", | |||
"translated_doctype": "Check", | |||
} | |||
docfield_properties = { | |||
@@ -226,7 +226,7 @@ CREATE TABLE `tabDocType` ( | |||
`sender_field` varchar(255) DEFAULT NULL, | |||
`show_title_field_in_link` int(1) NOT NULL DEFAULT 0, | |||
`migration_hash` varchar(255) DEFAULT NULL, | |||
`translate_link_fields` int(1) NOT NULL DEFAULT 0, | |||
`translated_doctype` int(1) NOT NULL DEFAULT 0, | |||
PRIMARY KEY (`name`) | |||
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci; | |||
@@ -231,7 +231,7 @@ CREATE TABLE "tabDocType" ( | |||
"sender_field" varchar(255) DEFAULT NULL, | |||
"show_title_field_in_link" smallint NOT NULL DEFAULT 0, | |||
"migration_hash" varchar(255) DEFAULT NULL, | |||
"translate_link_fields" smallint NOT NULL DEFAULT 0, | |||
"translated_doctype" smallint NOT NULL DEFAULT 0, | |||
PRIMARY KEY ("name") | |||
) ; | |||
@@ -8,6 +8,7 @@ import re | |||
import frappe | |||
from frappe import _, is_whitelisted | |||
from frappe.permissions import has_permission | |||
from frappe.translate import get_translated_doctypes | |||
from frappe.utils import cint, cstr, unique | |||
@@ -115,7 +116,10 @@ def search_widget( | |||
raise e | |||
else: | |||
frappe.respond_as_web_page( | |||
title="Invalid Method", html="Method not found", indicator_color="red", http_status_code=404 | |||
title="Invalid Method", | |||
html="Method not found", | |||
indicator_color="red", | |||
http_status_code=404, | |||
) | |||
return | |||
except Exception as e: | |||
@@ -146,9 +150,22 @@ def search_widget( | |||
filters = [] | |||
or_filters = [] | |||
translated_search_doctypes = frappe.get_hooks("translated_search_doctypes") | |||
translated_doctypes = frappe.cache().hget( | |||
"translated_doctypes", "doctypes", get_translated_doctypes | |||
) | |||
# build from doctype | |||
if txt: | |||
field_types = [ | |||
"Data", | |||
"Text", | |||
"Small Text", | |||
"Long Text", | |||
"Link", | |||
"Select", | |||
"Read Only", | |||
"Text Editor", | |||
] | |||
search_fields = ["name"] | |||
if meta.title_field: | |||
search_fields.append(meta.title_field) | |||
@@ -158,13 +175,8 @@ def search_widget( | |||
for f in search_fields: | |||
fmeta = meta.get_field(f.strip()) | |||
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"] | |||
) | |||
if (doctype not in translated_doctypes) and ( | |||
f == "name" or (fmeta and fmeta.fieldtype in field_types) | |||
): | |||
or_filters.append([doctype, f.strip(), "like", f"%{txt}%"]) | |||
@@ -188,7 +200,8 @@ def search_widget( | |||
# find relevance as location of search term from the beginning of string `name`. used for sorting results. | |||
formatted_fields.append( | |||
"""locate({_txt}, `tab{doctype}`.`name`) as `_relevance`""".format( | |||
_txt=frappe.db.escape((txt or "").replace("%", "").replace("@", "")), doctype=doctype | |||
_txt=frappe.db.escape((txt or "").replace("%", "").replace("@", "")), | |||
doctype=doctype, | |||
) | |||
) | |||
@@ -206,7 +219,7 @@ def search_widget( | |||
else (cint(ignore_user_permissions) and has_permission(doctype, ptype=ptype)) | |||
) | |||
if doctype in translated_search_doctypes: | |||
if doctype in translated_doctypes: | |||
page_length = None | |||
values = frappe.get_list( | |||
@@ -223,12 +236,13 @@ def search_widget( | |||
strict=False, | |||
) | |||
if doctype in translated_search_doctypes: | |||
if doctype in translated_doctypes: | |||
# Filtering the values array so that query is included in very element | |||
values = ( | |||
v | |||
for v in values | |||
if re.search(f"{re.escape(txt)}.*", _(v.name if as_dict else v[0]), re.IGNORECASE) | |||
or re.search(f"{_(re.escape(txt))}.*", _(v.name if as_dict else v[0]), re.IGNORECASE) | |||
) | |||
# Sorting the values array so that relevant results always come first | |||
@@ -54,7 +54,7 @@ | |||
"icon": "fa fa-globe", | |||
"idx": 1, | |||
"links": [], | |||
"modified": "2020-02-24 15:44:31.837133", | |||
"modified": "2022-08-05 18:33:27.880783", | |||
"modified_by": "Administrator", | |||
"module": "Geo", | |||
"name": "Country", | |||
@@ -84,5 +84,7 @@ | |||
"quick_entry": 1, | |||
"sort_field": "country_name", | |||
"sort_order": "ASC", | |||
"track_changes": 1 | |||
"states": [], | |||
"track_changes": 1, | |||
"translated_doctype": 1 | |||
} |
@@ -373,5 +373,3 @@ override_whitelisted_methods = { | |||
"frappe.core.doctype.file.file.move_file": "frappe.core.api.file.move_file", | |||
"frappe.core.doctype.file.file.zip_files": "frappe.core.api.file.zip_files", | |||
} | |||
translated_search_doctypes = ["DocType", "Role", "Country", "Gender", "Salutation"] |
@@ -87,7 +87,7 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat | |||
return this.is_translatable() ? __(value) : value; | |||
} | |||
is_translatable() { | |||
return in_list(frappe.boot?.translatable_doctypes || [], this.get_options()); | |||
return in_list(frappe.boot?.translated_doctypes || [], this.get_options()); | |||
} | |||
set_link_title(value) { | |||
let doctype = this.get_options(); | |||
@@ -382,22 +382,6 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat | |||
me.$input.val(""); | |||
} | |||
}); | |||
this.$input.on("focus", function () { | |||
if (!frappe.boot.translated_search_doctypes.includes(me.df.options)) { | |||
me.show_untranslated(); | |||
} | |||
}); | |||
this.$input.keydown((e) => { | |||
let BACKSPACE = 8; | |||
if ( | |||
e.keyCode === BACKSPACE && | |||
!frappe.boot.translated_search_doctypes.includes(me.df.options) | |||
) { | |||
me.show_untranslated(); | |||
} | |||
}); | |||
} | |||
show_untranslated() { | |||
@@ -184,7 +184,6 @@ def get(): | |||
frappe.get_attr(hook)(bootinfo=bootinfo) | |||
bootinfo["lang"] = frappe.translate.get_user_lang() | |||
bootinfo["translated_search_doctypes"] = frappe.get_hooks("translated_search_doctypes") | |||
bootinfo["disable_async"] = frappe.conf.disable_async | |||
bootinfo["setup_complete"] = cint(frappe.get_system_settings("setup_complete")) | |||
@@ -333,3 +333,37 @@ def insert_doctype_with_child_table_record(name): | |||
insert_child(doc, "Drag", "08189DIHAA2981", 0, 0.7, 342628, "2022-05-04") | |||
doc.insert() | |||
@frappe.whitelist() | |||
def insert_translations(): | |||
translation = [ | |||
{ | |||
"doctype": "Translation", | |||
"language": "de", | |||
"source_text": "Other", | |||
"translated_text": "Sonstiges", | |||
}, | |||
{ | |||
"doctype": "Translation", | |||
"language": "de", | |||
"source_text": "Genderqueer", | |||
"translated_text": "Geschlechtsspezifisch", | |||
}, | |||
{ | |||
"doctype": "Translation", | |||
"language": "de", | |||
"source_text": "Non-Conforming", | |||
"translated_text": "Nicht konform", | |||
}, | |||
{ | |||
"doctype": "Translation", | |||
"language": "de", | |||
"source_text": "Prefer not to say", | |||
"translated_text": "Mache lieber keine Angabe", | |||
}, | |||
] | |||
for doc in translation: | |||
if not frappe.db.exists("doc"): | |||
frappe.get_doc(doc).insert() |
@@ -23,7 +23,7 @@ from pypika.terms import PseudoColumn | |||
import frappe | |||
from frappe.model.utils import InvalidIncludePath, render_include | |||
from frappe.query_builder import DocType, Field | |||
from frappe.utils import cstr, get_bench_path, is_html, strip, strip_html_tags | |||
from frappe.utils import cstr, get_bench_path, is_html, strip, strip_html_tags, unique | |||
TRANSLATE_PATTERN = re.compile( | |||
r"_\(\s*" # starts with literal `_(`, ignore following whitespace/newlines | |||
@@ -108,8 +108,8 @@ def get_parent_language(lang: str) -> str: | |||
"""If the passed language is a variant, return its parent | |||
Eg: | |||
1. zh-TW -> zh | |||
2. sr-BA -> sr | |||
1. zh-TW -> zh | |||
2. sr-BA -> sr | |||
""" | |||
is_language_variant = "-" in lang | |||
if is_language_variant: | |||
@@ -1294,3 +1294,11 @@ def set_preferred_language_cookie(preferred_language): | |||
def get_preferred_language_cookie(): | |||
return frappe.request.cookies.get("preferred_language") | |||
def get_translated_doctypes(): | |||
dts = frappe.get_all("DocType", {"translated_doctype": 1}, pluck="name") | |||
custom_dts = frappe.get_all( | |||
"Property Setter", {"property": "translated_doctype", "value": "1"}, pluck="doc_type" | |||
) | |||
return unique(dts + custom_dts) |
@@ -79,7 +79,8 @@ def is_valid_title(title) -> bool: | |||
def _create_app_boilerplate(dest, hooks, no_git=False): | |||
frappe.create_folder( | |||
os.path.join(dest, hooks.app_name, hooks.app_name, frappe.scrub(hooks.app_title)), with_init=True | |||
os.path.join(dest, hooks.app_name, hooks.app_name, frappe.scrub(hooks.app_title)), | |||
with_init=True, | |||
) | |||
frappe.create_folder( | |||
os.path.join(dest, hooks.app_name, hooks.app_name, "templates"), with_init=True | |||
@@ -249,8 +250,8 @@ app_license = "{app_license}" | |||
# add methods and filters to jinja environment | |||
# jinja = {{ | |||
# "methods": "{app_name}.utils.jinja_methods", | |||
# "filters": "{app_name}.utils.jinja_filters" | |||
# "methods": "{app_name}.utils.jinja_methods", | |||
# "filters": "{app_name}.utils.jinja_filters" | |||
# }} | |||
# Installation | |||
@@ -276,11 +277,11 @@ app_license = "{app_license}" | |||
# Permissions evaluated in scripted ways | |||
# permission_query_conditions = {{ | |||
# "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", | |||
# "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", | |||
# }} | |||
# | |||
# has_permission = {{ | |||
# "Event": "frappe.desk.doctype.event.event.has_permission", | |||
# "Event": "frappe.desk.doctype.event.event.has_permission", | |||
# }} | |||
# DocType Class | |||
@@ -288,7 +289,7 @@ app_license = "{app_license}" | |||
# Override standard doctype classes | |||
# override_doctype_class = {{ | |||
# "ToDo": "custom_app.overrides.CustomToDo" | |||
# "ToDo": "custom_app.overrides.CustomToDo" | |||
# }} | |||
# Document Events | |||
@@ -296,10 +297,10 @@ app_license = "{app_license}" | |||
# Hook on document methods and events | |||
# doc_events = {{ | |||
# "*": {{ | |||
# "on_update": "method", | |||
# "on_cancel": "method", | |||
# "on_trash": "method" | |||
# "*": {{ | |||
# "on_update": "method", | |||
# "on_cancel": "method", | |||
# "on_trash": "method" | |||
# }} | |||
# }} | |||
@@ -307,21 +308,21 @@ app_license = "{app_license}" | |||
# --------------- | |||
# scheduler_events = {{ | |||
# "all": [ | |||
# "{app_name}.tasks.all" | |||
# ], | |||
# "daily": [ | |||
# "{app_name}.tasks.daily" | |||
# ], | |||
# "hourly": [ | |||
# "{app_name}.tasks.hourly" | |||
# ], | |||
# "weekly": [ | |||
# "{app_name}.tasks.weekly" | |||
# ], | |||
# "monthly": [ | |||
# "{app_name}.tasks.monthly" | |||
# ], | |||
# "all": [ | |||
# "{app_name}.tasks.all" | |||
# ], | |||
# "daily": [ | |||
# "{app_name}.tasks.daily" | |||
# ], | |||
# "hourly": [ | |||
# "{app_name}.tasks.hourly" | |||
# ], | |||
# "weekly": [ | |||
# "{app_name}.tasks.weekly" | |||
# ], | |||
# "monthly": [ | |||
# "{app_name}.tasks.monthly" | |||
# ], | |||
# }} | |||
# Testing | |||
@@ -333,14 +334,14 @@ app_license = "{app_license}" | |||
# ------------------------------ | |||
# | |||
# override_whitelisted_methods = {{ | |||
# "frappe.desk.doctype.event.event.get_events": "{app_name}.event.get_events" | |||
# "frappe.desk.doctype.event.event.get_events": "{app_name}.event.get_events" | |||
# }} | |||
# | |||
# each overriding function accepts a `data` argument; | |||
# generated from the base implementation of the doctype dashboard, | |||
# along with any modifications made in other Frappe apps | |||
# override_doctype_dashboards = {{ | |||
# "Task": "{app_name}.task.get_dashboard_data" | |||
# "Task": "{app_name}.task.get_dashboard_data" | |||
# }} | |||
# exempt linked doctypes from being automatically cancelled | |||
@@ -352,40 +353,32 @@ app_license = "{app_license}" | |||
# -------------------- | |||
# user_data_fields = [ | |||
# {{ | |||
# "doctype": "{{doctype_1}}", | |||
# "filter_by": "{{filter_by}}", | |||
# "redact_fields": ["{{field_1}}", "{{field_2}}"], | |||
# "partial": 1, | |||
# }}, | |||
# {{ | |||
# "doctype": "{{doctype_2}}", | |||
# "filter_by": "{{filter_by}}", | |||
# "partial": 1, | |||
# }}, | |||
# {{ | |||
# "doctype": "{{doctype_3}}", | |||
# "strict": False, | |||
# }}, | |||
# {{ | |||
# "doctype": "{{doctype_4}}" | |||
# }} | |||
# {{ | |||
# "doctype": "{{doctype_1}}", | |||
# "filter_by": "{{filter_by}}", | |||
# "redact_fields": ["{{field_1}}", "{{field_2}}"], | |||
# "partial": 1, | |||
# }}, | |||
# {{ | |||
# "doctype": "{{doctype_2}}", | |||
# "filter_by": "{{filter_by}}", | |||
# "partial": 1, | |||
# }}, | |||
# {{ | |||
# "doctype": "{{doctype_3}}", | |||
# "strict": False, | |||
# }}, | |||
# {{ | |||
# "doctype": "{{doctype_4}}" | |||
# }} | |||
# ] | |||
# Authentication and authorization | |||
# -------------------------------- | |||
# auth_hooks = [ | |||
# "{app_name}.auth.validate" | |||
# "{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 _ | |||
@@ -447,8 +440,8 @@ name: CI | |||
on: | |||
push: | |||
branches: | |||
- develop | |||
branches: | |||
- develop | |||
pull_request: | |||
concurrency: | |||
@@ -457,79 +450,79 @@ concurrency: | |||
jobs: | |||
tests: | |||
runs-on: ubuntu-latest | |||
strategy: | |||
fail-fast: false | |||
name: Server | |||
services: | |||
mariadb: | |||
image: mariadb:10.6 | |||
env: | |||
MYSQL_ROOT_PASSWORD: root | |||
ports: | |||
- 3306:3306 | |||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 | |||
steps: | |||
- name: Clone | |||
uses: actions/checkout@v2 | |||
- name: Setup Python | |||
uses: actions/setup-python@v2 | |||
with: | |||
python-version: '3.10' | |||
- name: Setup Node | |||
uses: actions/setup-node@v2 | |||
with: | |||
node-version: 14 | |||
check-latest: true | |||
- name: Cache pip | |||
uses: actions/cache@v2 | |||
with: | |||
path: ~/.cache/pip | |||
key: ${{{{ runner.os }}}}-pip-${{{{ hashFiles('**/*requirements.txt', '**/pyproject.toml', '**/setup.py', '**/setup.cfg') }}}} | |||
restore-keys: | | |||
${{{{ runner.os }}}}-pip- | |||
${{{{ runner.os }}}}- | |||
- name: Get yarn cache directory path | |||
id: yarn-cache-dir-path | |||
run: 'echo "::set-output name=dir::$(yarn cache dir)"' | |||
- uses: actions/cache@v2 | |||
id: yarn-cache | |||
with: | |||
path: ${{{{ steps.yarn-cache-dir-path.outputs.dir }}}} | |||
key: ${{{{ runner.os }}}}-yarn-${{{{ hashFiles('**/yarn.lock') }}}} | |||
restore-keys: | | |||
${{{{ runner.os }}}}-yarn- | |||
- name: Setup | |||
run: | | |||
pip install frappe-bench | |||
bench init --skip-redis-config-generation --skip-assets --python "$(which python)" ~/frappe-bench | |||
mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" | |||
mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" | |||
- name: Install | |||
working-directory: /home/runner/frappe-bench | |||
run: | | |||
bench get-app {app_name} $GITHUB_WORKSPACE | |||
bench setup requirements --dev | |||
bench new-site --db-root-password root --admin-password admin test_site | |||
bench --site test_site install-app {app_name} | |||
bench build | |||
env: | |||
CI: 'Yes' | |||
- name: Run Tests | |||
working-directory: /home/runner/frappe-bench | |||
run: | | |||
bench --site test_site set-config allow_tests true | |||
bench --site test_site run-tests --app {app_name} | |||
env: | |||
TYPE: server | |||
runs-on: ubuntu-latest | |||
strategy: | |||
fail-fast: false | |||
name: Server | |||
services: | |||
mariadb: | |||
image: mariadb:10.6 | |||
env: | |||
MYSQL_ROOT_PASSWORD: root | |||
ports: | |||
- 3306:3306 | |||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 | |||
steps: | |||
- name: Clone | |||
uses: actions/checkout@v2 | |||
- name: Setup Python | |||
uses: actions/setup-python@v2 | |||
with: | |||
python-version: '3.10' | |||
- name: Setup Node | |||
uses: actions/setup-node@v2 | |||
with: | |||
node-version: 14 | |||
check-latest: true | |||
- name: Cache pip | |||
uses: actions/cache@v2 | |||
with: | |||
path: ~/.cache/pip | |||
key: ${{{{ runner.os }}}}-pip-${{{{ hashFiles('**/*requirements.txt', '**/pyproject.toml', '**/setup.py', '**/setup.cfg') }}}} | |||
restore-keys: | | |||
${{{{ runner.os }}}}-pip- | |||
${{{{ runner.os }}}}- | |||
- name: Get yarn cache directory path | |||
id: yarn-cache-dir-path | |||
run: 'echo "::set-output name=dir::$(yarn cache dir)"' | |||
- uses: actions/cache@v2 | |||
id: yarn-cache | |||
with: | |||
path: ${{{{ steps.yarn-cache-dir-path.outputs.dir }}}} | |||
key: ${{{{ runner.os }}}}-yarn-${{{{ hashFiles('**/yarn.lock') }}}} | |||
restore-keys: | | |||
${{{{ runner.os }}}}-yarn- | |||
- name: Setup | |||
run: | | |||
pip install frappe-bench | |||
bench init --skip-redis-config-generation --skip-assets --python "$(which python)" ~/frappe-bench | |||
mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" | |||
mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" | |||
- name: Install | |||
working-directory: /home/runner/frappe-bench | |||
run: | | |||
bench get-app {app_name} $GITHUB_WORKSPACE | |||
bench setup requirements --dev | |||
bench new-site --db-root-password root --admin-password admin test_site | |||
bench --site test_site install-app {app_name} | |||
bench build | |||
env: | |||
CI: 'Yes' | |||
- name: Run Tests | |||
working-directory: /home/runner/frappe-bench | |||
run: | | |||
bench --site test_site set-config allow_tests true | |||
bench --site test_site run-tests --app {app_name} | |||
env: | |||
TYPE: server | |||
""" |