diff --git a/addons/web/static/src/core/l10n/localization_service.js b/addons/web/static/src/core/l10n/localization_service.js index 15c04bb904d..7ca45473704 100644 --- a/addons/web/static/src/core/l10n/localization_service.js +++ b/addons/web/static/src/core/l10n/localization_service.js @@ -1,11 +1,26 @@ /** @odoo-module **/ +import { session } from "@web/session"; import { browser } from "../browser/browser"; import { registry } from "../registry"; import { strftimeToLuxonFormat } from "./dates"; import { localization } from "./localization"; import { translatedTerms, _t } from "./translation"; -import { session } from "@web/session"; + +const { Settings } = luxon; + +/** @type {[RegExp, string][]} */ +const NUMBERING_SYSTEMS = [ + [/^ar-(sa|001)$/i, "arab"], + [/^bn/i, "beng"], + [/^bo/i, "tibt"], + // [/^fa/i, "Farsi (Persian)"], // No numberingSystem found in Intl + // [/^(hi|mr|ne)/i, "Hindi"], // No numberingSystem found in Intl + // [/^my/i, "Burmese"], // No numberingSystem found in Intl + [/^pa-in/i, "guru"], + [/^ta/i, "tamldec"], + [/.*/i, "latn"], +]; export const localizationService = { dependencies: ["user"], @@ -38,13 +53,18 @@ export const localizationService = { Object.setPrototypeOf(translatedTerms, terms); env._t = _t; - // Setup lang inside luxon. The locale codes received from the server contain "_", whereas - // the Intl codes use "-" (Unicode BCP 47). There's only one exception, which is locale - // "sr@latin", for which we manually fallback to the "sr-Latn-RS" locale. - if (lang === "sr@latin") { - luxon.Settings.defaultLocale = "sr-Latn-RS"; - } else if (lang) { - luxon.Settings.defaultLocale = lang.replace(/_/g, "-"); + if (lang) { + // Setup lang inside luxon. The locale codes received from the server contain "_", + // whereas the Intl codes use "-" (Unicode BCP 47). There's only one exception, which + // is locale "sr@latin", for which we manually fallback to the "sr-Latn-RS" locale. + const locale = lang === "sr@latin" ? "sr-Latn-RS" : lang.replace(/_/g, "-"); + Settings.defaultLocale = locale; + for (const [re, numberingSystem] of NUMBERING_SYSTEMS) { + if (re.test(locale)) { + Settings.defaultNumberingSystem = numberingSystem; + break; + } + } } const dateFormat = strftimeToLuxonFormat(userLocalization.date_format); diff --git a/addons/web/static/src/search/filter_menu/custom_filter_item.js b/addons/web/static/src/search/filter_menu/custom_filter_item.js index f62e0d0fd81..dca07157828 100644 --- a/addons/web/static/src/search/filter_menu/custom_filter_item.js +++ b/addons/web/static/src/search/filter_menu/custom_filter_item.js @@ -167,17 +167,17 @@ export class CustomFilterItem extends Component { condition.value = 0; break; } - case "date": { + case "date": + case "datetime": { condition.value = [DateTime.local()]; if (operator.symbol === "between") { condition.value.push(DateTime.local()); } - break; - } - case "datetime": { - condition.value = [DateTime.fromFormat("00:00:00", "hh:mm:ss")]; - if (operator.symbol === "between") { - condition.value.push(DateTime.fromFormat("23:59:59", "hh:mm:ss")); + if (genericType === "datetime") { + condition.value[0].set({ hour: 0, minute: 0, second: 0 }); + if (operator.symbol === "between") { + condition.value[1].set({ hour: 23, minute: 59, second: 59 }); + } } break; } diff --git a/addons/web/static/tests/core/l10n/translation_tests.js b/addons/web/static/tests/core/l10n/translation_tests.js index 8c03b1433a3..2ecaf0b9bab 100644 --- a/addons/web/static/tests/core/l10n/translation_tests.js +++ b/addons/web/static/tests/core/l10n/translation_tests.js @@ -1,22 +1,58 @@ /** @odoo-module **/ -import { browser } from "@web/core/browser/browser"; -import { translatedTerms, _lt } from "@web/core/l10n/translation"; -import { localizationService } from "@web/core/l10n/localization_service"; -import { registry } from "@web/core/registry"; -import { patch, unpatch } from "@web/core/utils/patch"; -import { session } from "@web/session"; +import { registerCleanup } from "@web/../tests/helpers/cleanup"; import { makeTestEnv } from "@web/../tests/helpers/mock_env"; import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services"; import { getFixture, mount, patchWithCleanup } from "@web/../tests/helpers/utils"; -import { registerCleanup } from "@web/../tests/helpers/cleanup"; +import { browser } from "@web/core/browser/browser"; +import { localizationService } from "@web/core/l10n/localization_service"; +import { translatedTerms, _lt } from "@web/core/l10n/translation"; +import { registry } from "@web/core/registry"; +import { patch, unpatch } from "@web/core/utils/patch"; +import { session } from "@web/session"; const { Component, xml } = owl; +const { DateTime, Settings } = luxon; + const terms = { Hello: "Bonjour" }; const serviceRegistry = registry.category("services"); class TestComponent extends Component {} +/** + * Patches the 'lang' of the user session and context. + * + * @param {string} lang + * @returns {Promise} + */ +const patchLang = async (lang) => { + const { defaultLocale, defaultNumberingSystem } = Settings; + registerCleanup(() => { + Settings.defaultLocale = defaultLocale; + Settings.defaultNumberingSystem = defaultNumberingSystem; + }); + patchWithCleanup(session.user_context, { lang }); + patchWithCleanup(browser, { + fetch: async () => ({ + ok: true, + json: async () => ({ + modules: {}, + lang_parameters: { + direction: "ltr", + date_format: "%d/%m/%Y", + time_format: "%H:%M:%S", + grouping: "[3,0]", + decimal_point: ",", + thousands_sep: ".", + week_start: 1, + }, + }), + }), + }); + serviceRegistry.add("localization", localizationService); + await makeTestEnv(); +}; + QUnit.module("Translations"); QUnit.test("can translate a text node", async (assert) => { @@ -61,37 +97,80 @@ QUnit.test("_t is in env", async (assert) => { }); QUnit.test("luxon is configured in the correct lang", async (assert) => { - const defaultLocale = luxon.Settings.defaultLocale; - registerCleanup(() => { - luxon.Settings.defaultLocale = defaultLocale; - }); - patchWithCleanup(session, { - user_context: { ...session.user_context, lang: "fr_BE" }, - }); - patchWithCleanup(browser, { - fetch() { - return { - ok: true, - json() { - return { - modules: {}, - lang_parameters: { - direction: "ltr", - date_format: "%d/%m/%Y", - time_format: "%H:%M:%S", - grouping: "[3,0]", - decimal_point: ",", - thousands_sep: ".", - week_start: 1, - }, - }; - }, - }; - }, - }); - serviceRegistry.add("localization", localizationService); - - await makeTestEnv(); - - assert.strictEqual(luxon.DateTime.utc(2021, 12, 10).toFormat("MMMM"), "décembre"); + await patchLang("fr_BE"); + assert.strictEqual(DateTime.utc(2021, 12, 10).toFormat("MMMM"), "décembre"); +}); + +QUnit.module("Numbering system"); + +QUnit.test("arabic has the correct numbering system (generic)", async (assert) => { + await patchLang("ar_001"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "١٠ ديسمبر, ٢٠٢١ ١٢:٠٠:٠٠" + ); +}); + +QUnit.test("arabic has the correct numbering system (Algeria)", async (assert) => { + await patchLang("ar_DZ"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "10 ديسمبر, 2021 12:00:00" + ); +}); + +QUnit.test("arabic has the correct numbering system (Lybia)", async (assert) => { + await patchLang("ar_LY"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "10 ديسمبر, 2021 12:00:00" + ); +}); + +QUnit.test("arabic has the correct numbering system (Morocco)", async (assert) => { + await patchLang("ar_MA"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "10 دجنبر, 2021 12:00:00" + ); +}); + +QUnit.test("arabic has the correct numbering system (Saudi Arabia)", async (assert) => { + await patchLang("ar_SA"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "١٠ جمادى الأولى, ٢٠٢١ ١٢:٠٠:٠٠" + ); +}); + +QUnit.test("arabic has the correct numbering system (Tunisia)", async (assert) => { + await patchLang("ar_TN"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "10 ديسمبر, 2021 12:00:00" + ); +}); + +QUnit.test("bengalese has the correct numbering system", async (assert) => { + await patchLang("bn"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "১০ ডিসেম্বর, ২০২১ ১২:০০:০০" + ); +}); + +QUnit.test("punjabi (gurmukhi) has the correct numbering system", async (assert) => { + await patchLang("pa_in"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "੧੦ M12, ੨੦੨੧ ੧੨:੦੦:੦੦" + ); +}); + +QUnit.test("tamil has the correct numbering system", async (assert) => { + await patchLang("ta"); + assert.strictEqual( + DateTime.utc(2021, 12, 10).toFormat("dd MMM, yyyy hh:mm:ss"), + "௧௦ டிச., ௨௦௨௧ ௧௨:௦௦:௦௦" + ); });