From 80e97e98ce76067db1079af8feeef667cfadf837 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 15 Jun 2020 15:16:16 +0200 Subject: [PATCH] [IMP] *: use named placeholders in translated message When more than one parameter is present in a message, it helps the translation to use named placeholder. This way, the order can be changed. It also helps the comprehension of the message. --- addons/account/models/account_account.py | 6 +- .../account/models/account_bank_statement.py | 7 ++- addons/account/models/account_journal.py | 6 +- addons/account/models/account_move.py | 13 +++-- .../account/wizard/account_move_reversal.py | 4 +- addons/base_vat/models/res_partner.py | 14 ++++- addons/calendar/models/calendar_event.py | 38 ++++++++----- addons/calendar/models/calendar_recurrence.py | 4 +- addons/calendar_sms/models/calendar.py | 2 +- addons/crm/models/crm_lead.py | 6 +- addons/delivery/models/stock_picking.py | 8 ++- addons/gamification/models/challenge.py | 6 +- addons/gamification/models/goal.py | 14 +++-- addons/google_calendar/models/calendar.py | 18 +++++- .../hr_expense_sheet_register_payment.py | 9 ++- addons/hr_fleet/controllers/main.py | 7 ++- addons/hr_holidays/models/hr_leave.py | 55 ++++++++++++------- .../hr_holidays/models/hr_leave_allocation.py | 24 +++++--- addons/hr_skills/models/hr_skills.py | 4 +- addons/hr_timesheet/models/project.py | 7 ++- addons/mail/models/mail_activity.py | 4 +- addons/mail/models/mail_channel.py | 2 +- addons/mail/models/mail_thread.py | 14 ++++- addons/mail/wizard/invite.py | 2 +- addons/mrp/models/mrp_bom.py | 10 ++-- addons/mrp/models/mrp_production.py | 8 ++- addons/mrp/models/mrp_workorder.py | 14 ++--- addons/mrp/wizard/change_production_qty.py | 6 +- addons/payment_stripe/models/payment.py | 2 +- .../tools/phone_validation.py | 2 +- addons/point_of_sale/models/pos_payment.py | 2 +- addons/portal/models/mail_thread.py | 6 +- addons/product/models/product_pricelist.py | 2 +- addons/purchase/models/purchase.py | 14 ++++- addons/sale/models/sale.py | 7 ++- addons/sale_coupon/models/coupon.py | 6 +- addons/sale_coupon/models/coupon_program.py | 6 +- addons/sale_management/models/sale_order.py | 7 ++- .../models/sale_order_template.py | 6 +- addons/sale_stock/models/sale_order.py | 8 ++- addons/stock/models/stock_warehouse.py | 2 +- addons/stock_account/models/product.py | 16 +++++- .../stock_valuation_layer_revaluation.py | 16 ++++-- addons/website_sale_stock/controllers/main.py | 6 +- 44 files changed, 309 insertions(+), 111 deletions(-) diff --git a/addons/account/models/account_account.py b/addons/account/models/account_account.py index 980e58a8ef7..1622338baf2 100644 --- a/addons/account/models/account_account.py +++ b/addons/account/models/account_account.py @@ -147,7 +147,11 @@ class AccountAccount(models.Model): if res: account = self.env['account.account'].browse(res[0]) journal = self.env['account.journal'].browse(res[1]) - raise ValidationError(_("The foreign currency set on the journal '%s' and the account '%s' must be the same.") % (journal.display_name, account.display_name)) + raise ValidationError(_( + "The foreign currency set on the journal '%(journal)s' and the account '%(account)s' must be the same.", + journal=journal.display_name, + account=account.display_name + )) @api.constrains('company_id') def _check_company_consistency(self): diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 85064116369..502d91c563b 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -317,8 +317,11 @@ class AccountBankStatement(models.Model): else: balance_end_real = formatLang(self.env, stmt.balance_end_real, currency_obj=stmt.currency_id) balance_end = formatLang(self.env, stmt.balance_end, currency_obj=stmt.currency_id) - raise UserError(_('The ending balance is incorrect !\nThe expected balance (%s) is different from the computed one. (%s)') - % (balance_end_real, balance_end)) + raise UserError(_( + 'The ending balance is incorrect !\nThe expected balance (%(real_balance)s) is different from the computed one (%(computed_balance)s).', + real_balance=balance_end_real, + computed_balance=balance_end + )) return True def unlink(self): diff --git a/addons/account/models/account_journal.py b/addons/account/models/account_journal.py index d8da1deea14..f424d2fb738 100644 --- a/addons/account/models/account_journal.py +++ b/addons/account/models/account_journal.py @@ -270,7 +270,11 @@ class AccountJournal(models.Model): ''', [tuple(accounts.ids)]) res = self._cr.fetchone() if res: - raise ValidationError(_("The account %s can't be shared between multiple journals: %s") % (res[0], ', '.join(res[1]))) + raise ValidationError(_( + "The account %(account_name)s can't be shared between multiple journals: %(journals)s", + account_name=res[0], + journals=', '.join(res[1]) + )) @api.constrains('type', 'default_credit_account_id', 'default_debit_account_id') def _check_type_default_credit_account_id_type(self): diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index aee49964d71..9263f9519f4 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -65,9 +65,10 @@ class AccountMove(models.Model): if not journal: company = self.env['res.company'].browse(company_id) - error_msg = _("No journal could be found in company %s for any of those types: %s") % ( - company.display_name, - ', '.join(journal_types), + error_msg = _( + "No journal could be found in company %(company_name)s for any of those types: %(journal_types)s", + company_name=company.display_name, + journal_types=', '.join(journal_types), ) raise UserError(error_msg) @@ -91,7 +92,11 @@ class AccountMove(models.Model): journal = self.env['account.journal'].browse(self._context['default_journal_id']) if move_type != 'entry' and journal.type not in journal_types: - raise UserError(_("Cannot create an invoice of type %s with a journal having %s as type.") % (move_type, journal.type)) + raise UserError(_( + "Cannot create an invoice of type %(move_type)s with a journal having %(journal_type)s as type.", + move_type=move_type, + journal_type=journal.type, + )) else: journal = self._search_default_journal(journal_types) diff --git a/addons/account/wizard/account_move_reversal.py b/addons/account/wizard/account_move_reversal.py index e7c51be9aaf..f83fc3a950c 100644 --- a/addons/account/wizard/account_move_reversal.py +++ b/addons/account/wizard/account_move_reversal.py @@ -57,7 +57,9 @@ class AccountMoveReversal(models.TransientModel): def _prepare_default_reversal(self, move): reverse_date = self.date if self.date_mode == 'custom' else move.date return { - 'ref': _('Reversal of: %s, %s') % (move.name, self.reason) if self.reason else _('Reversal of: %s') % (move.name), + 'ref': _('Reversal of: %(move_name)s, %(reason)s', move_name=move.name, reason=self.reason) + if self.reason + else _('Reversal of: %s', move.name), 'date': reverse_date, 'invoice_date': move.is_invoice(include_receipts=True) and (self.date or move.date) or False, 'journal_id': self.journal_id and self.journal_id.id or move.journal_id.id, diff --git a/addons/base_vat/models/res_partner.py b/addons/base_vat/models/res_partner.py index 0b54f0e0286..17f379012bc 100644 --- a/addons/base_vat/models/res_partner.py +++ b/addons/base_vat/models/res_partner.py @@ -162,8 +162,18 @@ class ResPartner(models.Model): else: company = self.env.company if company.vat_check_vies: - return '\n' + _('The VAT number [%s] for partner [%s] either failed the VIES VAT validation check or did not respect the expected format %s.') % (self.vat, self.name, vat_no) - return '\n' + _('The VAT number [%s] for partner [%s] does not seem to be valid. \nNote: the expected format is %s') % (self.vat, self.name, vat_no) + return '\n' + _( + 'The VAT number [%(vat)s] for partner [%(name)s] either failed the VIES VAT validation check or did not respect the expected format %(format)s.', + vat=self.vat, + name=self.name, + format=vat_no + ) + return '\n' + _( + 'The VAT number [%(vat)s] for partner [%(name)s] does not seem to be valid. \nNote: the expected format is %(format)s', + vat=self.vat, + name=self.name, + format=vat_no + ) __check_vat_ch_re1 = re.compile(r'(MWST|TVA|IVA)[0-9]{6}$') __check_vat_ch_re2 = re.compile(r'E([0-9]{9}|-[0-9]{3}\.[0-9]{3}\.[0-9]{3})(MWST|TVA|IVA)$') diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index df6347a678c..68740cae04d 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -135,25 +135,27 @@ class Meeting(models.Model): time_str = to_text(date.strftime(format_time)) if zallday: - display_time = _("AllDay , %s") % (date_str) + display_time = _("AllDay , %(day)s", day=date_str) elif zduration < 24: duration = date + timedelta(minutes=round(zduration*60)) duration_time = to_text(duration.strftime(format_time)) - display_time = _(u"%s at (%s To %s) (%s)") % ( - date_str, - time_str, - duration_time, - timezone, + display_time = _( + u"%(day)s at (%(start)s To %(end)s) (%(timezone)s)", + day=date_str, + start=time_str, + end=duration_time, + timezone=timezone, ) else: dd_date = to_text(date_deadline.strftime(format_date)) dd_time = to_text(date_deadline.strftime(format_time)) - display_time = _(u"%s at %s To\n %s at %s (%s)") % ( - date_str, - time_str, - dd_date, - dd_time, - timezone, + display_time = _( + u"%(date_start)s at %(time_start)s To\n %(date_end)s at %(time_end)s (%(timezone)s)", + date_start=date_str, + time_start=time_str, + date_end=dd_date, + time_end=dd_time, + timezone=timezone, ) return display_time @@ -356,12 +358,20 @@ class Meeting(models.Model): if meeting.start and meeting.stop and meeting.stop < meeting.start: raise ValidationError( _('The ending date and time cannot be earlier than the starting date and time.') + '\n' + - _("Meeting '%s' starts '%s' and ends '%s'") % (meeting.name, meeting.start, meeting.stop) + _("Meeting '%(name)s' starts '%(start_datetime)s' and ends '%(end_datetime)s'", + name=meeting.name, + start_datetime=meeting.start, + end_datetime=meeting.stop + ) ) if meeting.start_date and meeting.stop_date and meeting.stop_date < meeting.start_date: raise ValidationError( _('The ending date cannot be earlier than the starting date.') + '\n' + - _("Meeting '%s' starts '%s' and ends '%s'") % (meeting.name, meeting.start_date, meeting.stop_date) + _("Meeting '%(name)s' starts '%(start_datetime)s' and ends '%(end_datetime)s'", + name=meeting.name, + start_datetime=meeting.start, + end_datetime=meeting.stop + ) ) #################################################### diff --git a/addons/calendar/models/calendar_recurrence.py b/addons/calendar/models/calendar_recurrence.py index 73c671c611a..9dae012b6d4 100644 --- a/addons/calendar/models/calendar_recurrence.py +++ b/addons/calendar/models/calendar_recurrence.py @@ -124,7 +124,7 @@ class RecurrenceRule(models.Model): def _compute_name(self): for recurrence in self: period = dict(RRULE_TYPE_SELECTION)[recurrence.rrule_type] - every = _("Every %s %s, ") % (recurrence.interval, period) + every = _("Every %(count)s %(period)s, ", count=recurrence.interval, period=period) if recurrence.end_type == 'count': end = _("for %s events", recurrence.count) @@ -140,7 +140,7 @@ class RecurrenceRule(models.Model): elif recurrence.rrule_type == 'monthly': if recurrence.month_by == 'day': weekday_label = dict(BYDAY_SELECTION)[recurrence.byday] - on = _("on the %(position)s %(weekday)s, ") % {'position': recurrence.byday, 'weekday': weekday_label} + on = _("on the %(position)s %(weekday)s, ", position=recurrence.byday, weekday=weekday_label) else: on = _("day %s, ", recurrence.day) else: diff --git a/addons/calendar_sms/models/calendar.py b/addons/calendar_sms/models/calendar.py index 6b08ddcbe9d..b47a28b0916 100644 --- a/addons/calendar_sms/models/calendar.py +++ b/addons/calendar_sms/models/calendar.py @@ -22,7 +22,7 @@ class CalendarEvent(models.Model): for event in self: event._message_sms_with_template( template_xmlid='calendar_sms.sms_template_data_calendar_reminder', - template_fallback=_("Event reminder: %s, %s.") % (event.name, event.display_time), + template_fallback=_("Event reminder: %(name)s, %(time)s.", name=event.name, time=event.display_time), partner_ids=self._sms_get_default_partners().ids, put_in_queue=False ) diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 2c7b2b541f7..52f669bb9ba 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -894,7 +894,11 @@ class Lead(models.Model): for message in opportunity.message_ids: message.write({ 'res_id': self.id, - 'subject': _("From %s : %s") % (opportunity.name, message.subject) + 'subject': _( + "From %(source_name)s : %(source_subject)s", + source_name=opportunity.name, + source_subject=message.subject + ) }) return True diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py index f7f10919a7c..d4c90d77d55 100644 --- a/addons/delivery/models/stock_picking.py +++ b/addons/delivery/models/stock_picking.py @@ -172,7 +172,13 @@ class StockPicking(models.Model): if res['tracking_number']: self.carrier_tracking_ref = res['tracking_number'] order_currency = self.sale_id.currency_id or self.company_id.currency_id - msg = _("Shipment sent to carrier %s for shipping with tracking number %s
Cost: %.2f %s") % (self.carrier_id.name, self.carrier_tracking_ref, self.carrier_price, order_currency.name) + msg = _( + "Shipment sent to carrier %(carrier_name)s for shipping with tracking number %(ref)s
Cost: %(price).2f %(currency)s", + carrier_name=self.carrier_id.name, + ref=self.carrier_tracking_ref, + price=self.carrier_price, + currency=order_currency.name + ) self.message_post(body=msg) self._add_delivery_cost_to_so() diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py index 72fcf48ebad..93efdef0d9b 100644 --- a/addons/gamification/models/challenge.py +++ b/addons/gamification/models/challenge.py @@ -656,7 +656,11 @@ class Challenge(models.Model): if rewarded_users: user_names = rewarded_users.name_get() - message_body += _("
Reward (badge %s) for every succeeding user was sent to %s.") % (challenge.reward_id.name, ", ".join(name for (user_id, name) in user_names)) + message_body += _( + "
Reward (badge %(badge_name)s) for every succeeding user was sent to %(users)s.", + badge_name=challenge.reward_id.name, + users=", ".join(name for (user_id, name) in user_names) + ) else: message_body += _("
Nobody has succeeded to reach every goal, no badge is rewarded for this challenge.") diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index 2236a5baa45..e26ac0b37ff 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -111,11 +111,17 @@ class GoalDefinition(models.Model): Model = self.env[definition.model_id.model] field = Model._fields.get(definition.field_id.name) if not (field and field.store): - raise exceptions.UserError( - _("The model configuration for the definition %s seems incorrect, please check it.\n\n%s not stored") % (definition.name, definition.field_id.name)) + raise exceptions.UserError(_( + "The model configuration for the definition %(name)s seems incorrect, please check it.\n\n%(field_name)s not stored", + name=definition.name, + field_name=definition.field_id.name + )) except KeyError as e: - raise exceptions.UserError( - _("The model configuration for the definition %s seems incorrect, please check it.\n\n%s not found") % (definition.name, e)) + raise exceptions.UserError(_( + "The model configuration for the definition %(name)s seems incorrect, please check it.\n\n%(error)s not found", + name=definition.name, + error=e + )) @api.model def create(self, vals): diff --git a/addons/google_calendar/models/calendar.py b/addons/google_calendar/models/calendar.py index 57d9f63a440..765473509ba 100644 --- a/addons/google_calendar/models/calendar.py +++ b/addons/google_calendar/models/calendar.py @@ -131,15 +131,27 @@ class Meeting(models.Model): if minutes % (60*24) == 0: interval = 'days' duration = minutes / 60 / 24 - name = _("%s - %s Days") % (alarm_type_label, duration) + name = _( + "%(reminder_type)s - %(duration)s Days", + reminder_type=alarm_type_label, + duration=duration, + ) elif minutes % 60 == 0: interval = 'hours' duration = minutes / 60 - name = _("%s - %s Hours") % (alarm_type_label, duration) + name = _( + "%(reminder_type)s - %(duration)s Hours", + reminder_type=alarm_type_label, + duration=duration, + ) else: interval = 'minutes' duration = minutes - name = _("%s - %s Minutes") % (alarm_type_label, duration) + name = _( + "%(reminder_type)s - %(duration)s Minutes", + reminder_type=alarm_type_label, + duration=duration, + ) commands += [(0, 0, {'duration': duration, 'interval': interval, 'name': name, 'alarm_type': alarm_type})] return commands diff --git a/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py b/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py index ff586f68491..37e1f0bf68d 100644 --- a/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py +++ b/addons/hr_expense/wizard/hr_expense_sheet_register_payment.py @@ -113,7 +113,14 @@ class HrExpenseSheetRegisterPaymentWizard(models.TransientModel): payment.action_post() # Log the payment in the chatter - body = (_("A payment of %s %s with the reference %s related to your expense %s has been made.") % (payment.amount, payment.currency_id.symbol, url_encode({'model': 'account.payment', 'res_id': payment.id}), payment.name, expense_sheet.name)) + body = _( + "A payment of %(amount)s %(currency)s with the reference %(payment_name)s related to your expense %(expense_name)s has been made.", + amount=payment.amount, + currency=payment.currency_id.symbol, + url=url_encode({'model': 'account.payment', 'res_id': payment.id}), + payment_name=payment.name, + expense_name=expense_sheet.name + ) expense_sheet.message_post(body=body) # Reconcile the payment and the expense, i.e. lookup on the payable account move lines diff --git a/addons/hr_fleet/controllers/main.py b/addons/hr_fleet/controllers/main.py index 175139e04da..80748991fda 100644 --- a/addons/hr_fleet/controllers/main.py +++ b/addons/hr_fleet/controllers/main.py @@ -52,7 +52,12 @@ class HrFleet(Controller): date_start = car_line_doc.date_start date_end = car_line_doc.date_end or '...' - text_to_print = _("%s (driven from: %s to %s)") % (car_name, date_start, date_end) + text_to_print = _( + "%(car_name)s (driven from: %(date_start)s to %(date_end)s)", + car_name=car_name, + date_start=date_start, + date_end=date_end + ) can.drawCentredString(width / 2, height - normal_font_size, text_to_print) can.save() header_pdf = PdfFileReader(header, overwriteWarnings=False) diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 5e88edf967e..9da4c75eb71 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -621,11 +621,11 @@ class HolidaysRequest(models.Model): if leave.leave_type_request_unit == 'hour': res.append(( leave.id, - _("%s on %s: %.2f hours on %s") % ( - target, - leave.holiday_status_id.name, - leave.number_of_hours_display, - fields.Date.to_string(leave.date_from), + _("%(person)s on %(leave_type)s: %(duration).2f hours on %(date)s", + person=target, + leave_type=leave.holiday_status_id.name, + duration=leave.number_of_hours_display, + date=fields.Date.to_string(leave.date_from), ) )) else: @@ -634,11 +634,11 @@ class HolidaysRequest(models.Model): display_date += ' ⇨ %s' % fields.Date.to_string(leave.date_to) res.append(( leave.id, - _("%s on %s: %.2f days (%s)") % ( - target, - leave.holiday_status_id.name, - leave.number_of_days, - display_date, + _("%(person)s on %(leave_type)s: %(duration).2f days (%(start)s)", + person=target, + leave_type=leave.holiday_status_id.name, + duration=leave.number_of_days, + start=display_date, ) )) return res @@ -657,19 +657,26 @@ class HolidaysRequest(models.Model): dto = leave.date_to if leave.holiday_status_id.validity_start and leave.holiday_status_id.validity_stop: if dfrom and dto and (dfrom.date() < vstart or dto.date() > vstop): - raise ValidationError( - _('%s are only valid between %s and %s') % ( - leave.holiday_status_id.display_name, leave.holiday_status_id.validity_start, leave.holiday_status_id.validity_stop)) + raise ValidationError(_( + '%(leave_type)s are only valid between %(start)s and %(end)s', + leave_type=leave.holiday_status_id.display_name, + start=leave.holiday_status_id.validity_start, + end=leave.holiday_status_id.validity_stop + )) elif leave.holiday_status_id.validity_start: if dfrom and (dfrom.date() < vstart): - raise ValidationError( - _('%s are only valid starting from %s') % ( - leave.holiday_status_id.display_name, leave.holiday_status_id.validity_start)) + raise ValidationError(_( + '%(leave_type)s are only valid starting from %(date)s', + leave_type=leave.holiday_status_id.display_name, + date=leave.holiday_status_id.validity_start + )) elif leave.holiday_status_id.validity_stop: if dto and (dto.date() > vstop): - raise ValidationError( - _('%s are only valid until %s') % ( - leave.holiday_status_id.display_name, leave.holiday_status_id.validity_stop)) + raise ValidationError(_( + '%(leave_type)s are only valid until %(date)s', + leave_type=leave.holiday_status_id.display_name, + date=leave.holiday_status_id.validity_stop + )) def _check_double_validation_rules(self, employees, state): if self.user_has_groups('hr_holidays.group_hr_holidays_manager'): @@ -1032,7 +1039,7 @@ class HolidaysRequest(models.Model): for holiday in self: if holiday.employee_id.user_id: holiday.message_post( - body=_('Your %s planned on %s has been refused') % (holiday.holiday_status_id.display_name, holiday.date_from), + body=_('Your %(leave_type)s planned on %(date)s has been refused', leave_type=holiday.holiday_status_id.display_name, date=holiday.date_from), partner_ids=holiday.employee_id.user_id.partner_id.ids) self._remove_resource_leave() @@ -1101,7 +1108,13 @@ class HolidaysRequest(models.Model): for holiday in self: start = UTC.localize(holiday.date_from).astimezone(timezone(holiday.employee_id.tz or 'UTC')) end = UTC.localize(holiday.date_to).astimezone(timezone(holiday.employee_id.tz or 'UTC')) - note = _('New %s Request created by %s from %s to %s') % (holiday.holiday_status_id.name, holiday.create_uid.name, start, end) + note = _( + 'New %(leave_type)s Request created by %(user)s from %(start)s to %(end)s', + leave_type=holiday.holiday_status_id.name, + user=holiday.create_uid.name, + start=start, + end=end + ) if holiday.state == 'draft': to_clean |= holiday elif holiday.state == 'confirm': diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index 6fda4311739..5c39867ba50 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -389,11 +389,12 @@ class HolidaysAllocation(models.Model): res.append( (allocation.id, - _("Allocation of %s : %.2f %s to %s") % - (allocation.holiday_status_id.sudo().name, - allocation.number_of_hours_display if allocation.type_request_unit == 'hour' else allocation.number_of_days, - 'hours' if allocation.type_request_unit == 'hour' else 'days', - target)) + _("Allocation of %(allocation_name)s : %(duration).2f %(duration_type)s to %(person)s", + allocation_name=allocation.holiday_status_id.sudo().name, + duration=allocation.number_of_hours_display if allocation.type_request_unit == 'hour' else allocation.number_of_days, + duration_type='hours' if allocation.type_request_unit == 'hour' else 'days', + person=target + )) ) return res @@ -410,7 +411,11 @@ class HolidaysAllocation(models.Model): today = fields.Date.today() if vstop < today: - raise ValidationError(_('You can allocate %s only before %s.') % (allocation.holiday_status_id.display_name, allocation.holiday_status_id.validity_stop)) + raise ValidationError(_( + 'You can allocate %(allocation_type)s only before %(date)s.', + allocation_type=allocation.holiday_status_id.display_name, + date=allocation.holiday_status_id.validity_stop + )) @api.model def create(self, values): @@ -613,7 +618,12 @@ class HolidaysAllocation(models.Model): def activity_update(self): to_clean, to_do = self.env['hr.leave.allocation'], self.env['hr.leave.allocation'] for allocation in self: - note = _('New Allocation Request created by %s: %s Days of %s') % (allocation.create_uid.name, allocation.number_of_days, allocation.holiday_status_id.name) + note = _( + 'New Allocation Request created by %(user)s: %(count)s Days of %(allocation_type)s', + user=allocation.create_uid.name, + count=allocation.number_of_days, + allocation_type=allocation.holiday_status_id.name + ) if allocation.state == 'draft': to_clean |= allocation elif allocation.state == 'confirm': diff --git a/addons/hr_skills/models/hr_skills.py b/addons/hr_skills/models/hr_skills.py index e562dd58449..759607a8e72 100644 --- a/addons/hr_skills/models/hr_skills.py +++ b/addons/hr_skills/models/hr_skills.py @@ -33,13 +33,13 @@ class EmployeeSkill(models.Model): def _check_skill_type(self): for record in self: if record.skill_id not in record.skill_type_id.skill_ids: - raise ValidationError(_("The skill %s and skill type %s doesn't match") % (record.skill_id.name, record.skill_type_id.name)) + raise ValidationError(_("The skill %(name)s and skill type %(type)s doesn't match", name=record.skill_id.name, type=record.skill_type_id.name)) @api.constrains('skill_type_id', 'skill_level_id') def _check_skill_level(self): for record in self: if record.skill_level_id not in record.skill_type_id.skill_level_ids: - raise ValidationError(_("The skill level %s is not valid for skill type: %s ") % (record.skill_level_id.name, record.skill_type_id.name)) + raise ValidationError(_("The skill level %(level)s is not valid for skill type: %(type)s", level=record.skill_level_id.name, type=record.skill_type_id.name)) class SkillLevel(models.Model): diff --git a/addons/hr_timesheet/models/project.py b/addons/hr_timesheet/models/project.py index ed0ac3a5bad..c9d294a1a61 100644 --- a/addons/hr_timesheet/models/project.py +++ b/addons/hr_timesheet/models/project.py @@ -186,7 +186,12 @@ class Task(models.Model): for task in self: if task.allow_timesheets and task.planned_hours > 0: hours, mins = (str(int(duration)).rjust(2, '0') for duration in divmod(abs(task.remaining_hours) * 60, 60)) - hours_left = _("(%s%s:%s remaining)") % ('-' if task.remaining_hours < 0 else '', hours, mins) + hours_left = _( + "(%(sign)s%(hours)s:%(minutes)s remaining)", + sign='-' if task.remaining_hours < 0 else '', + hours=hours, + minutes=mins, + ) name_mapping[task.id] = name_mapping.get(task.id, '') + " ‒ " + hours_left return list(name_mapping.items()) return super().name_get() diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index dd92b4a17b3..81e04898477 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -433,7 +433,9 @@ class MailActivity(models.Model): record.message_notify( partner_ids=activity.user_id.partner_id.ids, body=body, - subject=_('%s: %s assigned to you') % (activity.res_name, activity.summary or activity.activity_type_id.name), + subject=_('%(activity_name)s: %(summary)s assigned to you', + activity_name=activity.res_name, + summary=activity.summary or activity.activity_type_id.name), record_name=activity.res_name, model_description=model_description, email_layout_xmlid='mail.mail_notification_light', diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index e2ea498ef0e..23f63f4dad3 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -1016,6 +1016,6 @@ class Channel(models.Model): msg = _("You are alone in this channel.") else: dots = "..." if len(members) != len(self.channel_partner_ids) - 1 else "" - msg = _("Users in this channel: %s %s and you.") % (", ".join(members), dots) + msg = _("Users in this channel: %(members)s %(dots)s and you.", members=", ".join(members), dots=dots) self._send_transient_message(partner, msg) diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 3f8818bc386..dcadca5b281 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -798,7 +798,12 @@ class MailThread(models.AbstractModel): # Existing Document: check if exists and model accepts the mailgateway; if not, fallback on create if allowed if thread_id: if not record_set.exists(): - self._routing_warn(_('reply to missing document (%s,%s), fall back on document creation') % (model, thread_id), message_id, route, False) + self._routing_warn( + _('reply to missing document (%(model)s,%(thread)s), fall back on document creation', model=model, thread=thread_id), + message_id, + route, + False + ) thread_id = None elif not hasattr(record_set, 'message_update'): self._routing_warn(_('reply to model %s that does not accept document update, fall back on document creation', model), message_id, route, False) @@ -834,7 +839,12 @@ class MailThread(models.AbstractModel): else: error_code = self.env['mail.alias.mixin']._alias_check_contact_on_record(obj, message, message_dict, alias) if error_code is not True: - self._routing_warn(_('alias %s: %s') % (alias.alias_name, error_code or _('unknown error')), message_id, route, False) + self._routing_warn( + _('alias %(name)s: %(error)s', name=alias.alias_name, error=error_code or _('unknown error')), + message_id, + route, + False + ) body = alias._get_alias_bounced_body(message_dict) self._routing_create_bounce_email(email_from, body, message, references=message_id) return False diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index bbe67a37cdc..3d96ebe25b6 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -64,7 +64,7 @@ class Invite(models.TransientModel): # send an email if option checked and if a message exists (do not send void emails) if wizard.send_mail and wizard.message and not wizard.message == '
': # when deleting the message, cleditor keeps a
message = self.env['mail.message'].create({ - 'subject': _('Invitation to follow %s: %s') % (model_name, document.display_name), + 'subject': _('Invitation to follow %(document_model)s: %(document_name)s', document_model=model_name, document_name=document.display_name), 'body': wizard.message, 'record_name': document.display_name, 'email_from': email_from, diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py index 43bce93cf71..7a154b16d0f 100644 --- a/addons/mrp/models/mrp_bom.py +++ b/addons/mrp/models/mrp_bom.py @@ -96,10 +96,12 @@ class MrpBom(models.Model): % (bom.product_id.display_name, ", ".join([ptav.display_name for ptav in bom_line.bom_product_template_attribute_value_ids]))) for ptav in bom_line.bom_product_template_attribute_value_ids: if ptav.product_tmpl_id != bom.product_tmpl_id: - raise ValidationError( - _("The attribute value %s set on product %s does not match the BoM product %s.") % - (ptav.display_name, ptav.product_tmpl_id.display_name, bom_line.parent_product_tmpl_id.display_name) - ) + raise ValidationError(_( + "The attribute value %(attribute)s set on product %(product)s does not match the BoM product %(bom_product)s.", + attribute=ptav.display_name, + product=ptav.product_tmpl_id.display_name, + bom_product=bom_line.parent_product_tmpl_id.display_name + )) @api.onchange('product_uom_id') def onchange_product_uom_id(self): diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 229d93f5b5d..491c775f6c3 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -1596,7 +1596,9 @@ class MrpProduction(models.Model): ('qty_done', '=', 1), ('state', '=', 'done') ] - message = _('The serial number %s used for byproduct %s has already been produced') % (move_line.lot_id.name, move_line.product_id.name) + message = _('The serial number %(number)s used for byproduct %(product_name)s has already been produced', + number=move_line.lot_id.name, + product_name=move_line.product_id.name) co_prod_move_lines = self.move_finished_ids.move_line_ids.filtered(lambda ml: ml.product_id != self.product_id) domain_unbuild = domain + [ ('production_id', '=', False), @@ -1628,7 +1630,9 @@ class MrpProduction(models.Model): ('qty_done', '=', 1), ('state', '=', 'done') ] - message = _('The serial number %s used for component %s has already been consumed') % (move_line.lot_id.name, move_line.product_id.name) + message = _('The serial number %(number)s used for component %(component)s has already been consumed', + number=move_line.lot_id.name, + component=move_line.product_id.name) co_prod_move_lines = self.move_raw_ids.move_line_ids domain_unbuild = domain + [ ('production_id', '=', False), diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index ad8711bd420..d9e89060c5c 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -175,9 +175,9 @@ class MrpWorkorder(models.Model): if wo.state == 'pending' and prev_start and not (prev_start > wo.date_planned_start): infos.append({ 'color': 'text-primary', - 'msg': _("Waiting the previous work order, planned from %s to %s") % ( - format_datetime(self.env, prev_start, dt_format=False), - format_datetime(self.env, prev_finished, dt_format=False)) + 'msg': _("Waiting the previous work order, planned from %(start)s to %(end)s", + start=format_datetime(self.env, prev_start, dt_format=False), + end=format_datetime(self.env, prev_finished, dt_format=False)) }) if wo.date_planned_finished < fields.Datetime.now(): infos.append({ @@ -187,14 +187,14 @@ class MrpWorkorder(models.Model): if prev_start and prev_start > wo.date_planned_start: infos.append({ 'color': 'text-danger', - 'msg': _("Scheduled before the previous work order, planned from %s to %s") % ( - format_datetime(self.env, prev_start, dt_format=False), - format_datetime(self.env, prev_finished, dt_format=False)) + 'msg': _("Scheduled before the previous work order, planned from %(start)s to %(end)s", + start=format_datetime(self.env, prev_start, dt_format=False), + end=format_datetime(self.env, prev_finished, dt_format=False)) }) if conflicted_dict.get(wo.id): infos.append({ 'color': 'text-danger', - 'msg': _("Planned at the same time than other workorder(s) at %s" % wo.workcenter_id.display_name) + 'msg': _("Planned at the same time than other workorder(s) at %s", wo.workcenter_id.display_name) }) color_icon = infos and infos[-1]['color'] or False wo.show_json_popover = bool(color_icon) diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py index 29657577a4f..cd82ca389f6 100644 --- a/addons/mrp/wizard/change_production_qty.py +++ b/addons/mrp/wizard/change_production_qty.py @@ -48,7 +48,11 @@ class ChangeProductionQty(models.TransientModel): produced = sum(production.move_finished_ids.filtered(lambda m: m.product_id == production.product_id).mapped('quantity_done')) if wizard.product_qty < produced: format_qty = '%.{precision}f'.format(precision=precision) - raise UserError(_("You have already processed %s. Please input a quantity higher than %s ") % (format_qty % produced, format_qty % produced)) + raise UserError(_( + "You have already processed %(quantity)s. Please input a quantity higher than %(minimum)s ", + quantity=format_qty % produced, + minimum=format_qty % produced + )) old_production_qty = production.product_qty new_production_qty = wizard.product_qty done_moves = production.move_finished_ids.filtered(lambda x: x.state == 'done' and x.product_id == production.product_id) diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index a1a7da752bc..936e8d1c601 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -253,7 +253,7 @@ class PaymentTransactionStripe(models.Model): _logger.error(error_msg) raise ValidationError(error_msg) elif len(tx) > 1: - error_msg = (_('Stripe: %s orders found for reference %s') % (len(tx), reference)) + error_msg = _('Stripe: %(count)s orders found for reference %(reference)s', count=len(tx), reference=reference) _logger.error(error_msg) raise ValidationError(error_msg) return tx[0] diff --git a/addons/phone_validation/tools/phone_validation.py b/addons/phone_validation/tools/phone_validation.py index 87fe5498188..ac96c82a87a 100644 --- a/addons/phone_validation/tools/phone_validation.py +++ b/addons/phone_validation/tools/phone_validation.py @@ -17,7 +17,7 @@ try: try: phone_nbr = phonenumbers.parse(number, region=country_code, keep_raw_input=True) except phonenumbers.phonenumberutil.NumberParseException as e: - raise UserError(_('Unable to parse %s.: %s') % (number, str(e))) + raise UserError(_('Unable to parse %(phone)s: %(error)s', phone=number, error=str(e))) if not phonenumbers.is_possible_number(phone_nbr): raise UserError(_('Impossible number %s: probably invalid number of digits.', number)) diff --git a/addons/point_of_sale/models/pos_payment.py b/addons/point_of_sale/models/pos_payment.py index a87762f501a..8dea1f62b92 100644 --- a/addons/point_of_sale/models/pos_payment.py +++ b/addons/point_of_sale/models/pos_payment.py @@ -33,7 +33,7 @@ class PosPayment(models.Model): res = [] for payment in self: if payment.name: - res.append((payment.id, _('%s %s') % (payment.name, formatLang(self.env, payment.amount, currency_obj=payment.currency_id)))) + res.append((payment.id, '%s %s' % (payment.name, formatLang(self.env, payment.amount, currency_obj=payment.currency_id)))) else: res.append((payment.id, formatLang(self.env, payment.amount, currency_obj=payment.currency_id))) return res diff --git a/addons/portal/models/mail_thread.py b/addons/portal/models/mail_thread.py index 424e3de0c25..0e9b58b9fca 100644 --- a/addons/portal/models/mail_thread.py +++ b/addons/portal/models/mail_thread.py @@ -28,7 +28,11 @@ class MailThread(models.AbstractModel): self.ensure_one() # check token field exists if self._mail_post_token_field not in self._fields: - raise NotImplementedError(_("Model %s does not support token signature, as it does not have %s field.") % (self._name, self._mail_post_token_field)) + raise NotImplementedError(_( + "Model %(model_name)s does not support token signature, as it does not have %(field_name)s field.", + model_name=self._name, + field_name=self._mail_post_token_field + )) # sign token secret = self.env["ir.config_parameter"].sudo().get_param("database.secret") token = (self.env.cr.dbname, self[self._mail_post_token_field], pid) diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index 1b2b0640284..d1ef0ec714c 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -521,7 +521,7 @@ class PricelistItem(models.Model): elif item.compute_price == 'percentage': item.price = _("%s %% discount", item.percent_price) else: - item.price = _("%s %% discount and %s surcharge") % (item.price_discount, item.price_surcharge) + item.price = _("%(percentage)s %% discount and %(price)s surcharge", percentage=item.price_discount, price=item.price_surcharge) @api.onchange('compute_price') def _onchange_compute_price(self): diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 7afe483ceaa..b0d8316f342 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -138,7 +138,12 @@ class PurchaseOrder(models.Model): companies = order.order_line.product_id.company_id if companies and companies != order.company_id: bad_products = order.order_line.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id) - raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name'))))) + raise ValidationError(_( + "Your quotation contains products from company %(product_company)s whereas your quotation belongs to company %(quote_company)s. \n Please change the company of your quotation or remove the products from other companies (%(bad_products)s).", + product_company=', '.join(companies.mapped('display_name')), + quote_company=order.company_id.display_name, + bad_products=', '.join(bad_products.mapped('display_name')), + )) def _compute_access_url(self): super(PurchaseOrder, self)._compute_access_url() @@ -723,7 +728,12 @@ class PurchaseOrder(models.Model): on portal website.""" note = _('

%s modified receipt dates for the following products:

', self.partner_id.name) for line, date in updated_dates: - note += _('

  - %s from %s to %s

') % (line.product_id.display_name, line.date_planned, date) + note += _( + '

  - %(product_name)s from %(date_start)s to %(date_end)s

', + product_name=line.product_id.display_name, + date_start=line.date_planned, + date_end=date + ) return note diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index aba5569b04c..b52e0a640e2 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -263,7 +263,12 @@ class SaleOrder(models.Model): companies = order.order_line.product_id.company_id if companies and companies != order.company_id: bad_products = order.order_line.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id) - raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name'))))) + raise ValidationError(_( + "Your quotation contains products from company %(product_company)s whereas your quotation belongs to company %(quote_company)s. \n Please change the company of your quotation or remove the products from other companies (%(bad_products)s).", + product_company=', '.join(companies.mapped('display_name')), + quote_company=order.company_id.display_name, + bad_products=', '.join(bad_products.mapped('display_name')), + )) @api.depends('pricelist_id', 'date_order', 'company_id') def _compute_currency_rate(self): diff --git a/addons/sale_coupon/models/coupon.py b/addons/sale_coupon/models/coupon.py index 6fbd5ce451f..bc92f4366a2 100644 --- a/addons/sale_coupon/models/coupon.py +++ b/addons/sale_coupon/models/coupon.py @@ -25,7 +25,11 @@ class Coupon(models.Model): message = {'error': _('This coupon is expired (%s).') % (self.code)} # Minimum requirement should not be checked if the coupon got generated by a promotion program (the requirement should have only be checked to generate the coupon) elif self.program_id.program_type == 'coupon_program' and not self.program_id._filter_on_mimimum_amount(order): - message = {'error': _('A minimum of %s %s should be purchased to get the reward') % (self.program_id.rule_minimum_amount, self.program_id.currency_id.name)} + message = {'error': _( + 'A minimum of %(amount)s %(currency)s should be purchased to get the reward', + amount=self.program_id.rule_minimum_amount, + currency=self.program_id.currency_id.name + )} elif not self.program_id.active: message = {'error': _('The coupon program for %s is in draft or closed state') % (self.code)} elif self.partner_id and self.partner_id != order.partner_id: diff --git a/addons/sale_coupon/models/coupon_program.py b/addons/sale_coupon/models/coupon_program.py index 5bc83d493e0..35fa15cb72e 100644 --- a/addons/sale_coupon/models/coupon_program.py +++ b/addons/sale_coupon/models/coupon_program.py @@ -34,7 +34,11 @@ class CouponProgram(models.Model): if self.maximum_use_number != 0 and self.order_count >= self.maximum_use_number: message = {'error': _('Promo code %s has been expired.') % (coupon_code)} elif not self._filter_on_mimimum_amount(order): - message = {'error': _('A minimum of %s %s should be purchased to get the reward') % (self.rule_minimum_amount, self.currency_id.name)} + message = {'error': _( + 'A minimum of %(amount)s %(currency)s should be purchased to get the reward', + amount=self.rule_minimum_amount, + currency=self.currency_id.name + )} elif self.promo_code and self.promo_code == order.promo_code: message = {'error': _('The promo code is already applied on this order')} elif not self.promo_code and self in order.no_code_promo_program_ids: diff --git a/addons/sale_management/models/sale_order.py b/addons/sale_management/models/sale_order.py index 04a9e87128a..f2ea0512f8b 100644 --- a/addons/sale_management/models/sale_order.py +++ b/addons/sale_management/models/sale_order.py @@ -35,7 +35,12 @@ class SaleOrder(models.Model): companies = order.sale_order_option_ids.product_id.company_id if companies and companies != order.company_id: bad_products = order.sale_order_option_ids.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id) - raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name'))))) + raise ValidationError(_( + "Your quotation contains products from company %(product_company)s whereas your quotation belongs to company %(quote_company)s. \n Please change the company of your quotation or remove the products from other companies (%(bad_products)s).", + product_company=', '.join(companies.mapped('display_name')), + quote_company=order.company_id.display_name, + bad_products=', '.join(bad_products.mapped('display_name')), + )) @api.returns('self', lambda value: value.id) def copy(self, default=None): diff --git a/addons/sale_management/models/sale_order_template.py b/addons/sale_management/models/sale_order_template.py index 5eaed0176f0..0552938bde3 100644 --- a/addons/sale_management/models/sale_order_template.py +++ b/addons/sale_management/models/sale_order_template.py @@ -37,7 +37,11 @@ class SaleOrderTemplate(models.Model): if len(companies) > 1: raise ValidationError(_("Your template cannot contain products from multiple companies.")) elif companies and companies != template.company_id: - raise ValidationError((_("Your template contains products from company %s whereas your template belongs to company %s. \n Please change the company of your template or remove the products from other companies.") % (companies.mapped('display_name'), template.company_id.display_name))) + raise ValidationError(_( + "Your template contains products from company %(product_company)s whereas your template belongs to company %(template_company)s. \n Please change the company of your template or remove the products from other companies.", + product_company=', '.join(companies.mapped('display_name')), + template_company=template.company_id.display_name, + )) @api.onchange('sale_order_template_line_ids', 'sale_order_template_option_ids') def _onchange_template_line_ids(self): diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py index 41e4e6d5bb4..fde99c982c2 100644 --- a/addons/sale_stock/models/sale_order.py +++ b/addons/sale_stock/models/sale_order.py @@ -584,7 +584,13 @@ class SaleOrderLine(models.Model): return { 'warning': { 'title': _('Warning'), - 'message': _("This product is packaged by %.2f %s. You should sell %.2f %s.") % (pack.qty, default_uom.name, newqty, self.product_uom.name), + 'message': _( + "This product is packaged by %(pack_size).2f %(pack_name)s. You should sell %(quantity).2f %(unit)s.", + pack_size=pack.qty, + pack_name=default_uom.name, + quantity=newqty, + unit=self.product_uom.name + ), }, } return {} diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py index ead232b7cdd..0ca8576dae4 100644 --- a/addons/stock/models/stock_warehouse.py +++ b/addons/stock/models/stock_warehouse.py @@ -686,7 +686,7 @@ class Warehouse(models.Model): def _get_inter_warehouse_route_values(self, supplier_warehouse): return { - 'name': _('%s: Supply Product from %s') % (self.name, supplier_warehouse.name), + 'name': _('%(warehouse)s: Supply Product from %(supplier)s', warehouse=self.name, supplier=supplier_warehouse.name), 'warehouse_selectable': True, 'product_selectable': True, 'product_categ_selectable': True, diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py index a87cdcd7510..fa954ec8f50 100644 --- a/addons/stock_account/models/product.py +++ b/addons/stock_account/models/product.py @@ -253,13 +253,25 @@ class ProductProduct(models.Model): 'stock_valuation_layer_ids': [(6, None, [stock_valuation_layer.id])], 'move_type': 'entry', 'line_ids': [(0, 0, { - 'name': _('%s changed cost from %s to %s - %s') % (self.env.user.name, product.standard_price, new_price, product.display_name), + 'name': _( + '%(user)s changed cost from %(previous)s to %(new_price)s - %(product)s', + user=self.env.user.name, + previous=product.standard_price, + new_price=new_price, + product=product.display_name + ), 'account_id': debit_account_id, 'debit': abs(value), 'credit': 0, 'product_id': product.id, }), (0, 0, { - 'name': _('%s changed cost from %s to %s - %s') % (self.env.user.name, product.standard_price, new_price, product.display_name), + 'name': _( + '%(user)s changed cost from %(previous)s to %(new_price)s - %(product)s', + user=self.env.user.name, + previous=product.standard_price, + new_price=new_price, + product=product.display_name + ), 'account_id': credit_account_id, 'debit': 0, 'credit': abs(value), diff --git a/addons/stock_account/wizard/stock_valuation_layer_revaluation.py b/addons/stock_account/wizard/stock_valuation_layer_revaluation.py index 50309cf1fd9..35989e80b67 100644 --- a/addons/stock_account/wizard/stock_valuation_layer_revaluation.py +++ b/addons/stock_account/wizard/stock_valuation_layer_revaluation.py @@ -131,15 +131,23 @@ class StockValuationLayerRevaluation(models.TransientModel): 'date': self.date or fields.Date.today(), 'move_type': 'entry', 'line_ids': [(0, 0, { - 'name': _('%s changed stock valuation from %s to %s of %s') % ( - self.env.user.name, self.current_value_svl, self.current_value_svl + self.added_value, product_id.display_name), + 'name': _('%(user)s changed stock valuation from %(previous)s to %(new_value)s - %(product)s', + user=self.env.user.name, + previous=self.current_value_svl, + new_value=self.current_value_svl + self.added_value, + product=product_id.display_name, + ), 'account_id': debit_account_id, 'debit': abs(self.added_value), 'credit': 0, 'product_id': product_id.id, }), (0, 0, { - 'name': _('%s changed stock valuation from %s to %s of %s') % ( - self.env.user.name, self.current_value_svl, self.current_value_svl + self.added_value, product_id.display_name), + 'name': _('%(user)s changed stock valuation from %(previous)s to %(new_value)s - %(product)s', + user=self.env.user.name, + previous=self.current_value_svl, + new_value=self.current_value_svl + self.added_value, + product=product_id.display_name, + ), 'account_id': credit_account_id, 'debit': 0, 'credit': abs(self.added_value), diff --git a/addons/website_sale_stock/controllers/main.py b/addons/website_sale_stock/controllers/main.py index 43f70fa4e9f..da26a11173c 100644 --- a/addons/website_sale_stock/controllers/main.py +++ b/addons/website_sale_stock/controllers/main.py @@ -20,7 +20,11 @@ class WebsiteSaleStock(WebsiteSale): cart_qty = sum(order.order_line.filtered(lambda p: p.product_id.id == line.product_id.id).mapped('product_uom_qty')) avl_qty = line.product_id.with_context(warehouse=order.warehouse_id.id).virtual_available if cart_qty > avl_qty: - values.append(_('You ask for %s products but only %s is available') % (cart_qty, avl_qty if avl_qty > 0 else 0)) + values.append(_( + 'You ask for %(quantity)s products but only %(available_qty)s is available', + quantity=cart_qty, + available_qty=avl_qty if avl_qty > 0 else 0 + )) if values: raise ValidationError('. '.join(values) + '.') return super(WebsiteSaleStock, self).payment_transaction(**kwargs)