diff --git a/addons/web/static/src/core/l10n/translation.js b/addons/web/static/src/core/l10n/translation.js index aec60f9b395..f191773c080 100644 --- a/addons/web/static/src/core/l10n/translation.js +++ b/addons/web/static/src/core/l10n/translation.js @@ -59,3 +59,17 @@ _lt("about a month ago"); _lt("%d months ago"); _lt("about a year ago"); _lt("%d years ago"); + +/** + * Load the installed languages long names and code + * + * The result of the call is put in cache. + * If any new language is installed, a full page refresh will happen, + * so there is no need invalidate it. + */ +export async function loadLanguages(orm) { + if (!loadLanguages.installedLanguages) { + loadLanguages.installedLanguages = await orm.call("res.lang", "get_installed"); + } + return loadLanguages.installedLanguages; +} diff --git a/addons/web/static/src/views/fields/char/char_field.xml b/addons/web/static/src/views/fields/char/char_field.xml index 3f77912f466..00132c8a29d 100644 --- a/addons/web/static/src/views/fields/char/char_field.xml +++ b/addons/web/static/src/views/fields/char/char_field.xml @@ -23,6 +23,7 @@ resModel="props.record.resModel" value="props.value" updateField="props.update" + context="props.record.context" /> diff --git a/addons/web/static/src/views/fields/text/text_field.xml b/addons/web/static/src/views/fields/text/text_field.xml index 62f5d9fdad1..3d9d0a517ec 100644 --- a/addons/web/static/src/views/fields/text/text_field.xml +++ b/addons/web/static/src/views/fields/text/text_field.xml @@ -22,6 +22,7 @@ resModel="props.record.resModel" value="props.value" updateField="props.update" + context="props.record.context" /> diff --git a/addons/web/static/src/views/fields/translation_button.js b/addons/web/static/src/views/fields/translation_button.js index 35da94f8ad9..a9faf663eaa 100644 --- a/addons/web/static/src/views/fields/translation_button.js +++ b/addons/web/static/src/views/fields/translation_button.js @@ -25,7 +25,7 @@ export class TranslationButton extends Component { model: "ir.translation", method: "translate_fields", args: [this.props.resModel, this.props.resId, this.props.fieldName], - kwargs: {}, + kwargs: { context: this.props.context }, }); this.dialog.add(TranslationDialog, { diff --git a/addons/web/static/src/views/fields/translation_dialog.js b/addons/web/static/src/views/fields/translation_dialog.js index c15f46a83ad..0cf8348e013 100644 --- a/addons/web/static/src/views/fields/translation_dialog.js +++ b/addons/web/static/src/views/fields/translation_dialog.js @@ -3,11 +3,10 @@ import { Dialog } from "@web/core/dialog/dialog"; import { useService } from "@web/core/utils/hooks"; import { sprintf } from "@web/core/utils/strings"; +import { loadLanguages } from "@web/core/l10n/translation"; const { Component, onWillStart } = owl; -let installedLanguages = null; - export class TranslationDialog extends Component { setup() { super.setup(); @@ -20,7 +19,7 @@ export class TranslationDialog extends Component { this.updatedTerms = {}; onWillStart(async () => { - const languages = await this.loadLanguages(); + const languages = await loadLanguages(this.orm); const translations = await this.loadTranslations(languages); this.terms = translations.map((term) => { @@ -52,24 +51,19 @@ export class TranslationDialog extends Component { }); } - /** - * Load the installed languages long names and code - * - * The result of the call is put in cache. - * If any new language is installed, a full page refresh will happen, - * so there is no need invalidate it. - */ - async loadLanguages() { - if (!installedLanguages) { - installedLanguages = await this.orm.call("res.lang", "get_installed"); + get domain() { + const domain = this.props.domain; + if (this.props.searchName) { + domain.push(["name", "=", `${this.props.searchName}`]); } - return installedLanguages; + return domain; } + /** * Load the translation terms for the installed language, for the current model and res_id */ async loadTranslations(languages) { - const domain = [...this.props.domain, ["lang", "in", languages.map((l) => l[0])]]; + const domain = [...this.domain, ["lang", "in", languages.map((l) => l[0])]]; return this.orm.searchRead("ir.translation", domain, ["lang", "src", "value"]); } diff --git a/addons/web/static/tests/setup.js b/addons/web/static/tests/setup.js index f2c0edd132b..05065dc362e 100644 --- a/addons/web/static/tests/setup.js +++ b/addons/web/static/tests/setup.js @@ -10,6 +10,7 @@ import { utils } from "./helpers/mock_env"; import { session as sessionInfo } from "@web/session"; import { prepareLegacyRegistriesWithCleanup } from "./helpers/legacy_env_utils"; import { config as transitionConfig } from "@web/core/transition"; +import { loadLanguages } from "@web/core/l10n/translation"; transitionConfig.disabled = true; @@ -186,6 +187,12 @@ function patchOdoo() { }); } +function cleanLoadedLanguages() { + registerCleanup(() => { + loadLanguages.installedLanguages = null; + }); +} + function patchSessionInfo() { patchWithCleanup(sessionInfo, { cache_hashes: { @@ -251,6 +258,7 @@ export async function setupTests() { prepareRegistriesWithCleanup(); prepareLegacyRegistriesWithCleanup(); forceLocaleAndTimezoneWithCleanup(); + cleanLoadedLanguages(); patchBrowserWithCleanup(); patchLegacyCoreBus(); patchOdoo(); diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 9631945b965..f79aa4e294f 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -7880,6 +7880,59 @@ QUnit.module("Views", (hooks) => { assert.verifySteps([]); }); + QUnit.test("translation dialog with right context and domain", async function (assert) { + serverData.models.partner.fields.foo.translate = true; + + patchWithCleanup(localization, { + multiLang: true, + }); + + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` +
`, + resId: 1, + mockRPC(route, args) { + if (args.method === "get_installed") { + return [ + ["CUST", "custom lang"], + ["CUST2", "second custom"], + ]; + } + if (args.method === "translate_fields") { + assert.step(`translate args ${JSON.stringify(args.args)}`); + assert.step(`translate context ${JSON.stringify(args.kwargs.context)}`); + return { + domain: [["res_id", "=", args.args[1]]], + context: { search_default_name: "partner_type,foo" }, + }; + } + if (args.method === "search_read" && args.model === "ir.translation") { + assert.step( + `search_read translations args: ${JSON.stringify( + args.args + )} ; kwargs: ${JSON.stringify(args.kwargs)}` + ); + } + }, + }); + await clickEdit(target); + + await click(target, ".o_field_translate.btn-link"); + assert.verifySteps([ + `translate args ["partner",1,"foo"]`, + `translate context {"lang":"en","uid":7,"tz":"taht"}`, + `search_read translations args: [] ; kwargs: {"context":{"lang":"en","uid":7,"tz":"taht"},"domain":[["res_id","=",1],["name","=","partner_type,foo"],["lang","in",["CUST","CUST2"]]],"fields":["lang","src","value"]}`, + ]); + + assert.containsOnce(target, ".modal"); + assert.strictEqual(target.querySelector(".modal-title").textContent, "Translate: foo"); + }); + QUnit.test("translation alerts are preserved on pager change", async function (assert) { serverData.models.partner.fields.foo.translate = true;