diff --git a/addons/web/static/src/core/datepicker/datepicker.js b/addons/web/static/src/core/datepicker/datepicker.js index 82d96f5c615..bc221c5f535 100644 --- a/addons/web/static/src/core/datepicker/datepicker.js +++ b/addons/web/static/src/core/datepicker/datepicker.js @@ -146,13 +146,13 @@ export class DatePicker extends Component { if (typeof commandOrParams === "object") { const format = luxonFormatToMomentFormat(this.props.format || this.defaultFormat); const params = { ...commandOrParams, format }; + if (!params.locale && commandOrParams.date) { + params.locale = commandOrParams.date.locale; + } for (const prop in params) { if (params[prop] instanceof DateTime) { const luxonDate = params[prop]; const momentDate = luxonDateToMomentDate(luxonDate); - if (momentDate.locale() !== luxonDate.locale) { - momentDate.locale(params.locale); - } params[prop] = momentDate; } } diff --git a/addons/web/static/src/core/l10n/localization_service.js b/addons/web/static/src/core/l10n/localization_service.js index c24d20abbe9..a240dcf4793 100644 --- a/addons/web/static/src/core/l10n/localization_service.js +++ b/addons/web/static/src/core/l10n/localization_service.js @@ -41,6 +41,16 @@ export const localizationService = { Object.setPrototypeOf(translatedTerms, terms); 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, "-"); + } + const dateFormat = strftimeToLuxonFormat(userLocalization.date_format); const timeFormat = strftimeToLuxonFormat(userLocalization.time_format); const dateTimeFormat = `${dateFormat} ${timeFormat}`; diff --git a/addons/web/static/tests/core/datepicker_tests.js b/addons/web/static/tests/core/datepicker_tests.js index f0da030c8b7..6b9f7359832 100644 --- a/addons/web/static/tests/core/datepicker_tests.js +++ b/addons/web/static/tests/core/datepicker_tests.js @@ -127,7 +127,7 @@ QUnit.module("Components", () => { assert.verifySteps(["datetime-changed"]); }); - QUnit.test("pick a date with locale", async function (assert) { + QUnit.test("pick a date with locale (locale given in props)", async function (assert) { assert.expect(5); const picker = await mountPicker(DatePicker, { @@ -158,6 +158,39 @@ QUnit.module("Components", () => { assert.verifySteps(["datetime-changed"]); }); + QUnit.test("pick a date with locale (locale from date props)", async function (assert) { + assert.expect(5); + + const picker = await mountPicker(DatePicker, { + props: { + date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", { + zone: "utc", + locale: useFRLocale(), + }), + format: "dd MMM, yyyy", + }, + onDateChange: (ev) => { + assert.step("datetime-changed"); + assert.strictEqual( + ev.detail.date.toFormat("dd/MM/yyyy"), + "01/09/1997", + "Event should transmit the correct date" + ); + }, + }); + const input = picker.el.querySelector(".o_datepicker_input"); + + assert.strictEqual(input.value, "09 janv., 1997"); + + await click(input); + await click(document.querySelector(".datepicker .picker-switch")); // month picker + await click(document.querySelectorAll(".datepicker .month")[8]); // september + await click(document.querySelector(".datepicker .day")); // first day + + assert.strictEqual(input.value, "01 sept., 1997"); + assert.verifySteps(["datetime-changed"]); + }); + QUnit.test("enter a date value", async function (assert) { assert.expect(5); diff --git a/addons/web/static/tests/core/l10n/translation_tests.js b/addons/web/static/tests/core/l10n/translation_tests.js index ded6e1df950..3bfe6d1848e 100644 --- a/addons/web/static/tests/core/l10n/translation_tests.js +++ b/addons/web/static/tests/core/l10n/translation_tests.js @@ -1,11 +1,15 @@ /** @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 { makeTestEnv } from "../../helpers/mock_env"; -import { makeFakeLocalizationService } from "../../helpers/mock_services"; -import { getFixture } from "../../helpers/utils"; +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; @@ -55,3 +59,39 @@ QUnit.test("_t is in env", async (assert) => { assert.strictEqual(target.innerText, "Bonjour"); unpatch(translatedTerms, "add translations"); }); + +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"); +});