diff --git a/frappe/auth.py b/frappe/auth.py
index a9b1516b01..5ce4462161 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -487,7 +487,10 @@ def validate_ip_address(user):
if bypass_restrict_ip_check:
return
- frappe.throw(_("Access not allowed from this IP Address"), frappe.AuthenticationError)
+ frappe.throw(
+ _("Access not allowed from this IP Address") + f": {frappe.local.request_ip}",
+ frappe.AuthenticationError,
+ )
def get_login_attempt_tracker(key: str, raise_locked_exception: bool = True):
diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
index ed830fd069..5ebfe48347 100644
--- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
+++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
@@ -3,7 +3,7 @@
import hashlib
import json
-from datetime import datetime
+from datetime import datetime, timedelta
import click
from croniter import CroniterBadCronError, croniter
@@ -105,8 +105,7 @@ class ScheduledJobType(Document):
# Maintenance jobs run at random time, the time is specific to the site though.
# This is done to avoid scheduling all maintenance task on all sites at the same time in
# multitenant deployments.
- hourly_site_offset = int(hashlib.sha1(frappe.local.site.encode()).hexdigest(), 16) % 60
- daily_site_offset = (hourly_site_offset + 30) % 60
+ maintenance_offset = int(hashlib.sha1(frappe.local.site.encode()).hexdigest(), 16) % 60
CRON_MAP = {
"Yearly": "0 0 1 1 *",
@@ -117,10 +116,10 @@ class ScheduledJobType(Document):
"Weekly Long": "0 0 * * 0",
"Daily": "0 0 * * *",
"Daily Long": "0 0 * * *",
- "Daily Maintenance": f"{daily_site_offset} 0 * * *",
+ "Daily Maintenance": "0 0 * * *",
"Hourly": "0 * * * *",
"Hourly Long": "0 * * * *",
- "Hourly Maintenance": f"{hourly_site_offset} * * * *",
+ "Hourly Maintenance": "0 * * * *",
"All": f"*/{(frappe.get_conf().scheduler_interval or 240) // 60} * * * *",
}
@@ -133,6 +132,9 @@ class ScheduledJobType(Document):
# A dynamic fallback like current time might miss the scheduler interval and job will never start.
last_execution = get_datetime(self.last_execution or self.creation)
+ next_execution = croniter(self.cron_format, last_execution).get_next(datetime)
+ if self.frequency in ("Hourly Maintenance", "Daily Maintenance"):
+ next_execution += timedelta(minutes=maintenance_offset)
return croniter(self.cron_format, last_execution).get_next(datetime)
def execute(self):
diff --git a/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py
index 8d27385bbb..dc6606a5b3 100644
--- a/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py
+++ b/frappe/core/doctype/scheduled_job_type/test_scheduled_job_type.py
@@ -117,7 +117,7 @@ class TestScheduledJobType(IntegrationTestCase):
sjt = frappe.new_doc(
"Scheduled Job Type",
frequency="Hourly Maintenance",
- last_execution=get_datetime("2019-01-01 00:00:00"),
+ last_execution=get_datetime("2019-01-01 23:59:00"),
)
# Should be within one hour
self.assertGreaterEqual(sjt.next_execution, sjt.last_execution)
diff --git a/frappe/database/database.py b/frappe/database/database.py
index 9216eee61f..8662693346 100644
--- a/frappe/database/database.py
+++ b/frappe/database/database.py
@@ -1447,7 +1447,7 @@ class Database:
values: Iterable[Sequence[Any]],
ignore_duplicates=False,
*,
- chunk_size=10_000,
+ chunk_size=1000,
):
"""
Insert multiple records at a time
diff --git a/frappe/desk/doctype/system_console/system_console.js b/frappe/desk/doctype/system_console/system_console.js
index 4b83fecfbd..bba9ea64a6 100644
--- a/frappe/desk/doctype/system_console/system_console.js
+++ b/frappe/desk/doctype/system_console/system_console.js
@@ -36,6 +36,10 @@ frappe.ui.form.on("System Console", {
frm.set_value("type", "Python"); // defaults don't work on singles on old sites.
}
frm.trigger("load_completions");
+
+ frm.page.add_inner_message(
+ `${__("Tip: Try the new dropdown console using")} ⇧+T`
+ );
},
type: function (frm) {
diff --git a/frappe/desk/doctype/system_console/system_console.json b/frappe/desk/doctype/system_console/system_console.json
index a59ab01b0b..0e00e7bb6e 100644
--- a/frappe/desk/doctype/system_console/system_console.json
+++ b/frappe/desk/doctype/system_console/system_console.json
@@ -86,7 +86,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2024-03-23 16:03:39.355553",
+ "modified": "2025-05-28 09:26:57.614890",
"modified_by": "Administrator",
"module": "Desk",
"name": "System Console",
@@ -96,14 +96,15 @@
"email": 1,
"print": 1,
"read": 1,
- "role": "System Manager",
+ "role": "Administrator",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
+ "row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/frappe/desk/doctype/system_console/system_console.py b/frappe/desk/doctype/system_console/system_console.py
index 2334f3809e..714a2c8240 100644
--- a/frappe/desk/doctype/system_console/system_console.py
+++ b/frappe/desk/doctype/system_console/system_console.py
@@ -25,11 +25,13 @@ class SystemConsole(Document):
# end: auto-generated types
def run(self):
- frappe.only_for("System Manager")
+ frappe.only_for(["System Manager", "Administrator"])
try:
frappe.local.debug_log = []
if self.type == "Python":
- safe_exec(self.console, script_filename="System Console")
+ safe_exec(
+ self.console, script_filename="System Console", restrict_commit_rollback=not self.commit
+ )
self.output = "\n".join(frappe.debug_log)
elif self.type == "SQL":
self.output = frappe.as_json(read_sql(self.console, as_dict=1))
diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py
index 7810bba752..5a371bc34d 100644
--- a/frappe/desk/query_report.py
+++ b/frappe/desk/query_report.py
@@ -14,7 +14,7 @@ from frappe.desk.reportview import clean_params, parse_json
from frappe.model.utils import render_include
from frappe.modules import get_module_path, scrub
from frappe.monitor import add_data_to_monitor
-from frappe.permissions import get_role_permissions, has_permission
+from frappe.permissions import get_role_permissions, get_valid_perms, has_permission
from frappe.utils import cint, cstr, flt, format_duration, get_html_format, sbool
@@ -710,10 +710,8 @@ def has_match(
# so that even if one of the sets allows a match, it is true
if match:
- if not frappe.has_permission(
- doctype=ref_doctype, ptype="read", throw=False, ignore_share_permissions=True
- ):
- match = False
+ valid_perms = get_valid_perms(doctype=ref_doctype)
+ match = any(perm.get("read") and not perm.get("if_owner") for perm in valid_perms)
matched_for_doctype = matched_for_doctype or match
diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py
index 836fd927a6..1b42df7b2e 100644
--- a/frappe/email/doctype/email_queue/email_queue.py
+++ b/frappe/email/doctype/email_queue/email_queue.py
@@ -731,7 +731,8 @@ class QueueBuilder:
if self.read_receipt:
mail.msg_root["Disposition-Notification-To"] = self.sender
if self.in_reply_to:
- mail.set_in_reply_to(self.in_reply_to)
+ if message_id := frappe.db.get_value("Communication", self.in_reply_to, "message_id"):
+ mail.set_in_reply_to(get_string_between("<", message_id, ">"))
return mail
def process(self, send_now=False) -> EmailQueue | None:
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 4c1d2397f2..09539b6e47 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -209,6 +209,7 @@ scheduler_events = {
"frappe.utils.global_search.sync_global_search",
"frappe.deferred_insert.save_to_db",
"frappe.automation.doctype.reminder.reminder.send_reminders",
+ "frappe.model.utils.link_count.update_link_count",
],
# 10 minutes
"0/10 * * * *": [
@@ -231,7 +232,6 @@ scheduler_events = {
# Use these for when you don't care about when the job runs but just need some guarantee for
# frequency.
"hourly_maintenance": [
- "frappe.model.utils.link_count.update_link_count",
"frappe.model.utils.user_settings.sync_user_settings",
"frappe.desk.page.backups.backups.delete_downloadable_backups",
"frappe.desk.form.document_follow.send_hourly_updates",
diff --git a/frappe/locale/fa.po b/frappe/locale/fa.po
index aabdfc5e35..91f8593305 100644
--- a/frappe/locale/fa.po
+++ b/frappe/locale/fa.po
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-05-18 09:33+0000\n"
-"PO-Revision-Date: 2025-05-19 07:02\n"
+"PO-Revision-Date: 2025-05-26 10:24\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Persian\n"
"MIME-Version: 1.0\n"
@@ -115,7 +115,7 @@ msgstr "+ افزودن / حذف فیلدها"
#. State'
#: frappe/workflow/doctype/workflow_document_state/workflow_document_state.json
msgid "0 - Draft; 1 - Submitted; 2 - Cancelled"
-msgstr "0 - پیشنویس؛ 1 - ارسال شده 2 - لغو شد"
+msgstr "0 - پیشنویس؛ 1 - ارسال شده؛ 2 - لغو شده"
#. Description of the 'Priority' (Int) field in DocType 'Web Page'
#: frappe/website/doctype/web_page/web_page.json
@@ -584,7 +584,7 @@ msgstr "یک {0} {1} تکرارشونده از طریق تکرار خودکار
#. Description of the 'Symbol' (Data) field in DocType 'Currency'
#: frappe/geo/doctype/currency/currency.json
msgid "A symbol for this currency. For e.g. $"
-msgstr "ن برای این ارز. به عنوان مثال $"
+msgstr "نمادی برای این ارز. مثلاً $"
#: frappe/printing/doctype/print_format_field_template/print_format_field_template.py:49
msgid "A template already exists for field {0} of {1}"
@@ -1153,7 +1153,7 @@ msgstr "افزودن یک نقش جدید"
#: frappe/public/js/frappe/form/form_tour.js:211
msgid "Add a Row"
-msgstr ""
+msgstr "افزودن یک ردیف"
#: frappe/templates/includes/comments/comments.html:30
#: frappe/templates/includes/comments/comments.html:47
@@ -2138,7 +2138,7 @@ msgstr "افزودن به میتواند یکی از {0} باشد"
#. Description of the 'Append To' (Link) field in DocType 'Email Account'
#: frappe/email/doctype/email_account/email_account.json
msgid "Append as communication against this DocType (must have fields: \"Sender\" and \"Subject\"). These fields can be defined in the email settings section of the appended doctype."
-msgstr "به عنوان ارتباط در مقابل این DocType اضافه شود (باید دارای فیلدهای: \"فرستنده\" و \"موضوع\"). این فیلدها را میتوان در قسمت تنظیمات ایمیل از doctype ضمیمه شده تعریف کرد."
+msgstr "به عنوان ارتباط در مقابل این DocType اضافه شود (باید دارای فیلدهای: \"فرستنده\" و \"موضوع\"). این فیلدها را میتوان در قسمت تنظیمات ایمیل از doctype پیوست شده تعریف کرد."
#: frappe/core/doctype/user_permission/user_permission_list.js:105
msgid "Applicable Document Types"
@@ -2524,7 +2524,7 @@ msgstr "پیوست"
#: frappe/public/js/frappe/views/communication.js:152
msgid "Attach Document Print"
-msgstr "ضمیمه چاپ سند"
+msgstr "پیوست چاپ سند"
#. Option for the 'Type' (Select) field in DocType 'DocField'
#. Option for the 'Field Type' (Select) field in DocType 'Custom Field'
@@ -2560,7 +2560,7 @@ msgstr "فایل ها / آدرس ها را پیوست کنید و در جدول
#. Label of the attached_file (Code) field in DocType 'Notification Log'
#: frappe/desk/doctype/notification_log/notification_log.json
msgid "Attached File"
-msgstr "فایل ضمیمه شده"
+msgstr "فایل پیوست شده"
#. Label of the attached_to_doctype (Link) field in DocType 'File'
#: frappe/core/doctype/file/file.json
@@ -3509,7 +3509,7 @@ msgstr "پرش کرد"
#. Label of the brand (Section Break) field in DocType 'Website Settings'
#: frappe/website/doctype/website_settings/website_settings.json
msgid "Brand"
-msgstr "نام تجاری"
+msgstr "برند"
#. Label of the brand_html (Code) field in DocType 'Website Settings'
#: frappe/website/doctype/website_settings/website_settings.json
@@ -3519,7 +3519,7 @@ msgstr "HTML برند"
#. Label of the banner_image (Attach Image) field in DocType 'Website Settings'
#: frappe/website/doctype/website_settings/website_settings.json
msgid "Brand Image"
-msgstr "تصویر نام تجاری"
+msgstr "تصویر برند"
#. Label of the brand_logo (Attach Image) field in DocType 'Email Account'
#: frappe/email/doctype/email_account/email_account.json
@@ -3530,7 +3530,7 @@ msgstr "لوگوی برند"
#: frappe/website/doctype/website_settings/website_settings.json
msgid "Brand is what appears on the top-left of the toolbar. If it is an image, make sure it\n"
"has a transparent background and use the <img /> tag. Keep size as 200px x 30px"
-msgstr "نام تجاری همان چیزی است که در سمت چپ بالای نوار ابزار ظاهر میشود. اگر تصویر است، مطمئن شوید که\n"
+msgstr "برند همان چیزی است که در سمت چپ بالای نوار ابزار ظاهر میشود. اگر تصویر است، مطمئن شوید که\n"
"دارای پسزمینه شفاف است و از تگ <img /> استفاده کنید. اندازه را 200×30 پیکسل نگه دارید"
#. Label of the breadcrumbs (Code) field in DocType 'Web Form'
@@ -13912,7 +13912,7 @@ msgstr "LDAP فعال نیست."
#. Label of the ldap_search_path_group (Data) field in DocType 'LDAP Settings'
#: frappe/integrations/doctype/ldap_settings/ldap_settings.json
msgid "LDAP search path for Groups"
-msgstr "مسیر جستجوی LDAP برای گروه ها"
+msgstr "مسیر جستجوی LDAP برای گروهها"
#. Label of the ldap_search_path_user (Data) field in DocType 'LDAP Settings'
#: frappe/integrations/doctype/ldap_settings/ldap_settings.json
@@ -16231,7 +16231,7 @@ msgstr "نظر جدید در مورد {0}: {1}"
#: frappe/public/js/frappe/form/templates/contact_list.html:3
msgid "New Contact"
-msgstr "تماس جدید"
+msgstr "مخاطب جدید"
#: frappe/public/js/frappe/widgets/widget_dialog.js:70
msgid "New Custom Block"
@@ -17384,7 +17384,7 @@ msgstr "تعداد بک آپ های DB نمیتواند کمتر از 1 با
#. Label of the number_of_groups (Int) field in DocType 'Dashboard Chart'
#: frappe/desk/doctype/dashboard_chart/dashboard_chart.json
msgid "Number of Groups"
-msgstr "تعداد گروه ها"
+msgstr "تعداد گروهها"
#. Label of the number_of_queries (Int) field in DocType 'Recorder'
#: frappe/core/doctype/recorder/recorder.json
@@ -20425,11 +20425,11 @@ msgstr "دلیل"
#: frappe/public/js/frappe/views/reports/query_report.js:889
msgid "Rebuild"
-msgstr "بازسازی کنید"
+msgstr "بازسازی"
#: frappe/public/js/frappe/views/treeview.js:509
msgid "Rebuild Tree"
-msgstr "درخت را بازسازی کنید"
+msgstr "بازسازی درخت"
#: frappe/utils/nestedset.py:177
msgid "Rebuilding of tree is not supported for {}"
@@ -21021,7 +21021,7 @@ msgstr ""
#: frappe/core/doctype/communication/communication.js:43
#: frappe/desk/doctype/todo/todo.js:36
msgid "Reopen"
-msgstr "دوباره باز کنید"
+msgstr "باز کردن دوباره"
#: frappe/public/js/frappe/form/toolbar.js:544
msgid "Repeat"
@@ -21402,7 +21402,7 @@ msgstr "نیاز به گواهی مورد اعتماد"
#. 'LDAP Settings'
#: frappe/integrations/doctype/ldap_settings/ldap_settings.json
msgid "Requires any valid fdn path. i.e. ou=groups,dc=example,dc=com"
-msgstr "به هر مسیر fdn معتبر نیاز دارد. یعنی ou=گروه ها،dc=example,dc=com"
+msgstr "به هر مسیر fdn معتبر نیاز دارد. یعنی ou=گروهها،dc=example,dc=com"
#. Description of the 'LDAP search path for Users' (Data) field in DocType
#. 'LDAP Settings'
@@ -27774,7 +27774,7 @@ msgstr "استفاده از POST"
#. Label of the use_report_chart (Check) field in DocType 'Dashboard Chart'
#: frappe/desk/doctype/dashboard_chart/dashboard_chart.json
msgid "Use Report Chart"
-msgstr "از نمودار گزارش استفاده کنید"
+msgstr "استفاده از نمودار گزارش"
#. Label of the use_ssl (Check) field in DocType 'Email Account'
#. Label of the use_ssl_for_outgoing (Check) field in DocType 'Email Account'
diff --git a/frappe/locale/sr_CS.po b/frappe/locale/sr_CS.po
index 75fed5e46c..248ac74bde 100644
--- a/frappe/locale/sr_CS.po
+++ b/frappe/locale/sr_CS.po
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-05-18 09:33+0000\n"
-"PO-Revision-Date: 2025-05-19 07:02\n"
+"PO-Revision-Date: 2025-05-25 10:26\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Serbian (Latin)\n"
"MIME-Version: 1.0\n"
@@ -46,7 +46,7 @@ msgstr "\"Članovi tima\" ili \"Menadžment\""
#: frappe/public/js/frappe/form/form.js:1090
msgid "\"amended_from\" field must be present to do an amendment."
-msgstr "Polje \"amended_from\" mora postojati da bi se izvršila promena."
+msgstr "Polje \"Izmenjeno iz\" mora postojati da bi se izvršila promena."
#: frappe/utils/csvutils.py:246
msgid "\"{0}\" is not a valid Google Sheets URL"
@@ -1736,7 +1736,7 @@ msgstr "Svi zapisi"
#: frappe/public/js/frappe/form/form.js:2222
msgid "All Submissions"
-msgstr "Svi podneti podaci"
+msgstr "Sve podneseno"
#: frappe/custom/doctype/customize_form/customize_form.js:452
msgid "All customizations will be removed. Please confirm."
@@ -1823,7 +1823,7 @@ msgstr "Dozvoli gosta"
#. Label of the allow_guest_to_view (Check) field in DocType 'DocType'
#: frappe/core/doctype/doctype/doctype.json
msgid "Allow Guest to View"
-msgstr "Dozvola gostu da pregleda"
+msgstr "Dozvoli gostu da pregleda"
#. Label of the allow_guest_to_comment (Check) field in DocType 'Blog Settings'
#: frappe/website/doctype/blog_settings/blog_settings.json
@@ -2143,7 +2143,7 @@ msgstr "Izmenjeni dokumenti"
#: frappe/core/doctype/transaction_log/transaction_log.json
#: frappe/website/doctype/personal_data_download_request/personal_data_download_request.json
msgid "Amended From"
-msgstr "Izmenjeno od"
+msgstr "Izmenjeno iz"
#: frappe/public/js/frappe/form/save.js:12
msgctxt "Freeze message while amending a document"
@@ -3614,7 +3614,7 @@ msgstr "Podešavanje bloga"
#. Label of the blog_title (Data) field in DocType 'Blog Settings'
#: frappe/website/doctype/blog_settings/blog_settings.json
msgid "Blog Title"
-msgstr "Naziv bloga"
+msgstr "Naslov bloga"
#. Name of a role
#. Label of the blogger (Link) field in DocType 'Blog Post'
@@ -4043,7 +4043,7 @@ msgstr "Callback poruka"
#. Label of the callback_title (Data) field in DocType 'Onboarding Step'
#: frappe/desk/doctype/onboarding_step/onboarding_step.json
msgid "Callback Title"
-msgstr "Callback naziv"
+msgstr "Callback naslov"
#: frappe/public/js/frappe/file_uploader/FileUploader.vue:150
#: frappe/public/js/frappe/ui/capture.js:334
@@ -4743,7 +4743,7 @@ msgstr "Očisti filtere"
#. Label of the days (Int) field in DocType 'Logs To Clear'
#: frappe/core/doctype/logs_to_clear/logs_to_clear.json
msgid "Clear Logs After (days)"
-msgstr "Očisti dnevnike nakon (dana)"
+msgstr "Očisti evidencije nakon (dana)"
#: frappe/core/doctype/user_permission/user_permission_list.js:144
msgid "Clear User Permissions"
@@ -5610,7 +5610,7 @@ msgstr "Sadržaj (Markdown)"
#. Label of the content_hash (Data) field in DocType 'File'
#: frappe/core/doctype/file/file.json
msgid "Content Hash"
-msgstr "Heš sadržaja"
+msgstr "Heš sadržaj"
#. Label of the content_type (Select) field in DocType 'Newsletter'
#. Label of the content_type (Select) field in DocType 'Blog Post'
@@ -6220,7 +6220,7 @@ msgstr "Prilagođene opcije"
#. Label of the custom_overrides (Code) field in DocType 'Website Theme'
#: frappe/website/doctype/website_theme/website_theme.json
msgid "Custom Overrides"
-msgstr "Prilagodi izmene"
+msgstr "Prilagođene izmene"
#. Option for the 'Report Type' (Select) field in DocType 'Report'
#: frappe/core/doctype/report/report.json
@@ -6413,7 +6413,7 @@ msgstr "Celodnevno"
#. Option for the 'Frequency' (Select) field in DocType 'Scheduled Job Type'
#: frappe/core/doctype/scheduled_job_type/scheduled_job_type.json
msgid "Daily Maintenance"
-msgstr ""
+msgstr "Dnevno održavanje"
#. Option for the 'Style' (Select) field in DocType 'Workflow State'
#: frappe/workflow/doctype/workflow_state/workflow_state.json
@@ -7141,7 +7141,7 @@ msgstr "Zavisnosti i licence"
#: frappe/custom/doctype/custom_field/custom_field.json
#: frappe/custom/doctype/customize_form_field/customize_form_field.json
msgid "Depends On"
-msgstr "Zavisni od"
+msgstr "Zavisi od"
#: frappe/public/js/frappe/ui/filters/filter.js:32
msgid "Descendants Of"
@@ -7385,7 +7385,7 @@ msgstr "Onemogući SMTP server autentifikaciju"
#. Settings'
#: frappe/desk/doctype/list_view_settings/list_view_settings.json
msgid "Disable Sidebar Stats"
-msgstr "Onemogući bočnu traku"
+msgstr "Onemogući statistiku u bočnoj traci"
#: frappe/website/doctype/website_settings/website_settings.js:146
msgid "Disable Signup for your site"
@@ -8755,7 +8755,7 @@ msgstr "Član imejl grupe"
#. Label of the email_header (Data) field in DocType 'Notification Log'
#: frappe/desk/doctype/notification_log/notification_log.json
msgid "Email Header"
-msgstr ""
+msgstr "Zaglavlje imejla"
#. Label of the email_id (Data) field in DocType 'Contact Email'
#. Label of the email_id (Data) field in DocType 'User Email'
@@ -8845,7 +8845,7 @@ msgstr "Imejl podešavanja"
#. Label of the email_signature (Text Editor) field in DocType 'User'
#: frappe/core/doctype/user/user.json
msgid "Email Signature"
-msgstr "Imejl potpi"
+msgstr "Imejl potpis"
#. Label of the email_status (Select) field in DocType 'Communication'
#: frappe/core/doctype/communication/communication.json
@@ -9106,7 +9106,7 @@ msgstr "Omogući kreiranje standardnog veb-šablona u razvojnom režimu"
#. 'Blog Post'
#: frappe/website/doctype/blog_post/blog_post.json
msgid "Enable email notification for any comment or likes received on your Blog Post."
-msgstr "Omogući obaveštenje putem imejla za svaki komentar illi lajk na Vašoj objavi na blogu."
+msgstr "Omogući obaveštenje putem imejla za svaki komentar ili lajk na Vašoj objavi na blogu."
#. Description of the 'Modal Trigger' (Check) field in DocType 'Form Tour Step'
#: frappe/desk/doctype/form_tour_step/form_tour_step.json
@@ -9257,7 +9257,7 @@ msgstr "Energetski poen"
#. Label of the enqueued_by (Data) field in DocType 'Submission Queue'
#: frappe/core/doctype/submission_queue/submission_queue.json
msgid "Enqueued By"
-msgstr "Stavljeno u redu od strane"
+msgstr "Stavljeno u red od strane"
#: frappe/core/doctype/recorder/recorder.py:125
msgid "Enqueued creation of indexes"
@@ -9508,7 +9508,7 @@ msgstr "Primer: \"boje\": [\"#d1d8dd\", \"#ff5858\"]"
#. Label of the exact_copies (Int) field in DocType 'Recorder Query'
#: frappe/core/doctype/recorder_query/recorder_query.json
msgid "Exact Copies"
-msgstr "Identične kompije"
+msgstr "Identične kopije"
#. Label of the example (HTML) field in DocType 'Workflow Transition'
#: frappe/workflow/doctype/workflow_transition/workflow_transition.json
@@ -9696,7 +9696,7 @@ msgstr "Izvoz redova koji sadrže grešku"
#. Label of the export_from (Data) field in DocType 'Access Log'
#: frappe/core/doctype/access_log/access_log.json
msgid "Export From"
-msgstr "Izvoz od"
+msgstr "Izvoz iz"
#: frappe/core/doctype/data_import/data_import.js:518
msgid "Export Import Log"
@@ -9901,7 +9901,7 @@ msgstr "Neuspešno dobijanje informacija o sajtu"
#: frappe/model/virtual_doctype.py:63
msgid "Failed to import virtual doctype {}, is controller file present?"
-msgstr "Neuspešan pokušaj uvoza virtuelnog doctype {}, da lije fajl kontrolera prisutan?"
+msgstr "Neuspešan pokušaj uvoza virtuelnog doctype {}, da li je fajl kontrolera prisutan?"
#: frappe/utils/image.py:75
msgid "Failed to optimize image: {0}"
@@ -10522,7 +10522,7 @@ msgstr "Prilagodi"
#. Label of the flag (Data) field in DocType 'Language'
#: frappe/core/doctype/language/language.json
msgid "Flag"
-msgstr "Zastavica"
+msgstr "Zastava"
#. Option for the 'Type' (Select) field in DocType 'DocField'
#. Option for the 'Fieldtype' (Select) field in DocType 'Report Column'
@@ -12186,7 +12186,7 @@ msgstr "Tokom svakog časa"
#. Option for the 'Frequency' (Select) field in DocType 'Scheduled Job Type'
#: frappe/core/doctype/scheduled_job_type/scheduled_job_type.json
msgid "Hourly Maintenance"
-msgstr ""
+msgstr "Održavanje na svakih sat vremena"
#. Description of the 'Password Reset Link Generation Limit' (Int) field in
#. DocType 'System Settings'
@@ -14221,23 +14221,23 @@ msgstr "Poslednjih 10 aktivnih korisnika"
#: frappe/public/js/frappe/ui/filters/filter.js:627
msgid "Last 14 Days"
-msgstr ""
+msgstr "Poslednjih 14 dana"
#: frappe/public/js/frappe/ui/filters/filter.js:631
msgid "Last 30 Days"
-msgstr ""
+msgstr "Poslednjih 30 dana"
#: frappe/public/js/frappe/ui/filters/filter.js:651
msgid "Last 6 Months"
-msgstr ""
+msgstr "Poslednjih 6 meseci"
#: frappe/public/js/frappe/ui/filters/filter.js:623
msgid "Last 7 Days"
-msgstr ""
+msgstr "Poslednjih 7 dana"
#: frappe/public/js/frappe/ui/filters/filter.js:635
msgid "Last 90 Days"
-msgstr ""
+msgstr "Poslednjih 90 dana"
#. Label of the last_active (Datetime) field in DocType 'User'
#: frappe/core/doctype/user/user.json
@@ -15187,7 +15187,7 @@ msgstr "MIT licenca"
#: frappe/desk/page/setup_wizard/install_fixtures.py:48
msgid "Madam"
-msgstr "Gospođo"
+msgstr "Gospođa"
#. Label of the main_section (Text Editor) field in DocType 'Web Page'
#: frappe/website/doctype/web_page/web_page.json
@@ -15863,7 +15863,7 @@ msgstr "Mobilni"
#: frappe/tests/test_translate.py:89 frappe/tests/test_translate.py:91
#: frappe/tests/test_translate.py:94
msgid "Mobile No"
-msgstr ""
+msgstr "Broj mobilnog telefona"
#. Label of the modal_trigger (Check) field in DocType 'Form Tour Step'
#: frappe/desk/doctype/form_tour_step/form_tour_step.json
@@ -16089,7 +16089,7 @@ msgstr "Više članaka o {0}"
#. Settings'
#: frappe/website/doctype/about_us_settings/about_us_settings.json
msgid "More content for the bottom of the page."
-msgstr "Više sadržaja za dno stranice."
+msgstr "Dodatni sadržaj za dno stranice."
#: frappe/public/js/frappe/ui/sort_selector.js:193
msgid "Most Used"
@@ -16667,19 +16667,19 @@ msgstr "Sledeće"
#: frappe/public/js/frappe/ui/filters/filter.js:683
msgid "Next 14 Days"
-msgstr ""
+msgstr "Narednih 14 dana"
#: frappe/public/js/frappe/ui/filters/filter.js:687
msgid "Next 30 Days"
-msgstr ""
+msgstr "Narednih 30 dana"
#: frappe/public/js/frappe/ui/filters/filter.js:703
msgid "Next 6 Months"
-msgstr ""
+msgstr "Narednih 6 meseci"
#: frappe/public/js/frappe/ui/filters/filter.js:679
msgid "Next 7 Days"
-msgstr ""
+msgstr "Narednih 7 dana"
#. Label of the next_action_email_template (Link) field in DocType 'Workflow
#. Document State'
@@ -16704,11 +16704,11 @@ msgstr "Naredni korak obilaska obrasca"
#: frappe/public/js/frappe/ui/filters/filter.js:695
msgid "Next Month"
-msgstr ""
+msgstr "Sledeći mesec"
#: frappe/public/js/frappe/ui/filters/filter.js:699
msgid "Next Quarter"
-msgstr ""
+msgstr "Sledeći kvartal"
#. Label of the next_schedule_date (Date) field in DocType 'Auto Repeat'
#: frappe/automation/doctype/auto_repeat/auto_repeat.json
@@ -16738,11 +16738,11 @@ msgstr "Sledeći token za sinhronizaciju"
#: frappe/public/js/frappe/ui/filters/filter.js:691
msgid "Next Week"
-msgstr ""
+msgstr "Sledeće nedelje"
#: frappe/public/js/frappe/ui/filters/filter.js:707
msgid "Next Year"
-msgstr ""
+msgstr "Sledeće godine"
#: frappe/public/js/frappe/form/workflow.js:45
msgid "Next actions"
@@ -20369,7 +20369,7 @@ msgstr "U redu stavljen"
#. Label of the queued_by (Data) field in DocType 'Prepared Report'
#: frappe/core/doctype/prepared_report/prepared_report.json
msgid "Queued By"
-msgstr "U redu od strane"
+msgstr "Stavljeno u red od strane"
#: frappe/core/doctype/submission_queue/submission_queue.py:174
msgid "Queued for Submission. You can track the progress over {0}."
@@ -22110,7 +22110,7 @@ msgstr "Indeks reda"
#. Label of the row_indexes (Code) field in DocType 'Data Import Log'
#: frappe/core/doctype/data_import_log/data_import_log.json
msgid "Row Indexes"
-msgstr "Indeksi redova"
+msgstr "Indeksi reda"
#. Label of the row_name (Data) field in DocType 'Property Setter'
#: frappe/custom/doctype/property_setter/property_setter.json
@@ -23525,7 +23525,7 @@ msgstr "Funkcionalnost serverskih skripti nije dostupna na ovom sajtu."
#: frappe/public/js/frappe/request.js:254
msgid "Server failed to process this request because of a concurrent conflicting request. Please try again."
-msgstr ""
+msgstr "Server nije uspeo da obradi zahtev zbog istovremenog konfliktnog zahteva. Molimo Vas da pokušate ponovo."
#: frappe/public/js/frappe/request.js:246
msgid "Server was too busy to process this request. Please try again."
@@ -25382,7 +25382,7 @@ msgstr "Simbol"
#: frappe/integrations/doctype/google_calendar/google_calendar.json
#: frappe/integrations/doctype/google_contacts/google_contacts.json
msgid "Sync"
-msgstr "SInhronizuj"
+msgstr "Sinhronizuj"
#: frappe/integrations/doctype/google_calendar/google_calendar.js:28
msgid "Sync Calendar"
@@ -25648,7 +25648,7 @@ msgstr "Neophodno se privilegije sistem menadžera."
#. Option for the 'Channel' (Select) field in DocType 'Notification'
#: frappe/email/doctype/notification/notification.json
msgid "System Notification"
-msgstr "Sistemsko obaveštenja"
+msgstr "Sistemsko obaveštenje"
#. Label of the system_page (Check) field in DocType 'Page'
#: frappe/core/doctype/page/page.json
@@ -26060,7 +26060,7 @@ msgstr "Dokument je dodeljen korisniku {0}"
#: frappe/desk/doctype/dashboard_chart/dashboard_chart.json
#: frappe/desk/doctype/number_card/number_card.json
msgid "The document type selected is a child table, so the parent document type is required."
-msgstr "Izabrana vrsta dokumenta je podtabela, stoga je potrebna matična vrsta dokumenta."
+msgstr "Izabrana vrsta dokumenta je zavisna tabela, stoga je potrebna matična vrsta dokumenta."
#: frappe/core/doctype/user_type/user_type.py:110
msgid "The field {0} is mandatory"
@@ -26317,19 +26317,19 @@ msgstr "Ova Kanban tabla će biti privatna"
#: frappe/public/js/frappe/ui/filters/filter.js:665
msgid "This Month"
-msgstr ""
+msgstr "Ovaj mesec"
#: frappe/public/js/frappe/ui/filters/filter.js:669
msgid "This Quarter"
-msgstr ""
+msgstr "Ovaj kvartal"
#: frappe/public/js/frappe/ui/filters/filter.js:661
msgid "This Week"
-msgstr ""
+msgstr "Ove nedelje"
#: frappe/public/js/frappe/ui/filters/filter.js:673
msgid "This Year"
-msgstr ""
+msgstr "Ove godine"
#: frappe/custom/doctype/customize_form/customize_form.js:220
msgid "This action is irreversible. Do you wish to continue?"
@@ -26663,7 +26663,7 @@ msgstr "Vremenska zona"
#. Label of the time_zones (Text) field in DocType 'Country'
#: frappe/geo/doctype/country/country.json
msgid "Time Zones"
-msgstr "Vremenske zona"
+msgstr "Vremenske zone"
#. Label of the time_format (Data) field in DocType 'Country'
#: frappe/geo/doctype/country/country.json
@@ -26926,7 +26926,7 @@ msgstr "Da biste izvršili izvoz ovog koraka kao JSON, povežite ga u dokumentu
#: frappe/email/doctype/email_account/email_account.js:126
msgid "To generate password click {0}"
-msgstr ""
+msgstr "Za generisanje lozinke kliknite {0}"
#: frappe/public/js/frappe/views/reports/query_report.js:857
msgid "To get the updated report, click on {0}."
@@ -26934,7 +26934,7 @@ msgstr "Za ažurirani izveštaj kliknite na {0}."
#: frappe/email/doctype/email_account/email_account.js:139
msgid "To know more click {0}"
-msgstr ""
+msgstr "Za više informacija kliknite {0}"
#. Description of the 'Console' (Code) field in DocType 'System Console'
#: frappe/desk/doctype/system_console/system_console.json
@@ -27044,7 +27044,7 @@ msgstr "Token nedostaje"
#: frappe/public/js/frappe/ui/filters/filter.js:738
msgid "Tomorrow"
-msgstr ""
+msgstr "Sutra"
#: frappe/desk/doctype/bulk_update/bulk_update.py:68
#: frappe/model/workflow.py:254
@@ -27110,7 +27110,7 @@ msgstr "Najčešće greške"
#: frappe/printing/doctype/print_format/print_format.json
#: frappe/public/js/print_format_builder/PrintFormatControls.vue:244
msgid "Top Left"
-msgstr "Gore desno"
+msgstr "Gore levo"
#. Option for the 'Position' (Select) field in DocType 'Form Tour Step'
#. Option for the 'Page Number' (Select) field in DocType 'Print Format'
@@ -27643,7 +27643,7 @@ msgstr "Ukloni dodeljivanje uslova"
#: frappe/app.py:383
msgid "Uncaught Exception"
-msgstr "Neočekivani izuzetak"
+msgstr "Neuhvaćeni izuzetak"
#: frappe/public/js/frappe/form/toolbar.js:103
msgid "Unchanged"
@@ -27973,7 +27973,7 @@ msgstr "Otpremanje na Google Drive"
#: frappe/desk/doctype/onboarding_step/onboarding_step.json
#, python-format
msgid "Use % for any non empty value."
-msgstr "Koristite % fza bilo koju vrednost koja nije prazna."
+msgstr "Koristite % za bilo koju vrednost koja nije prazna."
#. Label of the ascii_encode_password (Check) field in DocType 'Email Account'
#: frappe/email/doctype/email_account/email_account.json
@@ -28802,7 +28802,7 @@ msgstr "Prikaži {0}"
#. Label of the viewed_by (Data) field in DocType 'View Log'
#: frappe/core/doctype/view_log/view_log.json
msgid "Viewed By"
-msgstr "Pogledano od strane"
+msgstr "Uvid od strane"
#. Group in DocType's connections
#. Label of a Card Break in the Build Workspace
@@ -29706,7 +29706,7 @@ msgstr "Da"
#: frappe/public/js/frappe/ui/filters/filter.js:726
msgid "Yesterday"
-msgstr ""
+msgstr "Juče"
#: frappe/public/js/frappe/utils/user.js:33
msgctxt "Name of the current user. For example: You edited this 5 hours ago."
@@ -30646,7 +30646,7 @@ msgstr "nonce"
#. Label of the notified (Check) field in DocType 'Reminder'
#: frappe/automation/doctype/reminder/reminder.json
msgid "notified"
-msgstr "obvešten"
+msgstr "obavešten"
#: frappe/public/js/frappe/utils/pretty_date.js:25
msgid "now"
diff --git a/frappe/locale/sv.po b/frappe/locale/sv.po
index f7b2558b57..378bcbf981 100644
--- a/frappe/locale/sv.po
+++ b/frappe/locale/sv.po
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-05-18 09:33+0000\n"
-"PO-Revision-Date: 2025-05-19 07:02\n"
+"PO-Revision-Date: 2025-05-26 10:24\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Swedish\n"
"MIME-Version: 1.0\n"
@@ -8299,12 +8299,12 @@ msgstr "Rullgardin Meny"
#. Label of the date (Date) field in DocType 'ToDo'
#: frappe/desk/doctype/todo/todo.json
msgid "Due Date"
-msgstr "Förfallodatum"
+msgstr "Förfallo Datum"
#. Label of the due_date_based_on (Select) field in DocType 'Assignment Rule'
#: frappe/automation/doctype/assignment_rule/assignment_rule.json
msgid "Due Date Based On"
-msgstr "Förfallodatum Baserad På"
+msgstr "Förfallo Datum Baserad På"
#: frappe/public/js/frappe/form/grid_row_form.js:42
#: frappe/public/js/frappe/form/toolbar.js:419
@@ -9631,7 +9631,7 @@ msgstr "Förfallo Avisering Aktiverad"
#. Option for the 'Delivery Status' (Select) field in DocType 'Communication'
#: frappe/core/doctype/communication/communication.json
msgid "Expired"
-msgstr "Utgången"
+msgstr "Utgått"
#. Label of the expires_in (Int) field in DocType 'OAuth Bearer Token'
#. Label of the expires_in (Int) field in DocType 'Token Cache'
@@ -18262,7 +18262,7 @@ msgstr "Outlook.com"
#: frappe/desk/doctype/system_console/system_console.json
#: frappe/integrations/doctype/integration_request/integration_request.json
msgid "Output"
-msgstr "Utgång"
+msgstr "Utdata"
#: frappe/public/js/frappe/form/templates/form_dashboard.html:5
msgid "Overview"
@@ -30299,7 +30299,7 @@ msgstr "Roll "
#. Label of the profile (Code) field in DocType 'Recorder'
#: frappe/core/doctype/recorder/recorder.json
msgid "cProfile Output"
-msgstr "cProfil Utgång"
+msgstr "cProfil Utdata"
#: frappe/public/js/frappe/ui/toolbar/search_utils.js:286
msgid "calendar"
diff --git a/frappe/locale/zh.po b/frappe/locale/zh.po
index 1a379867c5..2c8fd9cbe0 100644
--- a/frappe/locale/zh.po
+++ b/frappe/locale/zh.po
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: developers@frappe.io\n"
"POT-Creation-Date: 2025-05-18 09:33+0000\n"
-"PO-Revision-Date: 2025-05-19 07:02\n"
+"PO-Revision-Date: 2025-05-25 10:26\n"
"Last-Translator: developers@frappe.io\n"
"Language-Team: Chinese Simplified\n"
"MIME-Version: 1.0\n"
@@ -5169,7 +5169,7 @@ msgstr "每小时评论限制"
#: frappe/desk/form/utils.py:75
msgid "Comment publicity can only be updated by the original author or a System Manager."
-msgstr ""
+msgstr "评论公开状态仅可由原作者或系统管理员修改。"
#: frappe/model/meta.py:57 frappe/public/js/frappe/form/controls/comment.js:9
#: frappe/public/js/frappe/model/meta.js:209
@@ -6413,7 +6413,7 @@ msgstr "每日长格式"
#. Option for the 'Frequency' (Select) field in DocType 'Scheduled Job Type'
#: frappe/core/doctype/scheduled_job_type/scheduled_job_type.json
msgid "Daily Maintenance"
-msgstr ""
+msgstr "日常维护"
#. Option for the 'Style' (Select) field in DocType 'Workflow State'
#: frappe/workflow/doctype/workflow_state/workflow_state.json
@@ -8755,7 +8755,7 @@ msgstr "电子邮件组成员"
#. Label of the email_header (Data) field in DocType 'Notification Log'
#: frappe/desk/doctype/notification_log/notification_log.json
msgid "Email Header"
-msgstr ""
+msgstr "邮件标头"
#. Label of the email_id (Data) field in DocType 'Contact Email'
#. Label of the email_id (Data) field in DocType 'User Email'
@@ -8905,7 +8905,7 @@ msgstr "未通过{0}验证的电子邮件"
#: frappe/email/doctype/email_queue/email_queue.js:19
msgid "Email queue is currently suspended. Resume to automatically send other emails."
-msgstr ""
+msgstr "邮件队列已暂停。恢复后系统将自动发送其他邮件。"
#. Label of the section_break_udjs (Section Break) field in DocType 'System
#. Health Report'
@@ -12186,7 +12186,7 @@ msgstr "每小时长格式"
#. Option for the 'Frequency' (Select) field in DocType 'Scheduled Job Type'
#: frappe/core/doctype/scheduled_job_type/scheduled_job_type.json
msgid "Hourly Maintenance"
-msgstr ""
+msgstr "按小时维护"
#. Description of the 'Password Reset Link Generation Limit' (Int) field in
#. DocType 'System Settings'
@@ -14221,11 +14221,11 @@ msgstr "最近10个活跃用户"
#: frappe/public/js/frappe/ui/filters/filter.js:627
msgid "Last 14 Days"
-msgstr ""
+msgstr "过去14天"
#: frappe/public/js/frappe/ui/filters/filter.js:631
msgid "Last 30 Days"
-msgstr ""
+msgstr "过去30天"
#: frappe/public/js/frappe/ui/filters/filter.js:651
msgid "Last 6 Months"
@@ -14233,11 +14233,11 @@ msgstr "过去6个月"
#: frappe/public/js/frappe/ui/filters/filter.js:623
msgid "Last 7 Days"
-msgstr ""
+msgstr "过去7天"
#: frappe/public/js/frappe/ui/filters/filter.js:635
msgid "Last 90 Days"
-msgstr ""
+msgstr "过去90天"
#. Label of the last_active (Datetime) field in DocType 'User'
#: frappe/core/doctype/user/user.json
@@ -16667,11 +16667,11 @@ msgstr "下一步"
#: frappe/public/js/frappe/ui/filters/filter.js:683
msgid "Next 14 Days"
-msgstr ""
+msgstr "未来 14 天"
#: frappe/public/js/frappe/ui/filters/filter.js:687
msgid "Next 30 Days"
-msgstr ""
+msgstr "未来30天"
#: frappe/public/js/frappe/ui/filters/filter.js:703
msgid "Next 6 Months"
@@ -16679,7 +16679,7 @@ msgstr "未来6个月"
#: frappe/public/js/frappe/ui/filters/filter.js:679
msgid "Next 7 Days"
-msgstr ""
+msgstr "未来 7 天"
#. Label of the next_action_email_template (Link) field in DocType 'Workflow
#. Document State'
@@ -18580,7 +18580,7 @@ msgstr "父项是数据将被添加到的文档名称"
#: frappe/public/js/frappe/ui/group_by/group_by.js:251
msgid "Parent-to-child or child-to-parent grouping is not allowed."
-msgstr ""
+msgstr "禁止父子层级互相嵌套的分组方式。"
#: frappe/permissions.py:798
msgid "Parentfield not specified in {0}: {1}"
@@ -23525,7 +23525,7 @@ msgstr "此站点未启用服务器脚本功能"
#: frappe/public/js/frappe/request.js:254
msgid "Server failed to process this request because of a concurrent conflicting request. Please try again."
-msgstr ""
+msgstr "因并发请求冲突,服务器未能处理本请求。请稍后重试。"
#: frappe/public/js/frappe/request.js:246
msgid "Server was too busy to process this request. Please try again."
@@ -26414,7 +26414,7 @@ msgstr "该文件已关联至受保护文档,不可删除。"
#: frappe/public/js/frappe/file_uploader/FilePreview.vue:76
msgid "This file is public and can be accessed by anyone, even without logging in. Mark it private to limit access."
-msgstr ""
+msgstr "本文件为公开文件,无需登录即可访问。请设为私有以限制访问权限。"
#: frappe/core/doctype/file/file.js:20
msgid "This file is public. It can be accessed without authentication."
@@ -26926,7 +26926,7 @@ msgstr "导出此步骤为JSON需关联到入职文档并保存"
#: frappe/email/doctype/email_account/email_account.js:126
msgid "To generate password click {0}"
-msgstr ""
+msgstr "生成密码请点击{0}"
#: frappe/public/js/frappe/views/reports/query_report.js:857
msgid "To get the updated report, click on {0}."
@@ -26934,7 +26934,7 @@ msgstr "获取更新后的报表请点击{0}"
#: frappe/email/doctype/email_account/email_account.js:139
msgid "To know more click {0}"
-msgstr ""
+msgstr "了解更多请点击{0}"
#. Description of the 'Console' (Code) field in DocType 'System Console'
#: frappe/desk/doctype/system_console/system_console.json
@@ -28831,7 +28831,7 @@ msgstr "可见性"
#: frappe/public/js/frappe/form/templates/timeline_message_box.html:40
msgid "Visible to website/portal users."
-msgstr ""
+msgstr "对网站/门户用户可见。"
#. Option for the 'Type' (Select) field in DocType 'Communication'
#: frappe/core/doctype/communication/communication.json
@@ -29578,11 +29578,11 @@ msgstr "工作区"
#: frappe/public/js/frappe/form/footer/form_timeline.js:731
msgid "Would you like to publish this comment? This means it will become visible to website/portal users."
-msgstr ""
+msgstr "是否确认发布本评论?发布后网站/门户用户可见。"
#: frappe/public/js/frappe/form/footer/form_timeline.js:735
msgid "Would you like to unpublish this comment? This means it will no longer be visible to website/portal users."
-msgstr ""
+msgstr "是否确认取消发布本评论?取消后网站/门户用户将不可见。"
#: frappe/desk/page/setup_wizard/setup_wizard.py:35
msgid "Wrapping up"
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 0a730c8b06..5ccfbf0cce 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -825,6 +825,8 @@ class BaseDocument:
return True
elif df.fieldtype == "Code" and df.options == "HTML" and has_text_or_img_tag:
return True
+ elif df.fieldtype == "Check":
+ return True # Checkboxes can't be mandatory, they're 0 by default
else:
return has_text_content
diff --git a/frappe/model/document.py b/frappe/model/document.py
index c37bb4b7a0..fad1bcbbed 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -1,6 +1,7 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
import hashlib
+import itertools
import json
import time
from collections.abc import Generator, Iterable
@@ -1320,7 +1321,8 @@ class Document(BaseDocument, DocRef):
elif self._action == "update_after_submit":
self.run_method("on_update_after_submit")
- self.clear_cache()
+ if not (frappe.flags.in_import and self.is_new()):
+ self.clear_cache()
if self.flags.get("notify_update", True):
self.notify_update()
@@ -1350,7 +1352,12 @@ class Document(BaseDocument, DocRef):
def notify_update(self):
"""Publish realtime that the current document is modified"""
- if frappe.flags.in_patch:
+ if (
+ frappe.flags.in_import
+ or frappe.flags.in_patch
+ or frappe.flags.in_migrate
+ or frappe.flags.in_install
+ ):
return
frappe.publish_realtime(
@@ -1456,14 +1463,13 @@ class Document(BaseDocument, DocRef):
doc_to_compare = frappe.get_doc(self.doctype, amended_from)
version = frappe.new_doc("Version")
+
+ if not doc_to_compare and not self.flags.updater_reference:
+ return
+
if version.update_version_info(doc_to_compare, self):
version.insert(ignore_permissions=True)
- if not frappe.flags.in_migrate:
- # follow since you made a change?
- if frappe.get_cached_value("User", frappe.session.user, "follow_created_documents"):
- follow_document(self.doctype, self.name, frappe.session.user)
-
@staticmethod
def hook(f):
"""Decorator: Make method `hookable` (i.e. extensible by another app).
@@ -1871,7 +1877,8 @@ def bulk_insert(
doctype: str,
documents: Iterable["Document"],
ignore_duplicates: bool = False,
- chunk_size=10_000,
+ chunk_size=1000,
+ commit_chunks=False,
):
"""Insert simple Documents objects to database in bulk.
@@ -1882,31 +1889,37 @@ def bulk_insert(
"""
doctype_meta = frappe.get_meta(doctype)
- documents = list(documents)
valid_column_map = {
doctype: doctype_meta.get_valid_columns(),
}
- values_map = {
- doctype: _document_values_generator(documents, valid_column_map[doctype]),
- }
- for child_table in doctype_meta.get_table_fields():
+ child_table_fields = doctype_meta.get_table_fields()
+ for child_table in child_table_fields:
valid_column_map[child_table.options] = frappe.get_meta(child_table.options).get_valid_columns()
- values_map[child_table.options] = _document_values_generator(
- [
- ch_doc
- for ch_doc in (
- child_docs for doc in documents for child_docs in doc.get(child_table.fieldname)
- )
- ],
- valid_column_map[child_table.options],
- )
- for dt, docs in values_map.items():
- frappe.db.bulk_insert(
- dt, valid_column_map[dt], docs, ignore_duplicates=ignore_duplicates, chunk_size=chunk_size
- )
+ documents = iter(documents)
+ while document_batch := list(itertools.islice(documents, chunk_size)):
+ values_map = {
+ doctype: _document_values_generator(document_batch, valid_column_map[doctype]),
+ }
+
+ for child_table in child_table_fields:
+ values_map[child_table.options] = _document_values_generator(
+ [
+ ch_doc
+ for ch_doc in (
+ child_docs for doc in document_batch for child_docs in doc.get(child_table.fieldname)
+ )
+ ],
+ valid_column_map[child_table.options],
+ )
+
+ for dt, docs in values_map.items():
+ frappe.db.bulk_insert(dt, valid_column_map[dt], docs, ignore_duplicates=ignore_duplicates)
+
+ if commit_chunks:
+ frappe.db.commit()
def _document_values_generator(
diff --git a/frappe/model/utils/link_count.py b/frappe/model/utils/link_count.py
index e2bc3f85f6..4d67297afe 100644
--- a/frappe/model/utils/link_count.py
+++ b/frappe/model/utils/link_count.py
@@ -2,6 +2,7 @@
# License: MIT. See LICENSE
from collections import defaultdict
+from random import random
import frappe
@@ -29,10 +30,13 @@ ignore_doctypes = {
}
+LINK_COUNT_BUFFER_SIZE = 256
+
+
def notify_link_count(doctype, name):
"""updates link count for given document"""
- if doctype in ignore_doctypes or not frappe.request:
+ if doctype in ignore_doctypes or not frappe.request or random() < 0.9: # Sample 10%
return
if not hasattr(frappe.local, "_link_count"):
@@ -50,13 +54,18 @@ def flush_local_link_count():
link_count = frappe.cache.get_value("_link_count") or {}
+ flush = False
for key, value in new_links.items():
if key in link_count:
link_count[key] += value
- else:
+ elif len(link_count) < LINK_COUNT_BUFFER_SIZE:
link_count[key] = value
+ else:
+ continue
+ flush = True
- frappe.cache.set_value("_link_count", link_count)
+ if flush:
+ frappe.cache.set_value("_link_count", link_count)
new_links.clear()
diff --git a/frappe/public/js/frappe/form/controls/code.js b/frappe/public/js/frappe/form/controls/code.js
index b3bee4b051..f8d60a4322 100644
--- a/frappe/public/js/frappe/form/controls/code.js
+++ b/frappe/public/js/frappe/form/controls/code.js
@@ -29,6 +29,7 @@ frappe.ui.form.ControlCode = class ControlCode extends frappe.ui.form.ControlTex
style="position: absolute; top: 32px; right: 5px;"
onmouseover="this.classList.add('btn-default')"
onmouseout="this.classList.remove('btn-default')"
+ title="${__("Copy to Clipboard")}"
>