diff --git a/addons/web/static/src/core/l10n/localization_service.js b/addons/web/static/src/core/l10n/localization_service.js index a240dcf479316fe86984ca07791ce3d7545ac3a8..6fe0a876a6c74ff1d84abbbe2534caf042c1fb86 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"], @@ -42,13 +57,18 @@ export const localizationService = { env._t = _t; env.qweb.translateFn = _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 0c89c16d97040061f609c8fa1471fb9e1809655e..b0152bb9977202d5fc2ce485a725f7c4734ce7da 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 3bfe6d1848e973a93d471f75cc5697703194f635..82e6fffbaf5d5f19d67814be6bad6ec4c90378b9 100644 --- a/addons/web/static/tests/core/l10n/translation_tests.js +++ b/addons/web/static/tests/core/l10n/translation_tests.js @@ -1,22 +1,57 @@ /** @odoo-module **/ +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, patchWithCleanup } from "@web/../tests/helpers/utils"; import { browser } from "@web/core/browser/browser"; -import { translatedTerms, _lt } from "@web/core/l10n/translation"; 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"; -import { makeTestEnv } from "@web/../tests/helpers/mock_env"; -import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services"; -import { getFixture, patchWithCleanup } from "@web/../tests/helpers/utils"; -import { registerCleanup } from "@web/../tests/helpers/cleanup"; const { mount } = owl; +const { DateTime, Settings } = luxon; const terms = { Hello: "Bonjour" }; const serviceRegistry = registry.category("services"); class TestComponent extends owl.Component {} +/** + * Patches the 'lang' of the user session and context. + * + * @param {string} lang + * @returns {Promise<void>} + */ +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 +96,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 patchLang("fr_BE"); + assert.strictEqual(DateTime.utc(2021, 12, 10).toFormat("MMMM"), "décembre"); +}); - await makeTestEnv(); +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, ੨੦੨੧ ੧੨:੦੦:੦੦" + ); +}); - assert.strictEqual(luxon.DateTime.utc(2021, 12, 10).toFormat("MMMM"), "décembre"); +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"), + "௧௦ டிச., ௨௦௨௧ ௧௨:௦௦:௦௦" + ); });