feat!: enhance Language to become more of a Locale (#27178)
This commit is contained in:
parent
1feef4890c
commit
b91cacdd18
11 changed files with 224 additions and 51 deletions
|
|
@ -10,7 +10,12 @@
|
||||||
"language_code",
|
"language_code",
|
||||||
"language_name",
|
"language_name",
|
||||||
"flag",
|
"flag",
|
||||||
"based_on"
|
"based_on",
|
||||||
|
"section_break_rtth",
|
||||||
|
"date_format",
|
||||||
|
"time_format",
|
||||||
|
"number_format",
|
||||||
|
"first_day_of_the_week"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
|
|
@ -46,12 +51,40 @@
|
||||||
"fieldname": "enabled",
|
"fieldname": "enabled",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enabled"
|
"label": "Enabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_rtth",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "date_format",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Date Format",
|
||||||
|
"options": "\nyyyy-mm-dd\ndd-mm-yyyy\ndd/mm/yyyy\ndd.mm.yyyy\nmm/dd/yyyy\nmm-dd-yyyy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "time_format",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Time Format",
|
||||||
|
"options": "\nHH:mm:ss\nHH:mm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "number_format",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Number Format",
|
||||||
|
"options": "\n#,###.##\n#.###,##\n# ###.##\n# ###,##\n#'###.##\n#, ###.##\n#,##,###.##\n#,###.###\n#.###\n#,###"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "first_day_of_the_week",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "First Day of the Week",
|
||||||
|
"options": "\nSunday\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-globe",
|
"icon": "fa fa-globe",
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-06-06 18:25:01.010821",
|
"modified": "2024-07-21 08:25:25.130166",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Core",
|
"module": "Core",
|
||||||
"name": "Language",
|
"name": "Language",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import re
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.defaults import clear_default, set_default
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,10 +19,30 @@ class Language(Document):
|
||||||
from frappe.types import DF
|
from frappe.types import DF
|
||||||
|
|
||||||
based_on: DF.Link | None
|
based_on: DF.Link | None
|
||||||
|
date_format: DF.Literal[
|
||||||
|
"", "yyyy-mm-dd", "dd-mm-yyyy", "dd/mm/yyyy", "dd.mm.yyyy", "mm/dd/yyyy", "mm-dd-yyyy"
|
||||||
|
]
|
||||||
enabled: DF.Check
|
enabled: DF.Check
|
||||||
|
first_day_of_the_week: DF.Literal[
|
||||||
|
"", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
||||||
|
]
|
||||||
flag: DF.Data | None
|
flag: DF.Data | None
|
||||||
language_code: DF.Data
|
language_code: DF.Data
|
||||||
language_name: DF.Data
|
language_name: DF.Data
|
||||||
|
number_format: DF.Literal[
|
||||||
|
"",
|
||||||
|
"#,###.##",
|
||||||
|
"#.###,##",
|
||||||
|
"# ###.##",
|
||||||
|
"# ###,##",
|
||||||
|
"#'###.##",
|
||||||
|
"#, ###.##",
|
||||||
|
"#,##,###.##",
|
||||||
|
"#,###.###",
|
||||||
|
"#.###",
|
||||||
|
"#,###",
|
||||||
|
]
|
||||||
|
time_format: DF.Literal["", "HH:mm:ss", "HH:mm"]
|
||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
|
@ -33,6 +54,22 @@ class Language(Document):
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
frappe.cache.delete_value("languages_with_name")
|
frappe.cache.delete_value("languages_with_name")
|
||||||
frappe.cache.delete_value("languages")
|
frappe.cache.delete_value("languages")
|
||||||
|
self.update_user_defaults()
|
||||||
|
|
||||||
|
def update_user_defaults(self):
|
||||||
|
"""Update user defaults for date, time, number format and first day of the week.
|
||||||
|
|
||||||
|
When we change any settings of a language, the defaults for all users with that language
|
||||||
|
should be updated.
|
||||||
|
"""
|
||||||
|
users = frappe.get_all("User", filters={"language": self.name}, pluck="name")
|
||||||
|
for key in ("date_format", "time_format", "number_format", "first_day_of_the_week"):
|
||||||
|
if self.has_value_changed(key):
|
||||||
|
for user in users:
|
||||||
|
if new_value := self.get(key):
|
||||||
|
set_default(key, new_value, user)
|
||||||
|
else:
|
||||||
|
clear_default(key, parent=user)
|
||||||
|
|
||||||
|
|
||||||
def validate_with_regex(name, label):
|
def validate_with_regex(name, label):
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,18 @@ class User(Document):
|
||||||
if self.time_zone:
|
if self.time_zone:
|
||||||
frappe.defaults.set_default("time_zone", self.time_zone, self.name)
|
frappe.defaults.set_default("time_zone", self.time_zone, self.name)
|
||||||
|
|
||||||
|
if self.has_value_changed("language"):
|
||||||
|
locale_keys = ("date_format", "time_format", "number_format", "first_day_of_the_week")
|
||||||
|
if self.language:
|
||||||
|
language = frappe.get_doc("Language", self.language)
|
||||||
|
for key in locale_keys:
|
||||||
|
value = language.get(key)
|
||||||
|
if value:
|
||||||
|
frappe.defaults.set_default(key, value, self.name)
|
||||||
|
else:
|
||||||
|
for key in locale_keys:
|
||||||
|
frappe.defaults.clear_default(key, parent=self.name)
|
||||||
|
|
||||||
if self.has_value_changed("enabled"):
|
if self.has_value_changed("enabled"):
|
||||||
frappe.cache.delete_key("users_for_mentions")
|
frappe.cache.delete_key("users_for_mentions")
|
||||||
frappe.cache.delete_key("enabled_users")
|
frappe.cache.delete_key("enabled_users")
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,9 @@ def set_default(key, value, parent, parenttype="__default"):
|
||||||
else:
|
else:
|
||||||
_clear_cache(parent)
|
_clear_cache(parent)
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
clear_defaults_cache(parent)
|
||||||
|
|
||||||
|
|
||||||
def add_default(key, value, parent, parenttype=None):
|
def add_default(key, value, parent, parenttype=None):
|
||||||
d = frappe.get_doc(
|
d = frappe.get_doc(
|
||||||
|
|
|
||||||
52
frappe/locale.py
Normal file
52
frappe/locale.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import frappe
|
||||||
|
from frappe.utils.number_format import NumberFormat
|
||||||
|
|
||||||
|
|
||||||
|
def get_number_format(language: str | None = None) -> NumberFormat:
|
||||||
|
"""Return the number format for the given language.
|
||||||
|
|
||||||
|
:param language: The language code to get the value for. Defaults to the current user's language.
|
||||||
|
:return: The number format. Defaults to "#,###.##" if not found.
|
||||||
|
"""
|
||||||
|
number_format = get_locale_value("number_format", language) or "#,###.##"
|
||||||
|
return NumberFormat.from_string(number_format)
|
||||||
|
|
||||||
|
|
||||||
|
def get_date_format(language: str | None = None) -> str:
|
||||||
|
"""Return the date format for the given language.
|
||||||
|
|
||||||
|
:param language: The language code to get the value for. Defaults to the current user's language.
|
||||||
|
:return: The date format string. Defaults to "yyyy-mm-dd" if not found.
|
||||||
|
"""
|
||||||
|
return get_locale_value("date_format", language) or "yyyy-mm-dd"
|
||||||
|
|
||||||
|
|
||||||
|
def get_time_format(language: str | None = None) -> str:
|
||||||
|
"""Return the time format for the given language.
|
||||||
|
|
||||||
|
:param language: The language code to get the value for. Defaults to the current user's language.
|
||||||
|
:return: The time format string. Defaults to "HH:mm:ss" if not found.
|
||||||
|
"""
|
||||||
|
return get_locale_value("time_format", language) or "HH:mm:ss"
|
||||||
|
|
||||||
|
|
||||||
|
def get_first_day_of_the_week(language: str | None = None) -> str:
|
||||||
|
"""Return the first day of the week for the given language.
|
||||||
|
|
||||||
|
:param language: The language code to get the value for. Defaults to the current user's language.
|
||||||
|
:return: The first day of the week. Defaults to "Sunday" if not found.
|
||||||
|
"""
|
||||||
|
return get_locale_value("first_day_of_the_week", language) or "Sunday"
|
||||||
|
|
||||||
|
|
||||||
|
def get_locale_value(key: str, language: str | None = None) -> str | None:
|
||||||
|
"""Return the value of the key from the Language record or System Settings.
|
||||||
|
|
||||||
|
:param key: The settings key to get the value for.
|
||||||
|
:param language: The language code to get the value for. Defaults to the current user's language.
|
||||||
|
"""
|
||||||
|
lang = language or frappe.local.lang
|
||||||
|
if lang:
|
||||||
|
value = frappe.db.get_value("Language", lang, key)
|
||||||
|
|
||||||
|
return value or frappe.db.get_default(key)
|
||||||
|
|
@ -811,7 +811,7 @@ def get_field_currency(df, doc=None):
|
||||||
|
|
||||||
def get_field_precision(df, doc=None, currency=None):
|
def get_field_precision(df, doc=None, currency=None):
|
||||||
"""get precision based on DocField options and fieldvalue in doc"""
|
"""get precision based on DocField options and fieldvalue in doc"""
|
||||||
from frappe.utils import get_number_format_info
|
from frappe.locale import get_number_format
|
||||||
|
|
||||||
if df.precision:
|
if df.precision:
|
||||||
precision = cint(df.precision)
|
precision = cint(df.precision)
|
||||||
|
|
@ -819,8 +819,8 @@ def get_field_precision(df, doc=None, currency=None):
|
||||||
elif df.fieldtype == "Currency":
|
elif df.fieldtype == "Currency":
|
||||||
precision = cint(frappe.db.get_default("currency_precision"))
|
precision = cint(frappe.db.get_default("currency_precision"))
|
||||||
if not precision:
|
if not precision:
|
||||||
number_format = frappe.db.get_default("number_format") or "#,###.##"
|
number_format = get_number_format()
|
||||||
decimal_str, comma_str, precision = get_number_format_info(number_format)
|
precision = number_format.precision
|
||||||
else:
|
else:
|
||||||
precision = cint(frappe.db.get_default("float_precision")) or 3
|
precision = cint(frappe.db.get_default("float_precision")) or 3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.desk.utils import slug
|
from frappe.desk.utils import slug
|
||||||
|
from frappe.locale import get_date_format, get_first_day_of_the_week, get_number_format, get_time_format
|
||||||
|
from frappe.utils.deprecations import deprecated
|
||||||
|
from frappe.utils.number_format import NUMBER_FORMAT_MAP, NumberFormat
|
||||||
|
|
||||||
DateTimeLikeObject = str | datetime.date | datetime.datetime
|
DateTimeLikeObject = str | datetime.date | datetime.datetime
|
||||||
NumericType = int | float
|
NumericType = int | float
|
||||||
|
|
@ -85,10 +88,6 @@ class Weekday(Enum):
|
||||||
Saturday = 6
|
Saturday = 6
|
||||||
|
|
||||||
|
|
||||||
def get_first_day_of_the_week() -> str:
|
|
||||||
return frappe.get_system_settings("first_day_of_the_week") or "Sunday"
|
|
||||||
|
|
||||||
|
|
||||||
def get_start_of_week_index() -> int:
|
def get_start_of_week_index() -> int:
|
||||||
return Weekday[get_first_day_of_the_week()].value
|
return Weekday[get_first_day_of_the_week()].value
|
||||||
|
|
||||||
|
|
@ -677,9 +676,9 @@ def get_time_str(timedelta_obj: datetime.timedelta | str) -> str:
|
||||||
def get_user_date_format() -> str:
|
def get_user_date_format() -> str:
|
||||||
"""Get the current user date format. The result will be cached."""
|
"""Get the current user date format. The result will be cached."""
|
||||||
if getattr(frappe.local, "user_date_format", None) is None:
|
if getattr(frappe.local, "user_date_format", None) is None:
|
||||||
frappe.local.user_date_format = frappe.db.get_default("date_format")
|
frappe.local.user_date_format = get_date_format()
|
||||||
|
|
||||||
return frappe.local.user_date_format or "yyyy-mm-dd"
|
return frappe.local.user_date_format
|
||||||
|
|
||||||
|
|
||||||
get_user_format = get_user_date_format # for backwards compatibility
|
get_user_format = get_user_date_format # for backwards compatibility
|
||||||
|
|
@ -688,9 +687,9 @@ get_user_format = get_user_date_format # for backwards compatibility
|
||||||
def get_user_time_format() -> str:
|
def get_user_time_format() -> str:
|
||||||
"""Get the current user time format. The result will be cached."""
|
"""Get the current user time format. The result will be cached."""
|
||||||
if getattr(frappe.local, "user_time_format", None) is None:
|
if getattr(frappe.local, "user_time_format", None) is None:
|
||||||
frappe.local.user_time_format = frappe.db.get_default("time_format")
|
frappe.local.user_time_format = get_time_format()
|
||||||
|
|
||||||
return frappe.local.user_time_format or "HH:mm:ss"
|
return frappe.local.user_time_format
|
||||||
|
|
||||||
|
|
||||||
def format_date(string_date=None, format_string: str | None = None, parse_day_first: bool = False) -> str:
|
def format_date(string_date=None, format_string: str | None = None, parse_day_first: bool = False) -> str:
|
||||||
|
|
@ -1347,14 +1346,13 @@ def fmt_money(
|
||||||
format: str | None = None,
|
format: str | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Convert to string with commas for thousands, millions etc."""
|
"""Convert to string with commas for thousands, millions etc."""
|
||||||
number_format = format or frappe.db.get_default("number_format") or "#,###.##"
|
number_format = NumberFormat.from_string(format) if format else get_number_format()
|
||||||
|
|
||||||
if precision is None:
|
if precision is None:
|
||||||
precision = cint(frappe.db.get_default("currency_precision")) or None
|
precision = cint(frappe.db.get_default("currency_precision")) or None
|
||||||
|
|
||||||
decimal_str, comma_str, number_format_precision = get_number_format_info(number_format)
|
|
||||||
|
|
||||||
if precision is None:
|
if precision is None:
|
||||||
precision = number_format_precision
|
precision = number_format.precision
|
||||||
|
|
||||||
# 40,000 -> 40,000.00
|
# 40,000 -> 40,000.00
|
||||||
# 40,000.00000 -> 40,000.00
|
# 40,000.00000 -> 40,000.00
|
||||||
|
|
@ -1366,7 +1364,7 @@ def fmt_money(
|
||||||
if amount is None:
|
if amount is None:
|
||||||
amount = 0
|
amount = 0
|
||||||
|
|
||||||
if decimal_str:
|
if number_format.decimal_separator:
|
||||||
decimals_after = str(round(amount % 1, precision))
|
decimals_after = str(round(amount % 1, precision))
|
||||||
parts = decimals_after.split(".")
|
parts = decimals_after.split(".")
|
||||||
parts = parts[1] if len(parts) > 1 else parts[0]
|
parts = parts[1] if len(parts) > 1 else parts[0]
|
||||||
|
|
@ -1377,7 +1375,7 @@ def fmt_money(
|
||||||
fraction = frappe.db.get_value("Currency", currency, "fraction_units", cache=True) or 100
|
fraction = frappe.db.get_value("Currency", currency, "fraction_units", cache=True) or 100
|
||||||
precision = len(cstr(fraction)) - 1
|
precision = len(cstr(fraction)) - 1
|
||||||
else:
|
else:
|
||||||
precision = number_format_precision
|
precision = number_format.precision
|
||||||
elif len(decimals) < precision:
|
elif len(decimals) < precision:
|
||||||
precision = len(decimals)
|
precision = len(decimals)
|
||||||
|
|
||||||
|
|
@ -1399,7 +1397,7 @@ def fmt_money(
|
||||||
parts.append(amount[-3:])
|
parts.append(amount[-3:])
|
||||||
amount = amount[:-3]
|
amount = amount[:-3]
|
||||||
|
|
||||||
val = number_format == "#,##,###.##" and 2 or 3
|
val = 2 if number_format.string == "#,##,###.##" else 3
|
||||||
|
|
||||||
while len(amount) > val:
|
while len(amount) > val:
|
||||||
parts.append(amount[-val:])
|
parts.append(amount[-val:])
|
||||||
|
|
@ -1409,7 +1407,9 @@ def fmt_money(
|
||||||
|
|
||||||
parts.reverse()
|
parts.reverse()
|
||||||
|
|
||||||
amount = comma_str.join(parts) + ((precision and decimal_str) and (decimal_str + decimals) or "")
|
amount = number_format.thousands_separator.join(parts) + (
|
||||||
|
(precision and number_format.decimal_separator) and (number_format.decimal_separator + decimals) or ""
|
||||||
|
)
|
||||||
if amount != "0":
|
if amount != "0":
|
||||||
amount = minus + amount
|
amount = minus + amount
|
||||||
|
|
||||||
|
|
@ -1425,29 +1425,21 @@ def fmt_money(
|
||||||
return amount
|
return amount
|
||||||
|
|
||||||
|
|
||||||
number_format_info = {
|
# keep for backwards compatibility
|
||||||
"#,###.##": (".", ",", 2),
|
number_format_info = NUMBER_FORMAT_MAP
|
||||||
"#.###,##": (",", ".", 2),
|
|
||||||
"# ###.##": (".", " ", 2),
|
|
||||||
"# ###,##": (",", " ", 2),
|
|
||||||
"#'###.##": (".", "'", 2),
|
|
||||||
"#, ###.##": (".", ", ", 2),
|
|
||||||
"#,##,###.##": (".", ",", 2),
|
|
||||||
"#,###.###": (".", ",", 3),
|
|
||||||
"#.###": ("", ".", 0),
|
|
||||||
"#,###": ("", ",", 0),
|
|
||||||
"#.########": (".", "", 8),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@deprecated
|
||||||
def get_number_format_info(format: str) -> tuple[str, str, int]:
|
def get_number_format_info(format: str) -> tuple[str, str, int]:
|
||||||
"""Return the decimal separator, thousands separator and precision for the given number `format` string.
|
"""DEPRECATED: use `NumberFormat.from_string()` from `frappe.utils.number_format` instead.
|
||||||
|
|
||||||
e.g. get_number_format_info('1,00,000.50') -> ('.', ',', 2)
|
Return the decimal separator, thousands separator and precision for the given number `format` string.
|
||||||
|
|
||||||
|
e.g. get_number_format_info('#,##,###.##') -> ('.', ',', 2)
|
||||||
|
|
||||||
Will return ('.', ',', 2) for format strings which can't be guessed.
|
Will return ('.', ',', 2) for format strings which can't be guessed.
|
||||||
"""
|
"""
|
||||||
return number_format_info.get(format) or (".", ",", 2)
|
return NUMBER_FORMAT_MAP.get(format) or (".", ",", 2)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
@ -1481,13 +1473,13 @@ def money_in_words(
|
||||||
"Cent"
|
"Cent"
|
||||||
)
|
)
|
||||||
|
|
||||||
number_format = (
|
currency_format_str = frappe.db.get_value("Currency", main_currency, "number_format", cache=True)
|
||||||
frappe.db.get_value("Currency", main_currency, "number_format", cache=True)
|
if currency_format_str:
|
||||||
or frappe.db.get_default("number_format")
|
number_format = NumberFormat.from_string(currency_format_str)
|
||||||
or "#,###.##"
|
else:
|
||||||
)
|
number_format = get_number_format()
|
||||||
|
|
||||||
fraction_length = get_number_format_info(number_format)[2]
|
fraction_length = number_format.precision
|
||||||
|
|
||||||
n = f"%.{fraction_length}f" % number
|
n = f"%.{fraction_length}f" % number
|
||||||
|
|
||||||
|
|
@ -1499,7 +1491,7 @@ def money_in_words(
|
||||||
fraction += zeros
|
fraction += zeros
|
||||||
|
|
||||||
in_million = True
|
in_million = True
|
||||||
if number_format == "#,##,###.##":
|
if number_format.string == "#,##,###.##":
|
||||||
in_million = False
|
in_million = False
|
||||||
|
|
||||||
# 0.00
|
# 0.00
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import datetime
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import frappe.defaults
|
import frappe.defaults
|
||||||
|
from frappe.locale import get_date_format
|
||||||
from frappe.utils import add_to_date, get_datetime, getdate
|
from frappe.utils import add_to_date, get_datetime, getdate
|
||||||
from frappe.utils.data import (
|
from frappe.utils.data import (
|
||||||
get_first_day,
|
get_first_day,
|
||||||
|
|
@ -75,7 +76,7 @@ def parse_date(date):
|
||||||
|
|
||||||
def get_user_date_format():
|
def get_user_date_format():
|
||||||
if getattr(frappe.local, "user_date_format", None) is None:
|
if getattr(frappe.local, "user_date_format", None) is None:
|
||||||
frappe.local.user_date_format = frappe.defaults.get_global_default("date_format") or "yyyy-mm-dd"
|
frappe.local.user_date_format = get_date_format()
|
||||||
|
|
||||||
return frappe.local.user_date_format
|
return frappe.local.user_date_format
|
||||||
|
|
||||||
|
|
|
||||||
36
frappe/utils/number_format.py
Normal file
36
frappe/utils/number_format.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
NUMBER_FORMAT_MAP = {
|
||||||
|
"#,###.##": (".", ",", 2),
|
||||||
|
"#.###,##": (",", ".", 2),
|
||||||
|
"# ###.##": (".", " ", 2),
|
||||||
|
"# ###,##": (",", " ", 2),
|
||||||
|
"#'###.##": (".", "'", 2),
|
||||||
|
"#, ###.##": (".", ", ", 2),
|
||||||
|
"#,##,###.##": (".", ",", 2),
|
||||||
|
"#,###.###": (".", ",", 3),
|
||||||
|
"#.###": ("", ".", 0),
|
||||||
|
"#,###": ("", ",", 0),
|
||||||
|
"#.########": (".", "", 8),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NumberFormat:
|
||||||
|
precision: int
|
||||||
|
decimal_separator: str
|
||||||
|
thousands_separator: str
|
||||||
|
string: str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_string(cls, number_format: str) -> "NumberFormat":
|
||||||
|
decimal_separator, thousands_separator, precision = NUMBER_FORMAT_MAP[number_format]
|
||||||
|
return NumberFormat(
|
||||||
|
precision=precision,
|
||||||
|
decimal_separator=decimal_separator,
|
||||||
|
thousands_separator=thousands_separator,
|
||||||
|
string=number_format,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.string
|
||||||
|
|
@ -21,11 +21,13 @@ from frappe import _
|
||||||
from frappe.core.utils import html2text
|
from frappe.core.utils import html2text
|
||||||
from frappe.frappeclient import FrappeClient
|
from frappe.frappeclient import FrappeClient
|
||||||
from frappe.handler import execute_cmd
|
from frappe.handler import execute_cmd
|
||||||
|
from frappe.locale import get_date_format, get_number_format, get_time_format
|
||||||
from frappe.model.delete_doc import delete_doc
|
from frappe.model.delete_doc import delete_doc
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
from frappe.model.rename_doc import rename_doc
|
from frappe.model.rename_doc import rename_doc
|
||||||
from frappe.modules import scrub
|
from frappe.modules import scrub
|
||||||
from frappe.utils.background_jobs import enqueue, get_jobs
|
from frappe.utils.background_jobs import enqueue, get_jobs
|
||||||
|
from frappe.utils.number_format import NumberFormat
|
||||||
from frappe.website.utils import get_next_link, get_toc
|
from frappe.website.utils import get_next_link, get_toc
|
||||||
from frappe.www.printview import get_visible_columns
|
from frappe.www.printview import get_visible_columns
|
||||||
|
|
||||||
|
|
@ -164,11 +166,13 @@ def get_safe_globals():
|
||||||
datautils = frappe._dict()
|
datautils = frappe._dict()
|
||||||
|
|
||||||
if frappe.db:
|
if frappe.db:
|
||||||
date_format = frappe.db.get_default("date_format") or "yyyy-mm-dd"
|
date_format = get_date_format()
|
||||||
time_format = frappe.db.get_default("time_format") or "HH:mm:ss"
|
time_format = get_time_format()
|
||||||
|
number_format = get_number_format()
|
||||||
else:
|
else:
|
||||||
date_format = "yyyy-mm-dd"
|
date_format = "yyyy-mm-dd"
|
||||||
time_format = "HH:mm:ss"
|
time_format = "HH:mm:ss"
|
||||||
|
number_format = NumberFormat.from_string("#,###.##")
|
||||||
|
|
||||||
add_data_utils(datautils)
|
add_data_utils(datautils)
|
||||||
|
|
||||||
|
|
@ -194,6 +198,7 @@ def get_safe_globals():
|
||||||
format_value=frappe.format_value,
|
format_value=frappe.format_value,
|
||||||
date_format=date_format,
|
date_format=date_format,
|
||||||
time_format=time_format,
|
time_format=time_format,
|
||||||
|
number_format=number_format,
|
||||||
format_date=frappe.utils.data.global_date_format,
|
format_date=frappe.utils.data.global_date_format,
|
||||||
form_dict=form_dict,
|
form_dict=form_dict,
|
||||||
bold=frappe.bold,
|
bold=frappe.bold,
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,8 @@ def get_home_page_via_hooks():
|
||||||
|
|
||||||
|
|
||||||
def get_boot_data():
|
def get_boot_data():
|
||||||
|
from frappe.locale import get_date_format, get_first_day_of_the_week, get_number_format, get_time_format
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"lang": frappe.local.lang or "en",
|
"lang": frappe.local.lang or "en",
|
||||||
"apps_data": {
|
"apps_data": {
|
||||||
|
|
@ -173,10 +175,10 @@ def get_boot_data():
|
||||||
},
|
},
|
||||||
"sysdefaults": {
|
"sysdefaults": {
|
||||||
"float_precision": cint(frappe.get_system_settings("float_precision")) or 3,
|
"float_precision": cint(frappe.get_system_settings("float_precision")) or 3,
|
||||||
"date_format": frappe.get_system_settings("date_format") or "yyyy-mm-dd",
|
"date_format": get_date_format(),
|
||||||
"time_format": frappe.get_system_settings("time_format") or "HH:mm:ss",
|
"time_format": get_time_format(),
|
||||||
"first_day_of_the_week": frappe.get_system_settings("first_day_of_the_week") or "Sunday",
|
"first_day_of_the_week": get_first_day_of_the_week(),
|
||||||
"number_format": frappe.get_system_settings("number_format") or "#,###.##",
|
"number_format": get_number_format().string,
|
||||||
},
|
},
|
||||||
"time_zone": {
|
"time_zone": {
|
||||||
"system": get_system_timezone(),
|
"system": get_system_timezone(),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue