[FIX] iap_mail, web: fix untranslatable text
Some translations could not be exported, as reported in odoo/odoo#114711. This is due to Babel—the library we use to extract `_t` occurrences from the sources—ignoring javascript template literals, resulting in any gettext inside template literals not being parsed and exported as translatable resources. From version 2.12.0 of the library, support for javascript template literals can be enabled by providing the `parse_template_string` option to the Babel `extract` method. Unfortunately, the library cannot be updated for now, as our policy is to stick to the version of packages from the official Debian repository. This commit refactors some code so that no gettext is inlined within template literals. closes odoo/odoo#119996 Related: odoo/enterprise#40457 Signed-off-by: Louis Wicket (wil) <wil@odoo.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Markup } from 'web.utils';
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
export const iapNotificationService = {
|
||||
@@ -33,7 +34,10 @@ export const iapNotificationService = {
|
||||
* Displays the IAP failure notification on user's screen
|
||||
*/
|
||||
function displayFailureIapNotification(notif) {
|
||||
const message = Markup`<a class='btn btn-link' href='${notif.url}' target='_blank' ><i class='fa fa-arrow-right'></i> ${env._t("Buy more credits")}</a>`;
|
||||
// ℹ️ `_t` can only be inlined directly inside JS template literals
|
||||
// after Babel has been updated to version 2.12.
|
||||
const translatedText = _t("Buy more credits");
|
||||
const message = Markup`<a class='btn btn-link' href='${notif.url}' target='_blank' ><i class='fa fa-arrow-right'></i> ${translatedText}</a>`;
|
||||
notification.add(message, {
|
||||
type: notif.error_type,
|
||||
title: notif.title
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/** @odoo-module alias=web/static/src/js/control_panel/control_panel_model_extension.js **/
|
||||
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
import ActionModel from "web.ActionModel";
|
||||
import Domain from "web.Domain";
|
||||
import pyUtils from "web.py_utils";
|
||||
@@ -436,7 +438,10 @@
|
||||
);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`${this.env._t("Control panel model extension failed to evaluate domain")}:/n${JSON.stringify(err)}`
|
||||
sprintf(
|
||||
_t("Control panel model extension failed to evaluate domain:\n%(error)s"),
|
||||
{ error: JSON.stringify(err) }
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,9 +663,14 @@ var FieldMany2One = AbstractField.extend({
|
||||
const [id, fullName] = result;
|
||||
const displayName = this._getDisplayName(fullName).trim();
|
||||
result[1] = displayName;
|
||||
// ℹ️ `_t` can only be inlined directly inside JS template literals
|
||||
// after Babel has been updated to version 2.12.
|
||||
const translatedText = _t("Unnamed");
|
||||
return {
|
||||
id,
|
||||
label: escape(displayName) || `<em class="text-warning">${escape(_t("Unnamed"))}</em>`,
|
||||
label:
|
||||
escape(displayName) ||
|
||||
`<em class="text-warning">${escape(translatedText)}</em>`,
|
||||
value: displayName,
|
||||
name: displayName,
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Domain } from "@web/core/domain";
|
||||
import { evaluateExpr } from "@web/core/py_js/py";
|
||||
import { sortBy } from "@web/core/utils/arrays";
|
||||
import { deepCopy } from "@web/core/utils/objects";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
import { SearchArchParser } from "./search_arch_parser";
|
||||
import {
|
||||
constructDateDomain,
|
||||
@@ -1590,7 +1591,10 @@ export class SearchModel extends EventBus {
|
||||
return context;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`${this.env._t("Failed to evaluate the context")} ${context}.\n${error.message}`
|
||||
sprintf(_t("Failed to evaluate the context: %(context)s.\n%(error)s"), {
|
||||
context,
|
||||
error: error.message,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1675,9 +1679,10 @@ export class SearchModel extends EventBus {
|
||||
return params.raw ? domain : domain.toList(this.domainEvalContext);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`${this.env._t("Failed to evaluate the domain")} ${domain.toString()}.\n${
|
||||
error.message
|
||||
}`
|
||||
sprintf(_t("Failed to evaluate the domain: %(domain)s.\n%(error)s"), {
|
||||
domain: domain.toString(),
|
||||
error: error.message,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2075,9 +2080,10 @@ export class SearchModel extends EventBus {
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`${this.env._t("Failed to evaluate the context")} "${
|
||||
searchItem.context
|
||||
}".\n${error.message}`
|
||||
sprintf(_t("Failed to evaluate the context: %(context)s.\n%(error)s"), {
|
||||
context: searchItem.context,
|
||||
error: error.message,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { _lt, _t } from "@web/core/l10n/translation";
|
||||
import { useOwnedDialogs, useService } from "@web/core/utils/hooks";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
import { Layout } from "@web/search/layout";
|
||||
import { useModel } from "@web/views/model";
|
||||
import { ViewScaleSelector } from "@web/views/view_components/view_scale_selector";
|
||||
@@ -163,7 +164,7 @@ export class CalendarController extends Component {
|
||||
resModel: this.model.resModel,
|
||||
resId: record.id || false,
|
||||
context,
|
||||
title: record.id ? `${_t("Open")}: ${record.title}` : _t("New Event"),
|
||||
title: record.id ? sprintf(_t("Open: %s"), record.title) : _t("New Event"),
|
||||
viewId: this.model.formViewId,
|
||||
onRecordSaved: () => this.model.load(),
|
||||
},
|
||||
|
||||
@@ -29,7 +29,7 @@ export class CalendarFilterPanel extends Component {
|
||||
return {
|
||||
autoSelect: true,
|
||||
resetOnSelect: true,
|
||||
placeholder: `+ ${_t("Add")} ${section.label}`,
|
||||
placeholder: sprintf(_t("+ Add %s"), section.label),
|
||||
sources: [
|
||||
{
|
||||
placeholder: _t("Loading..."),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { View } from "@web/views/view";
|
||||
import { escape } from "@web/core/utils/strings";
|
||||
@@ -14,11 +15,14 @@ export class SelectCreateDialog extends Component {
|
||||
this.viewService = useService("view");
|
||||
this.dialogService = useService("dialog");
|
||||
this.state = useState({ resIds: [] });
|
||||
// ℹ️ `_t` can only be inlined directly inside JS template literals
|
||||
// after Babel has been updated to version 2.12.
|
||||
const translatedText = _t("No records found!");
|
||||
this.baseViewProps = {
|
||||
display: { searchPanel: false },
|
||||
editable: false, // readonly
|
||||
noBreadcrumbs: true,
|
||||
noContentHelp: markup(`<p>${escape(this.env._t("No records found!"))}</p>`),
|
||||
noContentHelp: markup(`<p>${escape(translatedText)}</p>`),
|
||||
showButtons: false,
|
||||
selectRecord: (resId) => this.select([resId]),
|
||||
onSelectionChanged: (resIds) => {
|
||||
|
||||
+23
-5
@@ -4,6 +4,7 @@ import { registry } from "@web/core/registry";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { unique } from "@web/core/utils/arrays";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { sprintf } from "@web/core/utils/strings";
|
||||
|
||||
import { Component, useState, onWillStart } from "@odoo/owl";
|
||||
import { standardWidgetProps } from "@web/views/widgets/standard_widget_props";
|
||||
@@ -19,6 +20,7 @@ class ResConfigInviteUsers extends Component {
|
||||
this.invite = useService("user_invite");
|
||||
this.action = useService("action");
|
||||
this.notification = useService("notification");
|
||||
this.user = useService("user");
|
||||
|
||||
this.state = useState({
|
||||
status: "idle", // idle, inviting
|
||||
@@ -61,11 +63,27 @@ class ResConfigInviteUsers extends Component {
|
||||
}
|
||||
}
|
||||
if (invalidEmails.length) {
|
||||
throw new Error(
|
||||
`${_t("Invalid email address")}${
|
||||
invalidEmails.length > 1 ? "es" : ""
|
||||
}: ${invalidEmails.join(", ")}`
|
||||
);
|
||||
const errorMessage = (() => {
|
||||
const listFormatter = new Intl.ListFormat(this.user.lang.replace("_", "-"), {
|
||||
type: "conjunction",
|
||||
style: "long",
|
||||
});
|
||||
switch (invalidEmails.length) {
|
||||
case 1:
|
||||
return sprintf(_t("Invalid email address: %(address)s"), {
|
||||
address: invalidEmails[0],
|
||||
});
|
||||
case 2:
|
||||
return sprintf(_t("Invalid email addresses: %(2 addresses)s"), {
|
||||
"2 addresses": listFormatter.format(invalidEmails),
|
||||
});
|
||||
default:
|
||||
return sprintf(_t("Invalid email addresses: %(addresses)s"), {
|
||||
addresses: listFormatter.format(invalidEmails),
|
||||
});
|
||||
}
|
||||
})();
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { Component, markup } from "@odoo/owl";
|
||||
import { isMacOS } from "@web/core/browser/feature_detection";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { escape } from "@web/core/utils/strings";
|
||||
import { session } from "@web/session";
|
||||
import { browser } from "../../core/browser/browser";
|
||||
@@ -43,13 +44,16 @@ class ShortcutsFooterComponent extends Component {
|
||||
ShortcutsFooterComponent.template = "web.UserMenu.ShortcutsFooterComponent";
|
||||
|
||||
function shortCutsItem(env) {
|
||||
// ℹ️ `_t` can only be inlined directly inside JS template literals after
|
||||
// Babel has been updated to version 2.12.
|
||||
const translatedText = _t("Shortcuts");
|
||||
return {
|
||||
type: "item",
|
||||
id: "shortcuts",
|
||||
hide: env.isSmall,
|
||||
description: markup(
|
||||
`<div class="d-flex align-items-center justify-content-between">
|
||||
<span>${escape(env._t("Shortcuts"))}</span>
|
||||
<span>${escape(translatedText)}</span>
|
||||
<span class="fw-bold">${isMacOS() ? "CMD" : "CTRL"}+K</span>
|
||||
</div>`
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user