diff options
Diffstat (limited to 'addons')
133 files changed, 549 insertions, 343 deletions
diff --git a/addons/account/models/account_account.py b/addons/account/models/account_account.py index 68a903b2760..1622338baf2 100644 --- a/addons/account/models/account_account.py +++ b/addons/account/models/account_account.py @@ -42,7 +42,7 @@ class AccountAccount(models.Model): def _check_reconcile(self): for account in self: if account.internal_type in ('receivable', 'payable') and account.reconcile == False: - raise ValidationError(_('You cannot have a receivable/payable account that is not reconcilable. (account code: %s)') % account.code) + raise ValidationError(_('You cannot have a receivable/payable account that is not reconcilable. (account code: %s)', account.code)) @api.constrains('user_type_id') def _check_user_type_id(self): @@ -52,7 +52,7 @@ class AccountAccount(models.Model): if res.get('company_id_count', 0) >= 2: account_unaffected_earnings = self.search([('company_id', '=', res['company_id'][0]), ('user_type_id', '=', data_unaffected_earnings.id)]) - raise ValidationError(_('You cannot have more than one account with "Current Year Earnings" as type. (accounts: %s)') % [a.code for a in account_unaffected_earnings]) + raise ValidationError(_('You cannot have more than one account with "Current Year Earnings" as type. (accounts: %s)', [a.code for a in account_unaffected_earnings])) name = fields.Char(string="Account Name", required=True, index=True) currency_id = fields.Many2one('res.currency', string='Account Currency', @@ -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): @@ -445,7 +449,7 @@ class AccountAccount(models.Model): if partner_prop_acc: account_name = partner_prop_acc.get_by_record().display_name raise UserError( - _('You cannot remove/deactivate the account %s which is set on a customer or vendor.') % account_name + _('You cannot remove/deactivate the account %s which is set on a customer or vendor.', account_name) ) return super(AccountAccount, self).unlink() diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 71d6f336dac..502d91c563b 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -75,7 +75,7 @@ class AccountBankStmtCashWizard(models.Model): def name_get(self): result = [] for cashbox in self: - result.append((cashbox.id, _("%s")%(cashbox.total))) + result.append((cashbox.id, str(cashbox.total))) return result @api.model_create_multi @@ -294,29 +294,34 @@ class AccountBankStatement(models.Model): for stmt in self: if not stmt.currency_id.is_zero(stmt.difference): if stmt.journal_type == 'cash': - if stmt.difference < 0.0: - account = stmt.journal_id.loss_account_id - name = _('Loss') - else: - # statement.difference > 0.0 - account = stmt.journal_id.profit_account_id - name = _('Profit') - if not account: - raise UserError(_('Please go on the %s journal and define a %s Account. This account will be used to record cash difference.') % (stmt.journal_id.name, name)) - st_line_vals = { 'statement_id': stmt.id, 'journal_id': stmt.journal_id.id, 'amount': stmt.difference, - 'payment_ref': _("Cash difference observed during the counting (%s)") % name, 'date': stmt.date, } - self.env['account.bank.statement.line'].with_context(counterpart_account_id=account.id).create(st_line_vals) + + if stmt.difference < 0.0: + if not stmt.journal_id.loss_account_id: + raise UserError(_('Please go on the %s journal and define a Loss Account. This account will be used to record cash difference.', stmt.journal_id.name)) + + st_line_vals['payment_ref'] = _("Cash difference observed during the counting (Loss)") + self.env['account.bank.statement.line'].with_context(counterpart_account_id=stmt.journal_id.loss_account_id).create(st_line_vals) + else: + # statement.difference > 0.0 + if not stmt.journal_id.profit_account_id: + raise UserError(_('Please go on the %s journal and define a Profit Account. This account will be used to record cash difference.', stmt.journal_id.name)) + + st_line_vals['payment_ref'] = _("Cash difference observed during the counting (Profit)") + self.env['account.bank.statement.line'].with_context(counterpart_account_id=stmt.journal_id.profit_account_id).create(st_line_vals) 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): @@ -392,13 +397,13 @@ class AccountBankStatement(models.Model): for statement in self: # Chatter. - statement.message_post(body=_('Statement %s confirmed.') % statement.name) + statement.message_post(body=_('Statement %s confirmed.', statement.name)) # Bank statement report. if statement.journal_id.type == 'bank': content, content_type = self.env.ref('account.action_report_account_statement')._render(statement.id) self.env['ir.attachment'].create({ - 'name': statement.name and _("Bank Statement %s.pdf") % statement.name or _("Bank Statement.pdf"), + 'name': statement.name and _("Bank Statement %s.pdf", statement.name) or _("Bank Statement.pdf"), 'type': 'binary', 'datas': base64.encodebytes(content), 'res_model': statement._name, @@ -873,7 +878,7 @@ class AccountBankStatementLine(models.Model): if st_line.currency_id.is_zero(st_line.amount): raise ValidationError(_("The amount of a statement line can't be equal to zero.")) if st_line.foreign_currency_id == st_line.currency_id: - raise ValidationError(_("The foreign currency must be different than the journal one: %s") % st_line.currency_id.name) + raise ValidationError(_("The foreign currency must be different than the journal one: %s", st_line.currency_id.name)) if st_line.foreign_currency_id and st_line.foreign_currency_id.is_zero(st_line.amount_currency): raise ValidationError(_("The amount in foreign currency must be set if the amount is not equal to zero.")) if not st_line.foreign_currency_id and st_line.amount_currency: diff --git a/addons/account/models/account_journal.py b/addons/account/models/account_journal.py index db72d23f5f0..f424d2fb738 100644 --- a/addons/account/models/account_journal.py +++ b/addons/account/models/account_journal.py @@ -213,11 +213,11 @@ class AccountJournal(models.Model): for journal in self: if journal.type == 'bank' and journal.bank_account_id: if journal.bank_account_id.company_id and journal.bank_account_id.company_id != journal.company_id: - raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % journal.company_id.name) + raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).', journal.company_id.name)) # A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier. # Or they are part of a bank journal and their partner_id must be the company's partner_id. if journal.bank_account_id.partner_id != journal.company_id.partner_id: - raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % journal.company_id.name) + raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).', journal.company_id.name)) @api.constrains('company_id') def _check_company_consistency(self): @@ -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): @@ -365,7 +369,7 @@ class AccountJournal(models.Model): journal_entry = self.env['account.move'].search([('journal_id', '=', self.id), ('state', '=', 'posted'), ('secure_sequence_number', '!=', 0)], limit=1) if len(journal_entry) > 0: field_string = self._fields['restrict_mode_hash_table'].get_description(self.env)['string'] - raise UserError(_("You cannot modify the field %s of a journal that already has accounting entries.") % field_string) + raise UserError(_("You cannot modify the field %s of a journal that already has accounting entries.", field_string)) result = super(AccountJournal, self).write(vals) for journal in self: diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index e197d28d037..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) @@ -377,7 +382,7 @@ class AccountMove(models.Model): if p.invoice_warn != 'block' and p.parent_id and p.parent_id.invoice_warn == 'block': p = p.parent_id warning = { - 'title': _("Warning for %s") % p.name, + 'title': _("Warning for %s", p.name), 'message': p.invoice_warn_msg } if p.invoice_warn == 'block': @@ -758,7 +763,7 @@ class AccountMove(models.Model): return rounding_line_vals.update({ - 'name': _('%s (rounding)') % biggest_tax_line.name, + 'name': _('%s (rounding)', biggest_tax_line.name), 'account_id': biggest_tax_line.account_id.id, 'tax_repartition_line_id': biggest_tax_line.tax_repartition_line_id.id, 'tax_exigible': biggest_tax_line.tax_exigible, @@ -1582,9 +1587,9 @@ class AccountMove(models.Model): lock_date = move.company_id._get_user_fiscal_lock_date() if move.date <= lock_date: if self.user_has_groups('account.group_account_manager'): - message = _("You cannot add/modify entries prior to and inclusive of the lock date %s.") % format_date(self.env, lock_date) + message = _("You cannot add/modify entries prior to and inclusive of the lock date %s.", format_date(self.env, lock_date)) else: - message = _("You cannot add/modify entries prior to and inclusive of the lock date %s. Check the company settings or ask someone with the 'Adviser' role") % format_date(self.env, lock_date) + message = _("You cannot add/modify entries prior to and inclusive of the lock date %s. Check the company settings or ask someone with the 'Adviser' role", format_date(self.env, lock_date)) raise UserError(message) return True @@ -2284,7 +2289,7 @@ class AccountMove(models.Model): raise UserError(_('You need to add a line before posting.')) if move.auto_post and move.date > fields.Date.today(): date_msg = move.date.strftime(get_lang(self.env).date_format) - raise UserError(_("This move is configured to be auto-posted on %s") % date_msg) + raise UserError(_("This move is configured to be auto-posted on %s", date_msg)) if not move.partner_id: if move.is_sale_document(): @@ -3466,9 +3471,9 @@ class AccountMoveLine(models.Model): control_type_failed = journal.type_control_ids and account.user_type_id not in journal.type_control_ids control_account_failed = journal.account_control_ids and account not in journal.account_control_ids if control_journal_failed: - raise UserError(_('You cannot use this account (%s) in this journal, check the field \'Allowed Journals\' on the related account.') % account.display_name) + raise UserError(_('You cannot use this account (%s) in this journal, check the field \'Allowed Journals\' on the related account.', account.display_name)) if control_type_failed or control_account_failed: - raise UserError(_('You cannot use this account (%s) in this journal, check the section \'Control-Access\' under tab \'Advanced Settings\' on the related journal.') % account.display_name) + raise UserError(_('You cannot use this account (%s) in this journal, check the section \'Control-Access\' under tab \'Advanced Settings\' on the related journal.', account.display_name)) @api.constrains('account_id', 'tax_ids', 'tax_line_id', 'reconciled') def _check_off_balance(self): diff --git a/addons/account/models/account_partial_reconcile.py b/addons/account/models/account_partial_reconcile.py index 6e445c20c85..29c0c145944 100644 --- a/addons/account/models/account_partial_reconcile.py +++ b/addons/account/models/account_partial_reconcile.py @@ -67,7 +67,7 @@ class AccountPartialReconcile(models.Model): def _check_required_computed_currencies(self): bad_partials = self.filtered(lambda partial: not partial.debit_currency_id or not partial.credit_currency_id) if bad_partials: - raise ValidationError(_("Missing foreign currencies on partials having ids: %s") % bad_partials.ids) + raise ValidationError(_("Missing foreign currencies on partials having ids: %s", bad_partials.ids)) # ------------------------------------------------------------------------- # COMPUTE METHODS diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index e1581932463..ba2e519a914 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -205,9 +205,9 @@ class AccountPayment(models.Model): if self.is_internal_transfer: if self.payment_type == 'inbound': - liquidity_line_name = _('Transfer to %s') % self.journal_id.name + liquidity_line_name = _('Transfer to %s', self.journal_id.name) else: # payment.payment_type == 'outbound': - liquidity_line_name = _('Transfer from %s') % self.journal_id.name + liquidity_line_name = _('Transfer from %s', self.journal_id.name) else: liquidity_line_name = self.payment_reference diff --git a/addons/account/models/account_tax.py b/addons/account/models/account_tax.py index 0ce074b4622..7e5572aea39 100644 --- a/addons/account/models/account_tax.py +++ b/addons/account/models/account_tax.py @@ -184,7 +184,7 @@ class AccountTax(models.Model): @api.returns('self', lambda value: value.id) def copy(self, default=None): - default = dict(default or {}, name=_("%s (Copy)") % self.name) + default = dict(default or {}, name=_("%s (Copy)", self.name)) return super(AccountTax, self).copy(default=default) def name_get(self): diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py index 2b880c8b122..649962c411e 100644 --- a/addons/account/models/chart_template.py +++ b/addons/account/models/chart_template.py @@ -1040,7 +1040,7 @@ class AccountTaxRepartitionLineTemplate(models.Model): all_tax_rep_lines = self.mapped('plus_report_line_ids') + self.mapped('minus_report_line_ids') lines_without_tag = all_tax_rep_lines.filtered(lambda x: not x.tag_name) if lines_without_tag: - raise ValidationError(_("The following tax report lines are used in some tax repartition template though they don't generate any tag: %s . This probably means you forgot to set a tag_name on these lines.") % str(lines_without_tag.mapped('name'))) + raise ValidationError(_("The following tax report lines are used in some tax repartition template though they don't generate any tag: %s . This probably means you forgot to set a tag_name on these lines.", str(lines_without_tag.mapped('name')))) def get_repartition_line_create_vals(self, company): rslt = [(5, 0, 0)] diff --git a/addons/account/models/company.py b/addons/account/models/company.py index bda2c1301ed..acebbb209bf 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -537,7 +537,7 @@ class ResCompany(models.Model): hash_corrupted = False for move in moves: if move.inalterable_hash != move._compute_hash(previous_hash=previous_hash): - rslt.update({'msg_cover': _('Corrupted data on journal entry with id %s.') % move.id}) + rslt.update({'msg_cover': _('Corrupted data on journal entry with id %s.', move.id)}) results_by_journal['results'].append(rslt) hash_corrupted = True break diff --git a/addons/account/models/res_bank.py b/addons/account/models/res_bank.py index 5b587866eef..226e1c889ad 100644 --- a/addons/account/models/res_bank.py +++ b/addons/account/models/res_bank.py @@ -36,7 +36,7 @@ class ResPartnerBank(models.Model): return self._get_qr_code_url(candidate_method, amount, currency, debtor_partner, free_communication, structured_communication) elif not silent_errors: - error_header = _("The following error prevented '%s' QR-code to be generated though it was detected as eligible: ") % candidate_name + error_header = _("The following error prevented '%s' QR-code to be generated though it was detected as eligible: ", candidate_name) raise UserError( error_header + error_message) return None diff --git a/addons/account/models/sequence_mixin.py b/addons/account/models/sequence_mixin.py index f6f4520661d..e75842f8115 100644 --- a/addons/account/models/sequence_mixin.py +++ b/addons/account/models/sequence_mixin.py @@ -96,7 +96,7 @@ class SequenceMixin(models.AbstractModel): """ self.ensure_one() if self._sequence_field not in self._fields or not self._fields[self._sequence_field].store: - raise ValidationError(_('%s is not a stored field') % self._sequence_field) + raise ValidationError(_('%s is not a stored field', self._sequence_field)) where_string, param = self._get_last_sequence_domain(relaxed) if self.id or self.id.origin: where_string += " AND id != %(id)s " diff --git a/addons/account/wizard/account_accrual_accounting.py b/addons/account/wizard/account_accrual_accounting.py index cc6dd3c98ba..b48b5d95a4b 100644 --- a/addons/account/wizard/account_accrual_accounting.py +++ b/addons/account/wizard/account_accrual_accounting.py @@ -202,7 +202,7 @@ class AccrualAccountingWizard(models.TransientModel): record.preview_data = json.dumps({ 'groups_vals': preview_vals, 'options': { - 'discarded_number': (_("%d moves") % preview_discarded) if preview_discarded else False, + 'discarded_number': _("%d moves", preview_discarded) if preview_discarded else False, 'columns': preview_columns, }, }) 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/account/wizard/account_transfer_wizard.py b/addons/account/wizard/account_transfer_wizard.py index c6d73973abf..709adc51f74 100644 --- a/addons/account/wizard/account_transfer_wizard.py +++ b/addons/account/wizard/account_transfer_wizard.py @@ -81,7 +81,7 @@ class AccountTransferWizard(models.TransientModel): # Generate counterpart lines' vals for (counterpart_partner, counterpart_currency), counterpart_vals in counterpart_balances.items(): source_accounts = self.move_line_ids.mapped('account_id') - counterpart_label = len(source_accounts) == 1 and _("Transfer from %s") % source_accounts.display_name or _("Transfer counterpart") + counterpart_label = len(source_accounts) == 1 and _("Transfer from %s", source_accounts.display_name) or _("Transfer counterpart") if not self.company_id.currency_id.is_zero(counterpart_vals['balance']) or (counterpart_currency and not counterpart_currency.is_zero(counterpart_vals['amount_currency'])): line_vals.append({ @@ -112,7 +112,7 @@ class AccountTransferWizard(models.TransientModel): return { 'journal_id': self.journal_id.id, 'date': self.date, - 'ref': self.destination_account_id.display_name and _("Transfer entry to %s") % self.destination_account_id.display_name or '', + 'ref': self.destination_account_id.display_name and _("Transfer entry to %s", self.destination_account_id.display_name) or '', 'line_ids': [(0, 0, line) for line in line_vals], } diff --git a/addons/auth_signup/models/res_partner.py b/addons/auth_signup/models/res_partner.py index 94e8471e00b..fe68ae5380d 100644 --- a/addons/auth_signup/models/res_partner.py +++ b/addons/auth_signup/models/res_partner.py @@ -143,11 +143,11 @@ class ResPartner(models.Model): partner = self.search([('signup_token', '=', token)], limit=1) if not partner: if raise_exception: - raise exceptions.UserError(_("Signup token '%s' is not valid") % token) + raise exceptions.UserError(_("Signup token '%s' is not valid", token)) return False if check_validity and not partner.signup_valid: if raise_exception: - raise exceptions.UserError(_("Signup token '%s' is no longer valid") % token) + raise exceptions.UserError(_("Signup token '%s' is no longer valid", token)) return False return partner diff --git a/addons/auth_signup/models/res_users.py b/addons/auth_signup/models/res_users.py index c600d969e9d..3aaa43f0f18 100644 --- a/addons/auth_signup/models/res_users.py +++ b/addons/auth_signup/models/res_users.py @@ -123,7 +123,7 @@ class ResUsers(models.Model): invite_partner = user.create_uid.partner_id if invite_partner: # notify invite user that new user is connected - title = _("%s connected") % user.name + title = _("%s connected", user.name) message = _("This is his first connection. Wish him welcome") self.env['bus.bus'].sendone( (self._cr.dbname, 'res.partner', invite_partner.id), @@ -196,7 +196,7 @@ class ResUsers(models.Model): for user in self: if not user.email: - raise UserError(_("Cannot send email: user %s has no email address.") % user.name) + raise UserError(_("Cannot send email: user %s has no email address.", user.name)) # TDE FIXME: make this template technical (qweb) with self.env.cr.savepoint(): force_send = not(self.env.context.get('import_file', False)) diff --git a/addons/base_address_extended/models/res_partner.py b/addons/base_address_extended/models/res_partner.py index 963da5e9b72..7ddb2acc6c6 100644 --- a/addons/base_address_extended/models/res_partner.py +++ b/addons/base_address_extended/models/res_partner.py @@ -35,7 +35,7 @@ class Partner(models.Model): field_name = re_match.group()[2:-2] field_pos = re_match.start() if field_name not in street_fields: - raise UserError(_("Unrecognized field %s in street format.") % field_name) + raise UserError(_("Unrecognized field %s in street format.", field_name)) if not previous_field: # first iteration: add heading chars in street_format if partner[field_name]: @@ -104,7 +104,7 @@ class Partner(models.Model): # value not found: keep looking for the same field pass if field_name not in street_fields: - raise UserError(_("Unrecognized field %s in street format.") % field_name) + raise UserError(_("Unrecognized field %s in street format.", field_name)) previous_pos = re_match.end() # last field value is what remains in street_raw minus trailing chars in street_format diff --git a/addons/base_gengo/wizard/base_gengo_translations.py b/addons/base_gengo/wizard/base_gengo_translations.py index 72d23c5ad2d..7f070c00135 100644 --- a/addons/base_gengo/wizard/base_gengo_translations.py +++ b/addons/base_gengo/wizard/base_gengo_translations.py @@ -91,7 +91,7 @@ class BaseGengoTranslations(models.TransientModel): return (True, gengo) except Exception as e: _logger.exception('Gengo connection failed') - return (False, _("Gengo connection failed with this message:\n``%s``") % e) + return (False, _("Gengo connection failed with this message:\n``%s``", e)) def act_update(self): ''' diff --git a/addons/base_import/models/base_import.py b/addons/base_import/models/base_import.py index 041d5ef2dd1..d126bb4268e 100644 --- a/addons/base_import/models/base_import.py +++ b/addons/base_import/models/base_import.py @@ -297,7 +297,7 @@ class Import(models.TransientModel): _("Invalid cell value at row %(row)s, column %(col)s: %(cell_value)s") % { 'row': rowx, 'col': colx, - 'cell_value': xlrd.error_text_from_code.get(cell.value, _("unknown error code %s") % cell.value) + 'cell_value': xlrd.error_text_from_code.get(cell.value, _("unknown error code %s", cell.value)) } ) else: @@ -856,13 +856,13 @@ class Import(models.TransientModel): response.raise_for_status() if response.headers.get('Content-Length') and int(response.headers['Content-Length']) > maxsize: - raise ValueError(_("File size exceeds configured maximum (%s bytes)") % maxsize) + raise ValueError(_("File size exceeds configured maximum (%s bytes)", maxsize)) content = bytearray() for chunk in response.iter_content(DEFAULT_IMAGE_CHUNK_SIZE): content += chunk if len(content) > maxsize: - raise ValueError(_("File size exceeds configured maximum (%s bytes)") % maxsize) + raise ValueError(_("File size exceeds configured maximum (%s bytes)", maxsize)) image = Image.open(io.BytesIO(content)) w, h = image.size diff --git a/addons/base_import_module/controllers/main.py b/addons/base_import_module/controllers/main.py index d382d360961..1671798c20c 100644 --- a/addons/base_import_module/controllers/main.py +++ b/addons/base_import_module/controllers/main.py @@ -30,7 +30,7 @@ class ImportModule(Controller): @webservice def login_upload(self, login, password, db=None, force='', mod_file=None, **kw): if db and db != request.db: - raise Exception(_("Could not select database '%s'") % db) + raise Exception(_("Could not select database '%s'", db)) uid = request.session.authenticate(request.db, login, password) self.check_user(uid) force = True if force == '1' else False diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 9fff8448ffd..9e2116507a6 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -121,7 +121,7 @@ class IrModule(models.Model): with zipfile.ZipFile(module_file, "r") as z: for zf in z.filelist: if zf.file_size > MAX_FILE_SIZE: - raise UserError(_("File '%s' exceed maximum allowed file size") % zf.filename) + raise UserError(_("File '%s' exceed maximum allowed file size", zf.filename)) with tempfile.TemporaryDirectory() as module_dir: import odoo.modules.module as module diff --git a/addons/base_sparse_field/models/models.py b/addons/base_sparse_field/models/models.py index 1991306a631..179f6fbdc36 100644 --- a/addons/base_sparse_field/models/models.py +++ b/addons/base_sparse_field/models/models.py @@ -32,9 +32,9 @@ class IrModelFields(models.Model): if 'serialization_field_id' in vals or 'name' in vals: for field in self: if 'serialization_field_id' in vals and field.serialization_field_id.id != vals['serialization_field_id']: - raise UserError(_('Changing the storing system for field "%s" is not allowed.') % field.name) + raise UserError(_('Changing the storing system for field "%s" is not allowed.', field.name)) if field.serialization_field_id and (field.name != vals['name']): - raise UserError(_('Renaming sparse field "%s" is not allowed') % field.name) + raise UserError(_('Renaming sparse field "%s" is not allowed', field.name)) return super(IrModelFields, self).write(vals) 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 9ae8c4fc3de..9dae012b6d4 100644 --- a/addons/calendar/models/calendar_recurrence.py +++ b/addons/calendar/models/calendar_recurrence.py @@ -124,12 +124,12 @@ 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 + end = _("for %s events", recurrence.count) elif recurrence.end_type == 'end_date': - end = _("until %s") % recurrence.until + end = _("until %s", recurrence.until) else: end = '' @@ -140,9 +140,9 @@ 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 + on = _("day %s, ", recurrence.day) else: on = '' recurrence.name = every + on + end 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/sale_order.py b/addons/delivery/models/sale_order.py index d303623bb6e..10fd1d9cea4 100644 --- a/addons/delivery/models/sale_order.py +++ b/addons/delivery/models/sale_order.py @@ -101,7 +101,7 @@ class SaleOrder(models.Model): } if carrier.invoice_policy == 'real': values['price_unit'] = 0 - values['name'] += _(' (Estimated Cost: %s )') % self._format_currency_amount(price_unit) + values['name'] += _(' (Estimated Cost: %s )', self._format_currency_amount(price_unit)) else: values['price_unit'] = price_unit if carrier.free_over and self.currency_id.is_zero(price_unit) : 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<br/>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<br/>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/event/models/event_ticket.py b/addons/event/models/event_ticket.py index 3e96eb78d8c..598179d2070 100644 --- a/addons/event/models/event_ticket.py +++ b/addons/event/models/event_ticket.py @@ -51,7 +51,7 @@ class EventTicket(models.Model): def default_get(self, fields): res = super(EventTicket, self).default_get(fields) if 'name' in fields and (not res.get('name') or res['name'] == _('Registration')) and self.env.context.get('default_event_name'): - res['name'] = _('Registration for %s') % self.env.context['default_event_name'] + res['name'] = _('Registration for %s', self.env.context['default_event_name']) return res # description diff --git a/addons/fetchmail/models/fetchmail.py b/addons/fetchmail/models/fetchmail.py index 67dce8c145b..da83677a02c 100644 --- a/addons/fetchmail/models/fetchmail.py +++ b/addons/fetchmail/models/fetchmail.py @@ -126,7 +126,7 @@ odoo_mailgate: "|/path/to/odoo-mailgate.py --host=localhost -u %(uid)d -p PASSWO server.write({'state': 'done'}) except Exception as err: _logger.info("Failed to connect to %s server %s.", server.server_type, server.name, exc_info=True) - raise UserError(_("Connection test failed: %s") % tools.ustr(err)) + raise UserError(_("Connection test failed: %s", tools.ustr(err))) finally: try: if connection: diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py index c424a8c4b28..93efdef0d9b 100644 --- a/addons/gamification/models/challenge.py +++ b/addons/gamification/models/challenge.py @@ -596,7 +596,7 @@ class Challenge(models.Model): def accept_challenge(self): user = self.env.user sudoed = self.sudo() - sudoed.message_post(body=_("%s has joined the challenge") % user.name) + sudoed.message_post(body=_("%s has joined the challenge", user.name)) sudoed.write({'invited_user_ids': [(3, user.id)], 'user_ids': [(4, user.id)]}) return sudoed._generate_goals_from_challenge() @@ -604,7 +604,7 @@ class Challenge(models.Model): """The user discard the suggested challenge""" user = self.env.user sudoed = self.sudo() - sudoed.message_post(body=_("%s has refused the challenge") % user.name) + sudoed.message_post(body=_("%s has refused the challenge", user.name)) return sudoed.write({'invited_user_ids': (3, user.id)}) def _check_challenge_reward(self, force=False): @@ -652,11 +652,15 @@ class Challenge(models.Model): if challenge_ended: # open chatter message - message_body = _("The challenge %s is finished.") % challenge.name + message_body = _("The challenge %s is finished.", challenge.name) if rewarded_users: user_names = rewarded_users.name_get() - message_body += _("<br/>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 += _( + "<br/>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 += _("<br/>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 9a14a1438c3..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): @@ -430,7 +436,7 @@ class Goal(models.Model): if self.computation_mode == 'manually': # open a wizard window to update the value manually action = { - 'name': _("Update %s") % self.definition_id.name, + 'name': _("Update %s", self.definition_id.name), 'id': self.id, 'type': 'ir.actions.act_window', 'views': [[False, 'form']], 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/google_calendar/models/res_users.py b/addons/google_calendar/models/res_users.py index c2d2dfaf9ac..416cc9f8667 100644 --- a/addons/google_calendar/models/res_users.py +++ b/addons/google_calendar/models/res_users.py @@ -74,7 +74,7 @@ class User(models.Model): with self.pool.cursor() as cr: self.env.user.with_env(self.env(cr=cr)).write({'google_calendar_rtoken': False}) error_key = error.response.json().get("error", "nc") - error_msg = _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]") % error_key + error_msg = _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]", error_key) raise UserError(error_msg) def _sync_google_calendar(self, calendar_service: GoogleCalendarService): diff --git a/addons/hr/models/hr_plan.py b/addons/hr/models/hr_plan.py index a9361f531ac..47b4ecc9ef5 100644 --- a/addons/hr/models/hr_plan.py +++ b/addons/hr/models/hr_plan.py @@ -34,24 +34,24 @@ class HrPlanActivityType(models.Model): def get_responsible_id(self, employee): if self.responsible == 'coach': if not employee.coach_id: - raise UserError(_('Coach of employee %s is not set.') % employee.name) + raise UserError(_('Coach of employee %s is not set.', employee.name)) responsible = employee.coach_id.user_id if not responsible: - raise UserError(_('User of coach of employee %s is not set.') % employee.name) + raise UserError(_('User of coach of employee %s is not set.', employee.name)) elif self.responsible == 'manager': if not employee.parent_id: - raise UserError(_('Manager of employee %s is not set.') % employee.name) + raise UserError(_('Manager of employee %s is not set.', employee.name)) responsible = employee.parent_id.user_id if not responsible: - raise UserError(_('User of manager of employee %s is not set.') % employee.name) + raise UserError(_('User of manager of employee %s is not set.', employee.name)) elif self.responsible == 'employee': responsible = employee.user_id if not responsible: - raise UserError(_('User linked to employee %s is required.') % employee.name) + raise UserError(_('User linked to employee %s is required.', employee.name)) elif self.responsible == 'other': responsible = self.responsible_id if not responsible: - raise UserError(_('No specific user given on activity %s.') % self.activity_type_id.name) + raise UserError(_('No specific user given on activity %s.', self.activity_type_id.name)) return responsible diff --git a/addons/hr_contract/models/hr_contract.py b/addons/hr_contract/models/hr_contract.py index 9e79cd89b32..365f0149288 100644 --- a/addons/hr_contract/models/hr_contract.py +++ b/addons/hr_contract/models/hr_contract.py @@ -144,7 +144,7 @@ class Contract(models.Model): for contract in contracts: contract.activity_schedule( 'mail.mail_activity_data_todo', contract.date_end, - _("The contract of %s is about to expire.") % contract.employee_id.name, + _("The contract of %s is about to expire.", contract.employee_id.name), user_id=contract.hr_responsible_id.id or self.env.uid) contracts.write({'kanban_state': 'blocked'}) 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 <a href='/mail/view?%s'>%s</a> 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 <a href='/mail/view?%(url)s'>%(payment_name)s</a> 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_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py index 3623eaebd2c..35357ebd49d 100644 --- a/addons/hr_recruitment/models/hr_recruitment.py +++ b/addons/hr_recruitment/models/hr_recruitment.py @@ -466,7 +466,7 @@ class Applicant(models.Model): if applicant.job_id: applicant.job_id.write({'no_of_hired_employee': applicant.job_id.no_of_hired_employee + 1}) applicant.job_id.message_post( - body=_('New Employee %s Hired') % applicant.partner_name if applicant.partner_name else applicant.name, + body=_('New Employee %s Hired', applicant.partner_name if applicant.partner_name else applicant.name), subtype_xmlid="hr_recruitment.mt_job_applicant_hired") applicant.message_post_with_view( 'hr_recruitment.applicant_hired_template', 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/hw_drivers/iot_handlers/drivers/SerialBaseDriver.py b/addons/hw_drivers/iot_handlers/drivers/SerialBaseDriver.py index 481a11d1309..37a63f57548 100644 --- a/addons/hw_drivers/iot_handlers/drivers/SerialBaseDriver.py +++ b/addons/hw_drivers/iot_handlers/drivers/SerialBaseDriver.py @@ -142,7 +142,7 @@ class SerialDriver(Driver): self._take_measure() time.sleep(self._protocol.newMeasureDelay) except Exception: - msg = _('Error while reading %s') % self.device_name + msg = _('Error while reading %s', self.device_name) _logger.exception(msg) self._status = {'status': self.STATUS_ERROR, 'message_title': msg, 'message_body': traceback.format_exc()} self._push_status() diff --git a/addons/iap/models/iap.py b/addons/iap/models/iap.py index 34911b8a42b..3bd79296faa 100644 --- a/addons/iap/models/iap.py +++ b/addons/iap/models/iap.py @@ -68,7 +68,7 @@ def jsonrpc(url, method='call', params=None, timeout=15): return response.get('result') except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.MissingSchema, requests.exceptions.Timeout, requests.exceptions.HTTPError) as e: raise exceptions.AccessError( - _('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s') % url + _('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s', url) ) #---------------------------------------------------------- diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py index a1110b30c4b..783e576e71f 100644 --- a/addons/im_livechat/models/mail_channel.py +++ b/addons/im_livechat/models/mail_channel.py @@ -207,7 +207,7 @@ class MailChannel(models.Model): mail_body = template._render(render_context, engine='ir.qweb', minimal_qcontext=True) mail_body = self.env['mail.render.mixin']._replace_local_links(mail_body) mail = self.env['mail.mail'].sudo().create({ - 'subject': _('Conversation with %s') % self.livechat_operator_id.name, + 'subject': _('Conversation with %s', self.livechat_operator_id.name), 'email_from': company.catchall_formatted or company.email_formatted, 'author_id': self.env.user.partner_id.id, 'email_to': email, diff --git a/addons/l10n_ar/models/account_move.py b/addons/l10n_ar/models/account_move.py index 178f5644f34..afb6ac9ee56 100644 --- a/addons/l10n_ar/models/account_move.py +++ b/addons/l10n_ar/models/account_move.py @@ -98,7 +98,7 @@ class AccountMove(models.Model): for line in inv.mapped('invoice_line_ids').filtered(lambda x: x.display_type not in ('line_section', 'line_note')): vat_taxes = line.tax_ids.filtered(lambda x: x.tax_group_id.l10n_ar_vat_afip_code) if len(vat_taxes) != 1: - raise UserError(_('There must be one and only one VAT tax per line. Check line "%s"') % line.name) + raise UserError(_('There must be one and only one VAT tax per line. Check line "%s"', line.name)) elif purchase_aliquots == 'zero' and vat_taxes.tax_group_id.l10n_ar_vat_afip_code != '0': raise UserError(_('On invoice id "%s" you must use VAT Not Applicable on every line.') % inv.id) elif purchase_aliquots == 'not_zero' and vat_taxes.tax_group_id.l10n_ar_vat_afip_code == '0': @@ -129,22 +129,20 @@ class AccountMove(models.Model): res_code = rec.partner_id.l10n_ar_afip_responsibility_type_id.code domain = [('company_id', '=', rec.company_id.id), ('l10n_latam_use_documents', '=', True), ('type', '=', 'sale')] journal = self.env['account.journal'] - partner_type = journal_type = False + msg = False if res_code in ['9', '10'] and rec.journal_id.l10n_ar_afip_pos_system not in expo_journals: # if partner is foregin and journal is not of expo, we try to change to expo journal journal = journal.search(domain + [('l10n_ar_afip_pos_system', 'in', expo_journals)], limit=1) - partner_type, journal_type = (_('foreign partner'), _('exportation')) + msg = _('You are trying to create an invoice for foreign partner but you don\'t have an exportation journal') elif res_code not in ['9', '10'] and rec.journal_id.l10n_ar_afip_pos_system in expo_journals: # if partner is NOT foregin and journal is for expo, we try to change to local journal journal = journal.search(domain + [('l10n_ar_afip_pos_system', 'not in', expo_journals)], limit=1) - partner_type, journal_type = (_('domestic partner'), _('domestic market')) + msg = _('You are trying to create an invoice for domestic partner but you don\'t have an domestic market journal') if journal: rec.journal_id = journal.id - elif partner_type and journal_type: + elif msg: # Throw an error to user in order to proper configure the journal for the type of operation action = self.env.ref('account.action_account_journal_form') - msg = _('You are trying to create an invoice for %s but you dont have an %s journal') % ( - partner_type, journal_type) raise RedirectWarning(msg, action.id, _('Go to Journals')) def post(self): diff --git a/addons/l10n_ar/models/res_partner.py b/addons/l10n_ar/models/res_partner.py index 50adb05dc1f..68bb218730b 100644 --- a/addons/l10n_ar/models/res_partner.py +++ b/addons/l10n_ar/models/res_partner.py @@ -103,10 +103,10 @@ class ResPartner(models.Model): try: module.validate(rec.vat) except module.InvalidChecksum: - raise ValidationError(_('The validation digit is not valid for "%s"') % rec.l10n_latam_identification_type_id.name) + raise ValidationError(_('The validation digit is not valid for "%s"', rec.l10n_latam_identification_type_id.name)) except module.InvalidLength: - raise ValidationError(_('Invalid length for "%s"') % rec.l10n_latam_identification_type_id.name) + raise ValidationError(_('Invalid length for "%s"', rec.l10n_latam_identification_type_id.name)) except module.InvalidFormat: - raise ValidationError(_('Only numbers allowed for "%s"') % rec.l10n_latam_identification_type_id.name) + raise ValidationError(_('Only numbers allowed for "%s"', rec.l10n_latam_identification_type_id.name)) except Exception as error: raise ValidationError(repr(error)) diff --git a/addons/l10n_fr_fec/wizard/account_fr_fec.py b/addons/l10n_fr_fec/wizard/account_fr_fec.py index e09b63e7340..0484c10ce1c 100644 --- a/addons/l10n_fr_fec/wizard/account_fr_fec.py +++ b/addons/l10n_fr_fec/wizard/account_fr_fec.py @@ -88,7 +88,7 @@ class AccountFrFec(models.TransientModel): is_dom_tom = company.country_id.code in dom_tom_group.country_ids.mapped('code') if not is_dom_tom and not company.vat: raise Warning( - _("Missing VAT number for company %s") % company.name) + _("Missing VAT number for company %s", company.name)) if not is_dom_tom and company.vat[0:2] != 'FR': raise Warning( _("FEC is for French companies only !")) diff --git a/addons/l10n_fr_pos_cert/models/pos.py b/addons/l10n_fr_pos_cert/models/pos.py index 4e4b6f2d61e..c8b539a5521 100644 --- a/addons/l10n_fr_pos_cert/models/pos.py +++ b/addons/l10n_fr_pos_cert/models/pos.py @@ -28,7 +28,7 @@ class pos_session(models.Model): date_today = datetime.utcnow() session_start = Datetime.from_string(self.start_at) if not date_today - timedelta(hours=24) <= session_start: - raise UserError(_("This session has been opened another day. To comply with the French law, you should close sessions on a daily basis. Please close session %s and open a new one.") % self.name) + raise UserError(_("This session has been opened another day. To comply with the French law, you should close sessions on a daily basis. Please close session %s and open a new one.", self.name)) return True def open_frontend_cb(self): diff --git a/addons/l10n_fr_pos_cert/models/res_company.py b/addons/l10n_fr_pos_cert/models/res_company.py index 5cacda61c1d..c701c6f348e 100644 --- a/addons/l10n_fr_pos_cert/models/res_company.py +++ b/addons/l10n_fr_pos_cert/models/res_company.py @@ -64,14 +64,14 @@ class ResCompany(models.Model): ('l10n_fr_secure_sequence_number', '!=', 0)], order="l10n_fr_secure_sequence_number ASC") if not orders: - msg_alert = (_('There isn\'t any order flagged for data inalterability yet for the company %s. This mechanism only runs for point of sale orders generated after the installation of the module France - Certification CGI 286 I-3 bis. - POS') % self.env.company.name) + msg_alert = (_('There isn\'t any order flagged for data inalterability yet for the company %s. This mechanism only runs for point of sale orders generated after the installation of the module France - Certification CGI 286 I-3 bis. - POS', self.env.company.name)) hash_verified = False previous_hash = u'' start_order_info = [] for order in orders: if order.l10n_fr_hash != order._compute_hash(previous_hash=previous_hash): - msg_alert = (_('Corrupted data on point of sale order with id %s.') % order.id) + msg_alert = (_('Corrupted data on point of sale order with id %s.', order.id)) hash_verified = False break previous_hash = order.l10n_fr_hash diff --git a/addons/l10n_id_efaktur/models/account_move.py b/addons/l10n_id_efaktur/models/account_move.py index 2374be57c1f..e19b6d17367 100644 --- a/addons/l10n_id_efaktur/models/account_move.py +++ b/addons/l10n_id_efaktur/models/account_move.py @@ -102,7 +102,7 @@ class AccountMove(models.Model): """Reset E-Faktur, so it can be use for other invoice.""" for move in self: if move.l10n_id_attachment_id: - raise UserError(_('You have already generated the tax report for this document: %s') % move.name) + raise UserError(_('You have already generated the tax report for this document: %s', move.name)) self.env['l10n_id_efaktur.efaktur.range'].push_number(move.company_id.id, move.l10n_id_tax_number[3:]) move.message_post( body='e-Faktur Reset: %s ' % (move.l10n_id_tax_number), diff --git a/addons/l10n_it_edi/models/account_edi_format.py b/addons/l10n_it_edi/models/account_edi_format.py index ab2d7230407..6d52e5cf08e 100644 --- a/addons/l10n_it_edi/models/account_edi_format.py +++ b/addons/l10n_it_edi/models/account_edi_format.py @@ -83,13 +83,13 @@ class AccountEdiFormat(models.Model): else: company = self.env.company if elements: - _logger.info(_('Company not found with codice fiscale: %s. The company\'s user is set by default.') % elements[0].text) + _logger.info(_('Company not found with codice fiscale: %s. The company\'s user is set by default.', elements[0].text)) else: _logger.info(_('Company not found. The company\'s user is set by default.')) if not self.env.is_superuser(): if self.env.company != company: - raise UserError(_("You can only import invoice concern your current company: %s") % self.env.company.display_name) + raise UserError(_("You can only import invoice concern your current company: %s", self.env.company.display_name)) # Refund type. # TD01 == invoice diff --git a/addons/l10n_it_edi/models/account_invoice.py b/addons/l10n_it_edi/models/account_invoice.py index 62e40420247..3e7c910e7b0 100644 --- a/addons/l10n_it_edi/models/account_invoice.py +++ b/addons/l10n_it_edi/models/account_invoice.py @@ -168,7 +168,7 @@ class AccountMove(models.Model): } data = b"<?xml version='1.0' encoding='UTF-8'?>" + invoice._export_as_xml() - description = _('Italian invoice: %s') % invoice.move_type + description = _('Italian invoice: %s', invoice.move_type) invoice.edi_document_ids = self.env['ir.attachment'].create({ 'name': report_name, 'res_id': invoice.id, diff --git a/addons/l10n_latam_invoice_document/models/account_move.py b/addons/l10n_latam_invoice_document/models/account_move.py index 7472a1f79d5..23705dcae76 100644 --- a/addons/l10n_latam_invoice_document/models/account_move.py +++ b/addons/l10n_latam_invoice_document/models/account_move.py @@ -156,7 +156,7 @@ class AccountMove(models.Model): invoice_type = rec.move_type if internal_type in ['debit_note', 'invoice'] and invoice_type in ['out_refund', 'in_refund'] and \ rec.l10n_latam_document_type_id.code != '99': - raise ValidationError(_('You can not use a %s document type with a refund invoice') % internal_type) + raise ValidationError(_('You can not use a %s document type with a refund invoice', internal_type)) elif internal_type == 'credit_note' and invoice_type in ['out_invoice', 'in_invoice']: raise ValidationError(_('You can not use a %s document type with a invoice') % (internal_type)) diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py index 8f3b1694098..46d14831dd5 100644 --- a/addons/mail/controllers/main.py +++ b/addons/mail/controllers/main.py @@ -37,7 +37,7 @@ class MailController(http.Controller): def _check_token_and_record_or_redirect(cls, model, res_id, token): comparison = cls._check_token(token) if not comparison: - _logger.warning(_('Invalid token in route %s') % request.httprequest.url) + _logger.warning(_('Invalid token in route %s', request.httprequest.url)) return comparison, None, cls._redirect_to_messaging() try: record = request.env[model].browse(res_id).exists() 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_blacklist.py b/addons/mail/models/mail_blacklist.py index cbe5cc6693b..059c6e9e629 100644 --- a/addons/mail/models/mail_blacklist.py +++ b/addons/mail/models/mail_blacklist.py @@ -28,7 +28,7 @@ class MailBlackList(models.Model): for value in values: email = tools.email_normalize(value.get('email')) if not email: - raise UserError(_('Invalid email address %r') % value['email']) + raise UserError(_('Invalid email address %r', value['email'])) if email in all_emails: continue all_emails.append(email) diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py index 1d7c35fabc9..23f63f4dad3 100644 --- a/addons/mail/models/mail_channel.py +++ b/addons/mail/models/mail_channel.py @@ -427,7 +427,7 @@ class Channel(models.Model): 'email_from': company.catchall_formatted or company.email_formatted, 'author_id': self.env.user.partner_id.id, 'body_html': view._render({'channel': self, 'partner': partner}, engine='ir.qweb', minimal_qcontext=True), - 'subject': _("Guidelines of channel %s") % self.name, + 'subject': _("Guidelines of channel %s", self.name), 'recipient_ids': [(4, partner.id)] } mail = self.env['mail.mail'].sudo().create(create_values) @@ -976,7 +976,7 @@ class Channel(models.Model): def _execute_command_help(self, **kwargs): partner = self.env.user.partner_id if self.channel_type == 'channel': - msg = _("You are in channel <b>#%s</b>.") % self.name + msg = _("You are in channel <b>#%s</b>.", self.name) if self.public == 'private': msg += _(" This channel is private. People must be invited to join it.") else: @@ -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_render_mixin.py b/addons/mail/models/mail_render_mixin.py index ddd32659a03..79b66e55f8b 100644 --- a/addons/mail/models/mail_render_mixin.py +++ b/addons/mail/models/mail_render_mixin.py @@ -316,7 +316,7 @@ class MailRenderMixin(models.AbstractModel): render_result = template.render(variables) except Exception as e: _logger.info("Failed to render template : %s" % e, exc_info=True) - raise UserError(_("Failed to render template : %s") % e) + raise UserError(_("Failed to render template : %s", e)) if render_result == u"False": render_result = u"" results[record.id] = render_result diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index f8f90aea5fd..92783104b65 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -74,7 +74,7 @@ class MailTemplate(models.Model): @api.returns('self', lambda value: value.id) def copy(self, default=None): default = dict(default or {}, - name=_("%s (copy)") % self.name) + name=_("%s (copy)", self.name)) return super(MailTemplate, self).copy(default=default) def unlink_action(self): @@ -88,7 +88,7 @@ class MailTemplate(models.Model): view = self.env.ref('mail.email_compose_message_wizard_form') for template in self: - button_name = _('Send Mail (%s)') % template.name + button_name = _('Send Mail (%s)', template.name) action = ActWindow.create({ 'name': button_name, 'type': 'ir.actions.act_window', @@ -200,7 +200,7 @@ class MailTemplate(models.Model): else: res = report._render([res_id]) if not res: - raise UserError(_('Unsupported report type %s found.') % report.report_type) + raise UserError(_('Unsupported report type %s found.', report.report_type)) result, format = res # TODO in trunk, change return format to binary to match message_post expected format diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index ee16931f25e..dcadca5b281 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -544,7 +544,7 @@ class MailThread(models.AbstractModel): """ self.ensure_one() doc_name = self.env['ir.model']._get(self._name).name - return _('%s created') % doc_name + return _('%s created', doc_name) def _track_subtype(self, init_values): """ Give the subtypes triggered by the changes on the record according @@ -671,7 +671,7 @@ class MailThread(models.AbstractModel): def _routing_warn(self, error_message, message_id, route, raise_exception=True): """ Tools method used in _routing_check_route: whether to log a warning or raise an error """ - short_message = _("Mailbox unavailable - %s") % error_message + short_message = _("Mailbox unavailable - %s", error_message) full_message = ('Routing mail with Message-Id %s: route %s: %s' % (message_id, route, error_message)) _logger.info(full_message) @@ -791,22 +791,27 @@ class MailThread(models.AbstractModel): self._routing_warn(_('target model unspecified'), message_id, route, raise_exception) return () elif model not in self.env: - self._routing_warn(_('unknown target model %s') % model, message_id, route, raise_exception) + self._routing_warn(_('unknown target model %s', model), message_id, route, raise_exception) return () record_set = self.env[model].browse(thread_id) if thread_id else self.env[model] # 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) + self._routing_warn(_('reply to model %s that does not accept document update, fall back on document creation', model), message_id, route, False) thread_id = None # New Document: check model accepts the mailgateway if not thread_id and model and not hasattr(record_set, 'message_new'): - self._routing_warn(_('model %s does not accept document creation') % model, message_id, route, raise_exception) + self._routing_warn(_('model %s does not accept document creation', model), message_id, route, raise_exception) return () # Update message author. We do it now because we need it for aliases (contact settings) @@ -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 @@ -2595,7 +2605,7 @@ class MailThread(models.AbstractModel): access_link = self._notify_get_action_link('view') if model_name: - view_title = _('View %s') % model_name + view_title = _('View %s', model_name) else: view_title = _('View') @@ -2859,7 +2869,7 @@ class MailThread(models.AbstractModel): assignation_msg = view._render(values, engine='ir.qweb', minimal_qcontext=True) assignation_msg = self.env['mail.render.mixin']._replace_local_links(assignation_msg) record.message_notify( - subject=_('You have been assigned to %s') % record.display_name, + subject=_('You have been assigned to %s', record.display_name), body=assignation_msg, partner_ids=partner_ids, record_name=record.display_name, diff --git a/addons/mail/models/mail_thread_blacklist.py b/addons/mail/models/mail_thread_blacklist.py index 00f6bb95518..f17302f360e 100644 --- a/addons/mail/models/mail_thread_blacklist.py +++ b/addons/mail/models/mail_thread_blacklist.py @@ -93,9 +93,9 @@ class MailBlackListMixin(models.AbstractModel): def _assert_primary_email(self): if not hasattr(self, "_primary_email") or not isinstance(self._primary_email, str): - raise UserError(_('Invalid primary email field on model %s') % self._name) + raise UserError(_('Invalid primary email field on model %s', self._name)) if self._primary_email not in self._fields or self._fields[self._primary_email].type != 'char': - raise UserError(_('Invalid primary email field on model %s') % self._name) + raise UserError(_('Invalid primary email field on model %s', self._name)) def _message_receive_bounce(self, email, partner): """ Override of mail.thread generic method. Purpose is to increment the 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 == '<br>': # when deleting the message, cleditor keeps a <br> 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/maintenance/models/maintenance.py b/addons/maintenance/models/maintenance.py index 49d27a2b182..8224cc52d93 100644 --- a/addons/maintenance/models/maintenance.py +++ b/addons/maintenance/models/maintenance.py @@ -223,7 +223,7 @@ class MaintenanceEquipment(models.Model): def _create_new_request(self, date): self.ensure_one() self.env['maintenance.request'].create({ - 'name': _('Preventive Maintenance - %s') % self.name, + 'name': _('Preventive Maintenance - %s', self.name), 'request_date': date, 'schedule_date': date, 'category_id': self.category_id.id, diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 31c2acc8dc3..7146c1cc77d 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -259,7 +259,7 @@ class MassMailing(models.Model): def copy(self, default=None): self.ensure_one() default = dict(default or {}, - name=_('%s (copy)') % self.name, + name=_('%s (copy)', self.name), contact_list_ids=self.contact_list_ids.ids) return super(MassMailing, self).copy(default=default) @@ -469,7 +469,7 @@ class MassMailing(models.Model): elif 'email' in target._fields: mail_field = 'email' else: - raise UserError(_("Unsupported mass mailing model %s") % self.mailing_model_id.name) + raise UserError(_("Unsupported mass mailing model %s", self.mailing_model_id.name)) if self.unique_ab_testing: query +=""" diff --git a/addons/mass_mailing_sms/models/mailing_mailing.py b/addons/mass_mailing_sms/models/mailing_mailing.py index 3893f11a091..cd0e6060f6f 100644 --- a/addons/mass_mailing_sms/models/mailing_mailing.py +++ b/addons/mass_mailing_sms/models/mailing_mailing.py @@ -171,7 +171,7 @@ class Mailing(models.Model): if 'phone' in target._fields: phone_fields.append('phone') if not phone_fields: - raise UserError(_("Unsupported %s for mass SMS") % self.mailing_model_id.name) + raise UserError(_("Unsupported %s for mass SMS", self.mailing_model_id.name)) query = """ SELECT %(select_query)s diff --git a/addons/mass_mailing_sms/wizard/mailing_sms_test.py b/addons/mass_mailing_sms/wizard/mailing_sms_test.py index c9fe95ec8c5..198304dc2c6 100644 --- a/addons/mass_mailing_sms/wizard/mailing_sms_test.py +++ b/addons/mass_mailing_sms/wizard/mailing_sms_test.py @@ -23,7 +23,7 @@ class MassSMSTest(models.TransientModel): sanitized_numbers = [info['sanitized'] for info in sanitize_res.values() if info['sanitized']] invalid_numbers = [number for number, info in sanitize_res.items() if info['code']] if invalid_numbers: - raise exceptions.UserError(_('Following numbers are not correctly encoded: %s, example : "+32 495 85 85 77, +33 545 55 55 55"') % repr(invalid_numbers)) + raise exceptions.UserError(_('Following numbers are not correctly encoded: %s, example : "+32 495 85 85 77, +33 545 55 55 55"', repr(invalid_numbers))) self.env['sms.api']._send_sms_batch([{ 'res_id': 0, 'number': number, diff --git a/addons/mass_mailing_sms/wizard/sms_composer.py b/addons/mass_mailing_sms/wizard/sms_composer.py index b3e50234036..b8d13b7f056 100644 --- a/addons/mass_mailing_sms/wizard/sms_composer.py +++ b/addons/mass_mailing_sms/wizard/sms_composer.py @@ -45,7 +45,7 @@ class SMSComposer(models.TransientModel): trace_values['ignored'] = fields.Datetime.now() else: if self.mass_sms_allow_unsubscribe: - sms_values['body'] = '%s\n%s' % (sms_values['body'] or '', _('STOP SMS : %s') % self._get_unsubscribe_url(record.id, trace_code, sms_values['number'])) + sms_values['body'] = '%s\n%s' % (sms_values['body'] or '', _('STOP SMS : %s', self._get_unsubscribe_url(record.id, trace_code, sms_values['number']))) return trace_values def _get_blacklist_record_ids(self, records, recipients_info): diff --git a/addons/mrp/models/mrp_bom.py b/addons/mrp/models/mrp_bom.py index 6f0603c028f..7a154b16d0f 100644 --- a/addons/mrp/models/mrp_bom.py +++ b/addons/mrp/models/mrp_bom.py @@ -90,16 +90,18 @@ class MrpBom(models.Model): for bom in self: for bom_line in bom.bom_line_ids: if bom.product_id and bom_line.product_id == bom.product_id: - raise ValidationError(_("BoM line product %s should not be the same as BoM product.") % bom.display_name) + raise ValidationError(_("BoM line product %s should not be the same as BoM product.", bom.display_name)) if bom.product_id and bom_line.bom_product_template_attribute_value_ids: raise ValidationError(_("BoM cannot concern product %s and have a line with attributes (%s) at the same time.") % (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 7a58b069198..491c775f6c3 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -718,7 +718,7 @@ class MrpProduction(models.Model): not_cancel = self.filtered(lambda m: m.state != 'cancel') if not_cancel: productions_name = ', '.join([prod.display_name for prod in not_cancel]) - raise UserError(_('%s cannot be deleted. Try to cancel them before.') % productions_name) + raise UserError(_('%s cannot be deleted. Try to cancel them before.', productions_name)) workorders_to_delete = self.workorder_ids.filtered(lambda wo: wo.state != 'done') if workorders_to_delete: @@ -794,7 +794,7 @@ class MrpProduction(models.Model): moves = [] for production in self: if production.product_id in production.bom_id.byproduct_ids.mapped('product_id'): - raise UserError(_("You cannot have %s as the finished product and in the Byproducts") % self.product_id.name) + raise UserError(_("You cannot have %s as the finished product and in the Byproducts", self.product_id.name)) moves = [production._get_move_finished_values(production.product_id.id, production.product_qty, production.product_uom_id.id)] for byproduct in production.bom_id.byproduct_ids: product_uom_factor = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id) @@ -1554,7 +1554,7 @@ class MrpProduction(models.Model): def button_unbuild(self): self.ensure_one() return { - 'name': _('Unbuild: %s') % self.product_id.display_name, + 'name': _('Unbuild: %s', self.product_id.display_name), 'view_mode': 'form', 'res_model': 'mrp.unbuild', 'view_id': self.env.ref('mrp.mrp_unbuild_form_view_simplified').id, @@ -1585,7 +1585,7 @@ class MrpProduction(models.Model): ('state', '=', 'done') ]) if sml: - raise UserError(_('This serial number for product %s has already been produced') % self.product_id.name) + raise UserError(_('This serial number for product %s has already been produced', self.product_id.name)) for move in self.move_finished_ids: if move.has_tracking != 'serial' or move.product_id == self.product_id: @@ -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 0c1407c7a44..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) @@ -751,7 +751,7 @@ class MrpWorkorder(models.Model): qty_done += line.product_uom_id._compute_quantity(line.qty_done, move.product_uom) rounding = move.product_uom_id.rounding if float_compare(qty_done, move.product_uom_qty, precision_rounding=rounding) != 0: - raise UserError(_('You should consume the quantity of %s defined in the BoM. If you want to consume more or less components, change the consumption setting on the BoM.') % move.product_id.name) + raise UserError(_('You should consume the quantity of %s defined in the BoM. If you want to consume more or less components, change the consumption setting on the BoM.', move.product_id.name)) def _check_sn_uniqueness(self): """ Alert the user if the serial number as already been produced """ @@ -763,4 +763,4 @@ class MrpWorkorder(models.Model): ('state', '=', 'done') ]) if sml: - raise UserError(_('This serial number for product %s has already been produced') % self.product_id.name) + raise UserError(_('This serial number for product %s has already been produced', self.product_id.name)) 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_sips/models/payment.py b/addons/payment_sips/models/payment.py index bc44b5c68b0..49dbd5b4dbd 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -159,7 +159,7 @@ class TxSips(models.Model): payment_tx = self.search([('reference', '=', reference)]) if not payment_tx or len(payment_tx) > 1: - error_msg = _('Sips: received data for reference %s') % reference + error_msg = _('Sips: received data for reference %s', reference) if not payment_tx: error_msg += _('; no order found') else: diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index d13f80bec46..936e8d1c601 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -82,7 +82,7 @@ class PaymentAcquirerStripe(models.Model): except HTTPError: _logger.error(resp.text) stripe_error = resp.json().get('error', {}).get('message', '') - error_msg = " " + (_("Stripe gave us the following info about the problem: '%s'") % stripe_error) + error_msg = " " + (_("Stripe gave us the following info about the problem: '%s'", stripe_error)) raise ValidationError(error_msg) return resp.json() @@ -249,11 +249,11 @@ class PaymentTransactionStripe(models.Model): tx = self.search([('reference', '=', reference)]) if not tx: - error_msg = (_('Stripe: no order found for reference %s') % reference) + error_msg = _('Stripe: no order found for reference %s', reference) _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/models/mail_thread_phone.py b/addons/phone_validation/models/mail_thread_phone.py index 9b608c8b601..d560de1911a 100644 --- a/addons/phone_validation/models/mail_thread_phone.py +++ b/addons/phone_validation/models/mail_thread_phone.py @@ -106,9 +106,9 @@ class PhoneMixin(models.AbstractModel): def _assert_phone_field(self): if not hasattr(self, "_phone_get_number_fields"): - raise UserError(_('Invalid primary phone field on model %s') % self._name) + raise UserError(_('Invalid primary phone field on model %s', self._name)) if not any(fname in self and self._fields[fname].type == 'char' for fname in self._phone_get_number_fields()): - raise UserError(_('Invalid primary phone field on model %s') % self._name) + raise UserError(_('Invalid primary phone field on model %s', self._name)) def _phone_get_number_fields(self): """ This method returns the fields to use to find the number to use to diff --git a/addons/phone_validation/tools/phone_validation.py b/addons/phone_validation/tools/phone_validation.py index 97eb7bac05c..ac96c82a87a 100644 --- a/addons/phone_validation/tools/phone_validation.py +++ b/addons/phone_validation/tools/phone_validation.py @@ -17,12 +17,12 @@ 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) + raise UserError(_('Impossible number %s: probably invalid number of digits.', number)) if not phonenumbers.is_valid_number(phone_nbr): - raise UserError(_('Invalid number %s: probably incorrect prefix.') % number) + raise UserError(_('Invalid number %s: probably incorrect prefix.', number)) return phone_nbr diff --git a/addons/point_of_sale/models/pos_config.py b/addons/point_of_sale/models/pos_config.py index 235c97bb806..d63bced8eb9 100644 --- a/addons/point_of_sale/models/pos_config.py +++ b/addons/point_of_sale/models/pos_config.py @@ -459,7 +459,7 @@ class PosConfig(models.Model): def create(self, values): IrSequence = self.env['ir.sequence'].sudo() val = { - 'name': _('POS Order %s') % values['name'], + 'name': _('POS Order %s', values['name']), 'padding': 4, 'prefix': "%s/" % values['name'], 'code': "pos.order", @@ -468,7 +468,7 @@ class PosConfig(models.Model): # force sequence_id field to new pos.order sequence values['sequence_id'] = IrSequence.create(val).id - val.update(name=_('POS order line %s') % values['name'], code='pos.order.line') + val.update(name=_('POS order line %s', values['name']), code='pos.order.line') values['sequence_line_id'] = IrSequence.create(val).id pos_config = super(PosConfig, self).create(values) pos_config.sudo()._check_modules_to_install() diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 085ba223a04..ccb05ff7d42 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -363,7 +363,7 @@ class PosOrder(models.Model): total = float_round(self.amount_total, precision_rounding=self.config_id.rounding_method.rounding, rounding_method=self.config_id.rounding_method.rounding_method) if not float_is_zero(total - self.amount_paid, precision_rounding=self.currency_id.rounding): - raise UserError(_("Order %s is not fully paid.") % self.name) + raise UserError(_("Order %s is not fully paid.", self.name)) self.write({'state': 'paid'}) @@ -479,7 +479,7 @@ class PosOrder(models.Model): # order. It can be the same session, or if it has been closed the new one that has been opened. current_session = order.session_id.config_id.current_session_id if not current_session: - raise UserError(_('To return product(s), you need to open a session in the POS %s') % order.session_id.config_id.display_name) + raise UserError(_('To return product(s), you need to open a session in the POS %s', order.session_id.config_id.display_name)) refund_order = order.copy({ 'name': order.name + _(' REFUND'), 'session_id': current_session.id, @@ -533,7 +533,7 @@ class PosOrder(models.Model): 'mimetype': 'image/jpeg', }) mail_values = { - 'subject': _('Receipt %s') % name, + 'subject': _('Receipt %s', name), 'body_html': message, 'author_id': self.env.user.partner_id.id, 'email_from': self.env.company.email or self.env.user.email_formatted, 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/controllers/mail.py b/addons/portal/controllers/mail.py index c64859c1ad6..612191b705e 100644 --- a/addons/portal/controllers/mail.py +++ b/addons/portal/controllers/mail.py @@ -111,7 +111,7 @@ class PortalChatter(http.Controller): try: CustomerPortal._document_check_access(self, 'ir.attachment', attachment_id, access_token) except (AccessError, MissingError): - raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.") % attachment_id) + raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.", attachment_id)) @http.route(['/mail/chatter_post'], type='http', methods=['POST'], auth='public', website=True) def portal_chatter_post(self, res_model, res_id, message, redirect=None, attachment_ids='', attachment_tokens='', **kw): diff --git a/addons/portal/controllers/portal.py b/addons/portal/controllers/portal.py index 6bec53e7f74..6034a933e77 100644 --- a/addons/portal/controllers/portal.py +++ b/addons/portal/controllers/portal.py @@ -273,10 +273,10 @@ class CustomerPortal(Controller): raise UserError(_("The attachment does not exist or you do not have the rights to access it.")) if attachment_sudo.res_model != 'mail.compose.message' or attachment_sudo.res_id != 0: - raise UserError(_("The attachment %s cannot be removed because it is not in a pending state.") % attachment_sudo.name) + raise UserError(_("The attachment %s cannot be removed because it is not in a pending state.", attachment_sudo.name)) if attachment_sudo.env['mail.message'].search([('attachment_ids', 'in', attachment_sudo.ids)]): - raise UserError(_("The attachment %s cannot be removed because it is linked to a message.") % attachment_sudo.name) + raise UserError(_("The attachment %s cannot be removed because it is linked to a message.", attachment_sudo.name)) return attachment_sudo.unlink() @@ -364,12 +364,12 @@ class CustomerPortal(Controller): def _show_report(self, model, report_type, report_ref, download=False): if report_type not in ('html', 'pdf', 'text'): - raise UserError(_("Invalid report type: %s") % report_type) + raise UserError(_("Invalid report type: %s", report_type)) report_sudo = request.env.ref(report_ref).sudo() if not isinstance(report_sudo, type(request.env['ir.actions.report'])): - raise UserError(_("%s is not the reference of a report") % report_ref) + raise UserError(_("%s is not the reference of a report", report_ref)) method_name = '_render_qweb_%s' % (report_type) report = getattr(report_sudo, method_name)([model.id], data={'report_type': report_type})[0] 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/pos_adyen/models/pos_config.py b/addons/pos_adyen/models/pos_config.py index b0d9176c628..7578f844ed7 100644 --- a/addons/pos_adyen/models/pos_config.py +++ b/addons/pos_adyen/models/pos_config.py @@ -17,7 +17,7 @@ class PosConfig(models.Model): def _check_adyen_ask_customer_for_tip(self): for config in self: if config.adyen_ask_customer_for_tip and (not config.tip_product_id or not config.iface_tipproduct): - raise ValidationError(_("Please configure a tip product for POS %s to support tipping with Adyen.") % config.name) + raise ValidationError(_("Please configure a tip product for POS %s to support tipping with Adyen.", config.name)) @api.onchange('adyen_ask_customer_for_tip') def _onchange_adyen_ask_customer_for_tip(self): diff --git a/addons/pos_mercury/models/pos_mercury_transaction.py b/addons/pos_mercury/models/pos_mercury_transaction.py index 44ca5b89b23..c30d0c64514 100644 --- a/addons/pos_mercury/models/pos_mercury_transaction.py +++ b/addons/pos_mercury/models/pos_mercury_transaction.py @@ -19,7 +19,7 @@ class MercuryTransaction(models.Model): def _get_pos_session(self): pos_session = self.env['pos.session'].search([('state', '=', 'opened'), ('user_id', '=', self.env.uid)], limit=1) if not pos_session: - raise UserError(_("No opened point of sale session for user %s found.") % self.env.user.name) + raise UserError(_("No opened point of sale session for user %s found.", self.env.user.name)) pos_session.login() diff --git a/addons/product/models/product_pricelist.py b/addons/product/models/product_pricelist.py index 880766ce545..d1ef0ec714c 100644 --- a/addons/product/models/product_pricelist.py +++ b/addons/product/models/product_pricelist.py @@ -519,9 +519,9 @@ class PricelistItem(models.Model): ), ) elif item.compute_price == 'percentage': - item.price = _("%s %% discount") % (item.percent_price) + 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/product/models/product_template.py b/addons/product/models/product_template.py index cb9cd14ee32..8da67700c14 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -436,7 +436,7 @@ class ProductTemplate(models.Model): if default is None: default = {} if 'name' not in default: - default['name'] = _("%s (copy)") % self.name + default['name'] = _("%s (copy)", self.name) return super(ProductTemplate, self).copy(default=default) def name_get(self): diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 70c5f58f4dc..dee727dfcfb 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -639,7 +639,7 @@ class Task(models.Model): portal_users = task.allowed_user_ids.filtered('share') if portal_users: user_names = ', '.join(portal_users[:10].mapped('name')) - raise ValidationError(_("The project visibility setting doesn't allow portal users to see the project's tasks. (%s)") % user_names) + raise ValidationError(_("The project visibility setting doesn't allow portal users to see the project's tasks. (%s)", user_names)) def _compute_attachment_ids(self): for task in self: @@ -752,7 +752,7 @@ class Task(models.Model): if default is None: default = {} if not default.get('name'): - default['name'] = _("%s (copy)") % self.name + default['name'] = _("%s (copy)", self.name) return super(Task, self).copy(default) @api.constrains('parent_id') diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index e2d254d56fe..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() @@ -284,7 +289,7 @@ class PurchaseOrder(models.Model): # Block if partner only has warning but parent company is blocked if partner.purchase_warn != 'block' and partner.parent_id and partner.parent_id.purchase_warn == 'block': partner = partner.parent_id - title = _("Warning for %s") % partner.name + title = _("Warning for %s", partner.name) message = partner.purchase_warn_msg warning = { 'title': title, @@ -721,9 +726,14 @@ class PurchaseOrder(models.Model): def _compose_note(self, updated_dates): """Helper method for creating log note when user update scheduled date on portal website.""" - note = _('<p> %s modified receipt dates for the following products:</p>') % self.partner_id.name + note = _('<p> %s modified receipt dates for the following products:</p>', self.partner_id.name) for line, date in updated_dates: - note += _('<p> - %s from %s to %s </p>') % (line.product_id.display_name, line.date_planned, date) + note += _( + '<p> - %(product_name)s from %(date_start)s to %(date_end)s </p>', + product_name=line.product_id.display_name, + date_start=line.date_planned, + date_end=date + ) return note @@ -980,7 +990,7 @@ class PurchaseOrderLine(models.Model): product_info = self.product_id if product_info.purchase_line_warn != 'no-message': - title = _("Warning for %s") % product_info.name + title = _("Warning for %s", product_info.name) message = product_info.purchase_line_warn_msg warning['title'] = title warning['message'] = message diff --git a/addons/purchase_requisition/models/purchase_requisition.py b/addons/purchase_requisition/models/purchase_requisition.py index 0ee207103c4..0a4e042a6e4 100644 --- a/addons/purchase_requisition/models/purchase_requisition.py +++ b/addons/purchase_requisition/models/purchase_requisition.py @@ -89,7 +89,7 @@ class PurchaseRequisition(models.Model): ('company_id', '=', self.company_id.id), ]) if any(requisitions): - title = _("Warning for %s") % self.vendor_id.name + title = _("Warning for %s", self.vendor_id.name) message = _("There is already an open blanket order for this supplier. We suggest you to use to complete this open blanket order instead of creating a new one.") warning = { 'title': title, @@ -115,7 +115,7 @@ class PurchaseRequisition(models.Model): def action_in_progress(self): self.ensure_one() if not all(obj.line_ids for obj in self): - raise UserError(_("You cannot confirm agreement '%s' because there is no product line.") % self.name) + raise UserError(_("You cannot confirm agreement '%s' because there is no product line.", self.name)) if self.type_id.quantity_copy == 'none' and self.vendor_id: for requisition_line in self.line_ids: if requisition_line.price_unit <= 0.0: diff --git a/addons/purchase_stock/models/purchase.py b/addons/purchase_stock/models/purchase.py index 67fa411ed57..7d4e80430f3 100644 --- a/addons/purchase_stock/models/purchase.py +++ b/addons/purchase_stock/models/purchase.py @@ -218,7 +218,7 @@ class PurchaseOrder(models.Model): 'partner_id': self.partner_id.id }) if not self.partner_id.property_stock_supplier.id: - raise UserError(_("You must set a Vendor Location for this partner %s") % self.partner_id.name) + raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name)) return { 'picking_type_id': self.picking_type_id.id, 'partner_id': self.partner_id.id, @@ -258,9 +258,9 @@ class PurchaseOrder(models.Model): validated_picking = self.picking_ids.filtered(lambda p: p.state == 'done') if validated_picking: - note += _("<p>Those dates couldn’t be modified accordingly on the receipt %s which had already been validated.</p>") % validated_picking.name + note += _("<p>Those dates couldn’t be modified accordingly on the receipt %s which had already been validated.</p>", validated_picking.name) else: - note += _("<p>Those dates have been updated accordingly on the receipt %s.</p>") % self.picking_ids[0].name + note += _("<p>Those dates have been updated accordingly on the receipt %s.</p>", self.picking_ids[0].name) for line, date in updated_dates: date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S') line._update_date_planned(date) diff --git a/addons/repair/models/repair.py b/addons/repair/models/repair.py index 7d111329763..36c5ff1ca4e 100644 --- a/addons/repair/models/repair.py +++ b/addons/repair/models/repair.py @@ -360,7 +360,7 @@ class Repair(models.Model): account = operation.product_id.product_tmpl_id._get_product_accounts()['income'] if not account: - raise UserError(_('No account defined for product "%s".') % operation.product_id.name) + raise UserError(_('No account defined for product "%s".', operation.product_id.name)) invoice_line_vals = { 'name': name, @@ -402,7 +402,7 @@ class Repair(models.Model): account = fee.product_id.product_tmpl_id._get_product_accounts()['income'] if not account: - raise UserError(_('No account defined for product "%s".') % fee.product_id.name) + raise UserError(_('No account defined for product "%s".', fee.product_id.name)) invoice_line_vals = { 'name': name, diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py index 7c497a61856..e590bdc0643 100644 --- a/addons/resource/models/resource.py +++ b/addons/resource/models/resource.py @@ -160,7 +160,7 @@ class ResourceCalendar(models.Model): def default_get(self, fields): res = super(ResourceCalendar, self).default_get(fields) if not res.get('name') and res.get('company_id'): - res['name'] = _('Working Hours of %s') % self.env['res.company'].browse(res['company_id']).name + res['name'] = _('Working Hours of %s', self.env['res.company'].browse(res['company_id']).name) if 'attendance_ids' in fields and not res.get('attendance_ids'): res['attendance_ids'] = [ (0, 0, {'name': _('Monday Morning'), 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}), diff --git a/addons/sale/controllers/portal.py b/addons/sale/controllers/portal.py index 40e854af7c5..868235fde64 100644 --- a/addons/sale/controllers/portal.py +++ b/addons/sale/controllers/portal.py @@ -160,7 +160,7 @@ class CustomerPortal(CustomerPortal): session_obj_date = request.session.get('view_quote_%s' % order_sudo.id) if session_obj_date != now and request.env.user.share and access_token: request.session['view_quote_%s' % order_sudo.id] = now - body = _('Quotation viewed by customer %s') % order_sudo.partner_id.name + body = _('Quotation viewed by customer %s', order_sudo.partner_id.name) _message_post_helper( "sale.order", order_sudo.id, diff --git a/addons/sale/models/account_invoice.py b/addons/sale/models/account_invoice.py index 5a9667330ea..c02f918e333 100644 --- a/addons/sale/models/account_invoice.py +++ b/addons/sale/models/account_invoice.py @@ -96,7 +96,7 @@ class AccountMove(models.Model): for sale_line in line.sale_line_ids: todo.add((sale_line.order_id, invoice.name)) for (order, name) in todo: - order.message_post(body=_("Invoice %s paid") % name) + order.message_post(body=_("Invoice %s paid", name)) return res def _get_invoice_delivery_partner_id(self): diff --git a/addons/sale/models/payment.py b/addons/sale/models/payment.py index 30d63d02cec..4904f51e396 100644 --- a/addons/sale/models/payment.py +++ b/addons/sale/models/payment.py @@ -83,7 +83,7 @@ class PaymentTransaction(models.Model): order.amount_total, self.amount, ) order.message_post( - subject=_("Amount Mismatch (%s)") % self.acquirer_id.provider, + subject=_("Amount Mismatch (%s)", self.acquirer_id.provider), body=_("The order was not confirmed despite response from the acquirer (%s): order total is %r but acquirer replied with %r.") % ( self.acquirer_id.provider, order.amount_total, diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 877bd7602b3..82a62b2bf8a 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): @@ -449,7 +454,7 @@ class SaleOrder(models.Model): lines_to_update.append((1, line.id, {'price_unit': price_unit})) self.update({'order_line': lines_to_update}) self.show_update_pricelist = False - self.message_post(body=_("Product prices have been recomputed according to pricelist <b>%s<b> ") % self.pricelist_id.display_name) + self.message_post(body=_("Product prices have been recomputed according to pricelist <b>%s<b> ", self.pricelist_id.display_name)) @api.model def create(self, vals): @@ -1595,7 +1600,7 @@ class SaleOrderLine(models.Model): result = {} warning = {} if product.sale_line_warn != 'no-message': - title = _("Warning for %s") % product.name + title = _("Warning for %s", product.name) message = product.sale_line_warn_msg warning['title'] = title warning['message'] = message 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/sale_timesheet/models/project.py b/addons/sale_timesheet/models/project.py index da7a5926053..b31f89dad69 100644 --- a/addons/sale_timesheet/models/project.py +++ b/addons/sale_timesheet/models/project.py @@ -110,7 +110,7 @@ class Project(models.Model): return self.action_view_timesheet_plan() return { 'type': 'ir.actions.act_window', - 'name': _('Timesheets of %s') % self.name, + 'name': _('Timesheets of %s', self.name), 'domain': [('project_id', '!=', False)], 'res_model': 'account.analytic.line', 'view_id': False, diff --git a/addons/sales_team/models/crm_team.py b/addons/sales_team/models/crm_team.py index ef919653fea..e26a05abe7f 100644 --- a/addons/sales_team/models/crm_team.py +++ b/addons/sales_team/models/crm_team.py @@ -133,7 +133,7 @@ class CrmTeam(models.Model): def _graph_get_model(self): """ skeleton function defined here because it'll be called by crm and/or sale """ - raise UserError(_('Undefined graph model for Sales Team: %s') % self.name) + raise UserError(_('Undefined graph model for Sales Team: %s', self.name)) def _graph_get_dates(self, today): """ return a coherent start and end date for the dashboard graph covering a month period grouped by week. @@ -151,7 +151,7 @@ class CrmTeam(models.Model): return 'EXTRACT(WEEK FROM %s)' % self._graph_date_column() def _graph_y_query(self): - raise UserError(_('Undefined graph model for Sales Team: %s') % self.name) + raise UserError(_('Undefined graph model for Sales Team: %s', self.name)) def _extra_sql_conditions(self): return '' diff --git a/addons/sms/models/sms_template.py b/addons/sms/models/sms_template.py index fb5b8877e87..f3e777f77c4 100644 --- a/addons/sms/models/sms_template.py +++ b/addons/sms/models/sms_template.py @@ -32,7 +32,7 @@ class SMSTemplate(models.Model): @api.returns('self', lambda value: value.id) def copy(self, default=None): default = dict(default or {}, - name=_("%s (copy)") % self.name) + name=_("%s (copy)", self.name)) return super(SMSTemplate, self).copy(default=default) def unlink(self): @@ -44,7 +44,7 @@ class SMSTemplate(models.Model): view = self.env.ref('sms.sms_composer_view_form') for template in self: - button_name = _('Send SMS (%s)') % template.name + button_name = _('Send SMS (%s)', template.name) action = ActWindow.create({ 'name': button_name, 'type': 'ir.actions.act_window', diff --git a/addons/sms/wizard/sms_composer.py b/addons/sms/wizard/sms_composer.py index 0d3d822ed4b..7467d99a21a 100644 --- a/addons/sms/wizard/sms_composer.py +++ b/addons/sms/wizard/sms_composer.py @@ -155,7 +155,7 @@ class SendSMS(models.TransientModel): sanitized_numbers = [info['sanitized'] for info in sanitize_res.values() if info['sanitized']] invalid_numbers = [number for number, info in sanitize_res.items() if info['code']] if invalid_numbers: - raise UserError(_('Following numbers are not correctly encoded: %s') % repr(invalid_numbers)) + raise UserError(_('Following numbers are not correctly encoded: %s', repr(invalid_numbers))) composer.sanitized_numbers = ','.join(sanitized_numbers) else: composer.sanitized_numbers = False @@ -193,7 +193,7 @@ class SendSMS(models.TransientModel): if self.comment_single_recipient and not self.recipient_single_valid: raise UserError(_('Invalid recipient number. Please update it.')) elif not self.comment_single_recipient and self.recipient_invalid_count: - raise UserError(_('%s invalid recipients') % self.recipient_invalid_count) + raise UserError(_('%s invalid recipients', self.recipient_invalid_count)) self._action_send_sms() return False diff --git a/addons/snailmail_account/wizard/account_invoice_send.py b/addons/snailmail_account/wizard/account_invoice_send.py index c4c74f9b9df..d694ca56586 100644 --- a/addons/snailmail_account/wizard/account_invoice_send.py +++ b/addons/snailmail_account/wizard/account_invoice_send.py @@ -80,7 +80,7 @@ class AccountInvoiceSend(models.TransientModel): self.env['bus.bus'].sendone( (self._cr.dbname, 'res.partner', self.env.user.partner_id.id), {'type': 'snailmail_invalid_address', 'title': _("Invalid Addresses"), - 'message': _("%s of the selected invoice(s) had an invalid address and were not sent") % self.invalid_addresses} + 'message': _("%s of the selected invoice(s) had an invalid address and were not sent", self.invalid_addresses)} ) def invalid_addresses_action(self): diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index ea9529e58b3..b7f9ce7e06c 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -329,11 +329,11 @@ class Product(models.Model): # TDE FIXME: should probably clean the search methods # to prevent sql injections if field not in ('qty_available', 'virtual_available', 'incoming_qty', 'outgoing_qty', 'free_qty'): - raise UserError(_('Invalid domain left operand %s') % field) + raise UserError(_('Invalid domain left operand %s', field)) if operator not in ('<', '>', '=', '!=', '<=', '>='): - raise UserError(_('Invalid domain operator %s') % operator) + raise UserError(_('Invalid domain operator %s', operator)) if not isinstance(value, (float, int)): - raise UserError(_('Invalid domain right operand %s') % value) + raise UserError(_('Invalid domain right operand %s', value)) # TODO: Still optimization possible when searching virtual quantities ids = [] diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 8155141c7ca..7256e54c5e6 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -499,7 +499,7 @@ class StockMove(models.Model): return msg = _("The scheduled date has been automatically updated due to a delay on <a href='#' data-oe-model='%s' data-oe-id='%s'>%s</a>.") % (doc_orig[0]._name, doc_orig[0].id, doc_orig[0].name) - msg_subject = _("Scheduled date update due to delay on %s") % doc_orig[0].name + msg_subject = _("Scheduled date update due to delay on %s", doc_orig[0].name) # write the message on each document for doc in documents: last_message = doc.message_ids[:1] diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index 7e0f88d6b36..0ba3384d755 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -157,7 +157,7 @@ class StockMoveLine(models.Model): if self.qty_done and self.product_id.tracking == 'serial': qty_done = self.product_uom_id._compute_quantity(self.qty_done, self.product_id.uom_id) if float_compare(qty_done, 1.0, precision_rounding=self.product_id.uom_id.rounding) != 0: - message = _('You can only process 1.0 %s of products with unique serial number.') % self.product_id.uom_id.name + message = _('You can only process 1.0 %s of products with unique serial number.', self.product_id.uom_id.name) res['warning'] = {'title': _('Warning'), 'message': message} return res diff --git a/addons/stock/models/stock_quant.py b/addons/stock/models/stock_quant.py index 10ce708554b..0be79095598 100644 --- a/addons/stock/models/stock_quant.py +++ b/addons/stock/models/stock_quant.py @@ -456,12 +456,12 @@ class StockQuant(models.Model): # if we want to reserve available_quantity = self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict) if float_compare(quantity, available_quantity, precision_rounding=rounding) > 0: - raise UserError(_('It is not possible to reserve more products of %s than you have in stock.') % product_id.display_name) + raise UserError(_('It is not possible to reserve more products of %s than you have in stock.', product_id.display_name)) elif float_compare(quantity, 0, precision_rounding=rounding) < 0: # if we want to unreserve available_quantity = sum(quants.mapped('reserved_quantity')) if float_compare(abs(quantity), available_quantity, precision_rounding=rounding) > 0: - raise UserError(_('It is not possible to unreserve more products of %s than you have in stock.') % product_id.display_name) + raise UserError(_('It is not possible to unreserve more products of %s than you have in stock.', product_id.display_name)) else: return reserved_quants diff --git a/addons/stock/models/stock_rule.py b/addons/stock/models/stock_rule.py index ff49323f5af..1e7bda0be53 100644 --- a/addons/stock/models/stock_rule.py +++ b/addons/stock/models/stock_rule.py @@ -140,7 +140,7 @@ class StockRule(models.Model): if self.procure_method == 'make_to_order' and self.location_src_id: suffix = _("<br>A need is created in <b>%s</b> and a rule will be triggered to fulfill it.") % (source) if self.procure_method == 'mts_else_mto' and self.location_src_id: - suffix = _("<br>If the products are not available in <b>%s</b>, a rule will be triggered to bring products in this location.") % source + suffix = _("<br>If the products are not available in <b>%s</b>, a rule will be triggered to bring products in this location.", source) message_dict = { 'pull': _('When products are needed in <b>%s</b>, <br/> <b>%s</b> are created from <b>%s</b> to fulfill the need.') % (destination, operation, source) + suffix, 'push': _('When products arrive in <b>%s</b>, <br/> <b>%s</b> are created to send them in <b>%s</b>.') % (source, operation, destination) diff --git a/addons/stock/models/stock_warehouse.py b/addons/stock/models/stock_warehouse.py index 96e77ba907a..fcc0713ba28 100644 --- a/addons/stock/models/stock_warehouse.py +++ b/addons/stock/models/stock_warehouse.py @@ -740,7 +740,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/wizard/stock_picking_return.py b/addons/stock/wizard/stock_picking_return.py index a66749b81db..7bcda6b4d72 100644 --- a/addons/stock/wizard/stock_picking_return.py +++ b/addons/stock/wizard/stock_picking_return.py @@ -118,7 +118,7 @@ class ReturnPicking(models.TransientModel): 'move_lines': [], 'picking_type_id': picking_type_id, 'state': 'draft', - 'origin': _("Return of %s") % self.picking_id.name, + 'origin': _("Return of %s", self.picking_id.name), 'location_id': self.picking_id.location_dest_id.id, 'location_dest_id': self.location_id.id}) new_picking.message_post_with_view('mail.message_origin_link', 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 49d693b728a..35989e80b67 100644 --- a/addons/stock_account/wizard/stock_valuation_layer_revaluation.py +++ b/addons/stock_account/wizard/stock_valuation_layer_revaluation.py @@ -74,12 +74,20 @@ class StockValuationLayerRevaluation(models.TransientModel): ]) # Create a manual stock valuation layer + if self.reason: + description = _("Manual Stock Valuation: %s.", self.reason) + else: + description = _("Manual Stock Valuation: No Reason Given.") + if product_id.categ_id.property_cost_method == 'average': + description += _( + " Product cost updated from %(previous)s to %(new_cost)s.", + previous=product_id.standard_price, + new_cost=product_id.standard_price + self.added_value / self.current_quantity_svl + ) revaluation_svl_vals = { 'company_id': self.company_id.id, 'product_id': product_id.id, - 'description': _("Manual Stock Valuation: %s.%s") % ( - self.reason or _("No Reason Given"), - product_id.categ_id.property_cost_method == 'average' and (_(" Product cost updated from %s to %s.") % (product_id.standard_price, product_id.standard_price + self.added_value / self.current_quantity_svl)) or ''), + 'description': description, 'value': self.added_value, 'quantity': 0, } @@ -118,20 +126,28 @@ class StockValuationLayerRevaluation(models.TransientModel): move_vals = { 'journal_id': self.account_journal_id.id or accounts['stock_journal'].id, 'company_id': self.company_id.id, - 'ref': _("Revaluation of %s") % product_id.display_name, + 'ref': _("Revaluation of %s", product_id.display_name), 'stock_valuation_layer_ids': [(6, None, [revaluation_svl.id])], '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/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py index 63222bc1385..076ead97c0c 100644 --- a/addons/stock_landed_costs/models/stock_landed_cost.py +++ b/addons/stock_landed_costs/models/stock_landed_cost.py @@ -204,7 +204,7 @@ class StockLandedCost(models.Model): if not lines: target_model_descriptions = dict(self._fields['target_model']._description_selection(self.env)) - raise UserError(_("You cannot apply landed costs on the chosen %s(s). Landed costs can only be applied for products with automated inventory valuation and FIFO or average costing method.") % target_model_descriptions[self.target_model]) + raise UserError(_("You cannot apply landed costs on the chosen %s(s). Landed costs can only be applied for products with automated inventory valuation and FIFO or average costing method.", target_model_descriptions[self.target_model])) return lines def compute_landed_cost(self): @@ -285,7 +285,7 @@ class StockLandedCost(models.Model): for cost in self: if not cost._get_targeted_move_ids(): target_model_descriptions = dict(self._fields['target_model']._description_selection(self.env)) - raise UserError(_('Please define %s on which those additional costs should apply.') % target_model_descriptions[cost.target_model]) + raise UserError(_('Please define %s on which those additional costs should apply.', target_model_descriptions[cost.target_model])) def _check_sum(self): """ Check if each cost line its valuation lines sum to the correct amount diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index c69ee0d66ce..383308061de 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -773,11 +773,11 @@ class ExportXlsxWriter: # fails note that you can't export cell_value = pycompat.to_text(cell_value) except UnicodeDecodeError: - raise UserError(_("Binary fields can not be exported to Excel unless their content is base64-encoded. That does not seem to be the case for %s.") % self.field_names[column]) + raise UserError(_("Binary fields can not be exported to Excel unless their content is base64-encoded. That does not seem to be the case for %s.", self.field_names)[column]) if isinstance(cell_value, str): if len(cell_value) > self.worksheet.xls_strmax: - cell_value = _("The content of this cell is too long for an XLSX file (more than %s characters). Please use the CSV format for this export.") % self.worksheet.xls_strmax + cell_value = _("The content of this cell is too long for an XLSX file (more than %s characters). Please use the CSV format for this export.", self.worksheet.xls_strmax) else: cell_value = cell_value.replace("\r", " ") elif isinstance(cell_value, datetime.datetime): diff --git a/addons/website/models/website.py b/addons/website/models/website.py index afe67a8a9ef..3e810dfa729 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -284,7 +284,7 @@ class Website(models.Model): copy_menu(submenu, new_menu) for website in self: new_top_menu = top_menu.copy({ - 'name': _('Top Menu for Website %s') % website.id, + 'name': _('Top Menu for Website %s', website.id), 'website_id': website.id, }) for submenu in top_menu.child_id: @@ -408,7 +408,7 @@ class Website(models.Model): for page in pages: dependencies.setdefault(page_key, []) dependencies[page_key].append({ - 'text': _('Page <b>%s</b> contains a link to this page') % page.url, + 'text': _('Page <b>%s</b> contains a link to this page', page.url), 'item': page.name, 'link': page.url, }) @@ -436,7 +436,7 @@ class Website(models.Model): menu_key = _('Menus') for menu in menus: dependencies.setdefault(menu_key, []).append({ - 'text': _('This page is in the menu <b>%s</b>') % menu.name, + 'text': _('This page is in the menu <b>%s</b>', menu.name), 'link': '/web#id=%s&view_type=form&model=website.menu' % menu.id, 'item': menu.name, }) @@ -472,7 +472,7 @@ class Website(models.Model): for p in pages: dependencies.setdefault(page_key, []) dependencies[page_key].append({ - 'text': _('Page <b>%s</b> is calling this file') % p.url, + 'text': _('Page <b>%s</b> is calling this file', p.url), 'item': p.name, 'link': p.url, }) diff --git a/addons/website/models/website_visitor.py b/addons/website/models/website_visitor.py index 3af252bda6e..7ff7702df94 100644 --- a/addons/website/models/website_visitor.py +++ b/addons/website/models/website_visitor.py @@ -67,7 +67,7 @@ class WebsiteVisitor(models.Model): def name_get(self): return [( record.id, - (record.name or _('Website Visitor #%s') % record.id) + (record.name or _('Website Visitor #%s', record.id)) ) for record in self] @api.depends('partner_id.email_normalized', 'partner_id.mobile', 'partner_id.phone') diff --git a/addons/website_blog/models/website.py b/addons/website_blog/models/website.py index a647326c340..fb153e3d756 100644 --- a/addons/website_blog/models/website.py +++ b/addons/website_blog/models/website.py @@ -26,7 +26,7 @@ class Website(models.Model): dep[page_key] = [] for p in posts: dep[page_key].append({ - 'text': _('Blog Post <b>%s</b> seems to have a link to this page !') % p.name, + 'text': _('Blog Post <b>%s</b> seems to have a link to this page !', p.name), 'item': p.name, 'link': p.website_url, }) @@ -51,7 +51,7 @@ class Website(models.Model): dep[page_key] = [] for p in posts: dep[page_key].append({ - 'text': _('Blog Post <b>%s</b> seems to be calling this file !') % p.name, + 'text': _('Blog Post <b>%s</b> seems to be calling this file !', p.name), 'item': p.name, 'link': p.website_url, }) diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py index c99d2c0b1d0..42c07b289c7 100644 --- a/addons/website_blog/models/website_blog.py +++ b/addons/website_blog/models/website_blog.py @@ -215,7 +215,7 @@ class BlogPost(models.Model): @api.returns('self', lambda value: value.id) def copy_data(self, default=None): self.ensure_one() - name = _("%s (copy)") % self.name + name = _("%s (copy)", self.name) default = dict(default or {}, name=name) return super(BlogPost, self).copy_data(default) diff --git a/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py index 9f6a466ef92..9267f6300e3 100644 --- a/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py +++ b/addons/website_crm_partner_assign/wizard/crm_forward_to_partner.py @@ -69,7 +69,7 @@ class CrmLeadForwardToPartner(models.TransientModel): if no_email: raise UserError(_('Set an email address for the partner(s): %s') % ", ".join(no_email)) if self.forward_type == 'single' and not self.partner_id.email: - raise UserError(_('Set an email address for the partner %s') % self.partner_id.name) + raise UserError(_('Set an email address for the partner %s', self.partner_id.name)) partners_leads = {} for lead in self.assignation_lines: diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index f8cf3c6ea02..abe6d4c39da 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -464,7 +464,7 @@ class Post(models.Model): filter_regexp = r'(<img.*?>)|(<a[^>]*?href[^>]*?>)|(<[a-z|A-Z]+[^>]*style\s*=\s*[\'"][^\'"]*\s*background[^:]*:[^url;]*url)' content_match = re.search(filter_regexp, content, re.I) if content_match: - raise AccessError(_('%d karma required to post an image or link.') % forum.karma_editor) + raise AccessError(_('%d karma required to post an image or link.', forum.karma_editor)) return content def _default_website_meta(self): @@ -492,9 +492,9 @@ class Post(models.Model): raise UserError(_('Posting answer on a [Deleted] or [Closed] question is not possible.')) # karma-based access if not post.parent_id and not post.can_ask: - raise AccessError(_('%d karma required to create a new question.') % post.forum_id.karma_ask) + raise AccessError(_('%d karma required to create a new question.', post.forum_id.karma_ask)) elif post.parent_id and not post.can_answer: - raise AccessError(_('%d karma required to answer a question.') % post.forum_id.karma_answer) + raise AccessError(_('%d karma required to answer a question.', post.forum_id.karma_answer)) if not post.parent_id and not post.can_post: post.sudo().state = 'pending' @@ -511,7 +511,7 @@ class Post(models.Model): # Make sure only author or moderator can edit/delete messages for post in self.browse(res_ids): if not post.can_edit: - raise AccessError(_('%d karma required to edit a post.') % post.karma_edit) + raise AccessError(_('%d karma required to edit a post.', post.karma_edit)) return super(Post, self).get_mail_message_access(res_ids, operation, model_name=model_name) def write(self, vals): @@ -527,18 +527,18 @@ class Post(models.Model): if 'state' in vals: if vals['state'] in ['active', 'close']: if not post.can_close: - raise AccessError(_('%d karma required to close or reopen a post.') % post.karma_close) + raise AccessError(_('%d karma required to close or reopen a post.', post.karma_close)) trusted_keys += ['state', 'closed_uid', 'closed_date', 'closed_reason_id'] elif vals['state'] == 'flagged': if not post.can_flag: - raise AccessError(_('%d karma required to flag a post.') % post.forum_id.karma_flag) + raise AccessError(_('%d karma required to flag a post.', post.forum_id.karma_flag)) trusted_keys += ['state', 'flag_user_id'] if 'active' in vals: if not post.can_unlink: - raise AccessError(_('%d karma required to delete or reactivate a post.') % post.karma_unlink) + raise AccessError(_('%d karma required to delete or reactivate a post.', post.karma_unlink)) if 'is_correct' in vals: if not post.can_accept: - raise AccessError(_('%d karma required to accept or refuse an answer.') % post.karma_accept) + raise AccessError(_('%d karma required to accept or refuse an answer.', post.karma_accept)) # update karma except for self-acceptance mult = 1 if vals['is_correct'] else -1 if vals['is_correct'] != post.is_correct and post.create_uid.id != self._uid: @@ -546,9 +546,9 @@ class Post(models.Model): self.env.user.sudo().add_karma(post.forum_id.karma_gen_answer_accept * mult) if tag_ids: if set(post.tag_ids.ids) != tag_ids and self.env.user.karma < post.forum_id.karma_edit_retag: - raise AccessError(_('%d karma required to retag.') % post.forum_id.karma_edit_retag) + raise AccessError(_('%d karma required to retag.', post.forum_id.karma_edit_retag)) if any(key not in trusted_keys for key in vals) and not post.can_edit: - raise AccessError(_('%d karma required to edit a post.') % post.karma_edit) + raise AccessError(_('%d karma required to edit a post.', post.karma_edit)) res = super(Post, self).write(vals) @@ -575,7 +575,7 @@ class Post(models.Model): if post.state == 'active' and post.parent_id: post.parent_id.message_post_with_view( 'website_forum.forum_post_template_new_answer', - subject=_('Re: %s') % post.parent_id.name, + subject=_('Re: %s', post.parent_id.name), partner_ids=[(4, p.id) for p in tag_partners], subtype_id=self.env['ir.model.data'].xmlid_to_res_id('website_forum.mt_answer_new')) elif post.state == 'active' and not post.parent_id: @@ -647,7 +647,7 @@ class Post(models.Model): def validate(self): for post in self: if not post.can_moderate: - raise AccessError(_('%d karma required to validate a post.') % post.forum_id.karma_moderate) + raise AccessError(_('%d karma required to validate a post.', post.forum_id.karma_moderate)) # if state == pending, no karma previously added for the new question if post.state == 'pending': post.create_uid.sudo().add_karma(post.forum_id.karma_gen_question_new) @@ -662,7 +662,7 @@ class Post(models.Model): def refuse(self): for post in self: if not post.can_moderate: - raise AccessError(_('%d karma required to refuse a post.') % post.forum_id.karma_moderate) + raise AccessError(_('%d karma required to refuse a post.', post.forum_id.karma_moderate)) post.moderator_id = self.env.user return True @@ -670,7 +670,7 @@ class Post(models.Model): res = [] for post in self: if not post.can_flag: - raise AccessError(_('%d karma required to flag a post.') % post.forum_id.karma_flag) + raise AccessError(_('%d karma required to flag a post.', post.forum_id.karma_flag)) if post.state == 'flagged': res.append({'error': 'post_already_flagged'}) elif post.state == 'active': @@ -691,7 +691,7 @@ class Post(models.Model): def mark_as_offensive(self, reason_id): for post in self: if not post.can_moderate: - raise AccessError(_('%d karma required to mark a post as offensive.') % post.forum_id.karma_moderate) + raise AccessError(_('%d karma required to mark a post as offensive.', post.forum_id.karma_moderate)) # remove some karma _logger.info('Downvoting user <%s> for posting spam/offensive contents', post.create_uid) post.create_uid.sudo().add_karma(post.forum_id.karma_gen_answer_flagged) @@ -721,7 +721,7 @@ class Post(models.Model): def unlink(self): for post in self: if not post.can_unlink: - raise AccessError(_('%d karma required to unlink a post.') % post.karma_unlink) + raise AccessError(_('%d karma required to unlink a post.', post.karma_unlink)) # if unlinking an answer with accepted answer: remove provided karma for post in self: if post.is_correct: @@ -766,7 +766,7 @@ class Post(models.Model): # karma-based action check: use the post field that computed own/all value if not self.can_comment_convert: - raise AccessError(_('%d karma required to convert an answer to a comment.') % self.karma_comment_convert) + raise AccessError(_('%d karma required to convert an answer to a comment.', self.karma_comment_convert)) # post the message question = self.parent_id @@ -806,9 +806,9 @@ class Post(models.Model): can_convert = self.env.user.karma >= karma_convert if not can_convert: if is_author and karma_own < karma_all: - raise AccessError(_('%d karma required to convert your comment to an answer.') % karma_own) + raise AccessError(_('%d karma required to convert your comment to an answer.', karma_own)) else: - raise AccessError(_('%d karma required to convert a comment to an answer.') % karma_all) + raise AccessError(_('%d karma required to convert a comment to an answer.', karma_all)) # check the message's author has not already an answer question = post.parent_id if post.parent_id else post @@ -846,7 +846,7 @@ class Post(models.Model): ) can_unlink = user.karma >= karma_unlink if not can_unlink: - raise AccessError(_('%d karma required to unlink a comment.') % karma_unlink) + raise AccessError(_('%d karma required to unlink a comment.', karma_unlink)) result.append(comment.unlink()) return result @@ -893,7 +893,7 @@ class Post(models.Model): self.ensure_one() if not self.can_comment: - raise AccessError(_('%d karma required to comment.') % self.karma_comment) + raise AccessError(_('%d karma required to comment.', self.karma_comment)) if not kwargs.get('record_name') and self.parent_id: kwargs['record_name'] = self.parent_id.name return super(Post, self).message_post(message_type=message_type, **kwargs) @@ -1005,9 +1005,9 @@ class Vote(models.Model): def _check_karma_rights(self, upvote=None): # karma check if upvote and not self.post_id.can_upvote: - raise AccessError(_('%d karma required to upvote.') % self.post_id.forum_id.karma_upvote) + raise AccessError(_('%d karma required to upvote.', self.post_id.forum_id.karma_upvote)) elif not upvote and not self.post_id.can_downvote: - raise AccessError(_('%d karma required to downvote.') % self.post_id.forum_id.karma_downvote) + raise AccessError(_('%d karma required to downvote.', self.post_id.forum_id.karma_downvote)) def _vote_update_karma(self, old_vote, new_vote): if self.post_id.parent_id: @@ -1042,5 +1042,5 @@ class Tags(models.Model): def create(self, vals): forum = self.env['forum.forum'].browse(vals.get('forum_id')) if self.env.user.karma < forum.karma_tag_create: - raise AccessError(_('%d karma required to create a new Tag.') % forum.karma_tag_create) + raise AccessError(_('%d karma required to create a new Tag.', forum.karma_tag_create)) return super(Tags, self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)).create(vals) diff --git a/addons/website_livechat/models/mail_channel.py b/addons/website_livechat/models/mail_channel.py index 804571bde42..86ab7aeb2c3 100644 --- a/addons/website_livechat/models/mail_channel.py +++ b/addons/website_livechat/models/mail_channel.py @@ -58,7 +58,7 @@ class MailChannel(models.Model): message = _("""%s has started a conversation with %s. The chat request has been canceled.""") % (name, operator or _('an operator')) else: - message = _('%s has left the conversation.') % name + message = _('%s has left the conversation.', name) return message diff --git a/addons/website_sale/models/product_image.py b/addons/website_sale/models/product_image.py index 5fe484a6a5c..eea9afb6967 100644 --- a/addons/website_sale/models/product_image.py +++ b/addons/website_sale/models/product_image.py @@ -40,7 +40,7 @@ class ProductImage(models.Model): def _check_valid_video_url(self): for image in self: if image.video_url and not image.embed_code: - raise ValidationError(_("Provided video URL for '%s' is not valid. Please enter a valid video URL.") % image.name) + raise ValidationError(_("Provided video URL for '%s' is not valid. Please enter a valid video URL.", image.name)) @api.model_create_multi def create(self, vals_list): diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 73e52810c61..c71a6201f9f 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -361,9 +361,9 @@ class SaleOrderLine(models.Model): def get_sale_order_line_multiline_description_sale(self, product): description = super(SaleOrderLine, self).get_sale_order_line_multiline_description_sale(product) if self.linked_line_id: - description += "\n" + _("Option for: %s") % self.linked_line_id.product_id.display_name + description += "\n" + _("Option for: %s", self.linked_line_id.product_id.display_name) if self.option_line_ids: - description += "\n" + '\n'.join([_("Option: %s") % option_line.product_id.display_name for option_line in self.option_line_ids]) + description += "\n" + '\n'.join([_("Option: %s", option_line.product_id.display_name) for option_line in self.option_line_ids]) return description @api.depends('product_id.display_name') 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) diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index 1e896d3f754..68648b7ff9d 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -993,7 +993,7 @@ class WebsiteSlides(WebsiteProfile): return preview existing_slide = Slide.search([('channel_id', '=', int(data['channel_id'])), ('document_id', '=', document_id)], limit=1) if existing_slide: - preview['error'] = _('This video already exists in this channel on the following slide: %s') % existing_slide.name + preview['error'] = _('This video already exists in this channel on the following slide: %s', existing_slide.name) return preview values = Slide._parse_document_url(data['url'], only_preview_fields=True) if values.get('error'): @@ -1051,7 +1051,7 @@ class WebsiteSlides(WebsiteProfile): return {'error': e.args[0]} except Exception as e: _logger.error(e) - return {'error': _('Internal server error, please try again later or contact administrator.\nHere is the error message: %s') % e} + return {'error': _('Internal server error, please try again later or contact administrator.\nHere is the error message: %s', e)} # ensure correct ordering by re sequencing slides in front-end (backend should be ok thanks to list view) channel._resequence_slides(slide, force_category=category) diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py index 36ba1c351f7..401878ee94b 100644 --- a/addons/website_slides/models/slide_channel.py +++ b/addons/website_slides/models/slide_channel.py @@ -446,7 +446,7 @@ class Channel(models.Model): action = self.env.ref('website_slides.slide_channel_partner_action').read()[0] action['domain'] = [('channel_id', 'in', self.ids)] if len(self) == 1: - action['display_name'] = _('Attendees of %s') % self.name + action['display_name'] = _('Attendees of %s', self.name) action['context'] = {'active_test': False, 'default_channel_id': self.id} if state: action['domain'] += [('completed', '=', state == 'completed')] diff --git a/addons/website_slides/models/slide_question.py b/addons/website_slides/models/slide_question.py index 96dc76c8c63..2ebe650043a 100644 --- a/addons/website_slides/models/slide_question.py +++ b/addons/website_slides/models/slide_question.py @@ -24,9 +24,9 @@ class SlideQuestion(models.Model): def _check_answers_integrity(self): for question in self: if len(question.answer_ids.filtered(lambda answer: answer.is_correct)) != 1: - raise ValidationError(_('Question "%s" must have 1 correct answer') % question.question) + raise ValidationError(_('Question "%s" must have 1 correct answer', question.question)) if len(question.answer_ids) < 2: - raise ValidationError(_('Question "%s" must have 1 correct answer and at least 1 invalid answer') % question.question) + raise ValidationError(_('Question "%s" must have 1 correct answer and at least 1 invalid answer', question.question)) @api.depends('slide_id') def _compute_statistics(self): diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py index 6e600f90b44..45bf3a722be 100644 --- a/addons/website_slides/models/slide_slide.py +++ b/addons/website_slides/models/slide_slide.py @@ -795,7 +795,7 @@ class Slide(models.Model): if error == 'keyInvalid': return _('Your Google API key is invalid, please update it into your settings.\nSettings > Website > Features > API Key') - return _('Could not fetch data from url. Document or access right not available:\n%s') % error + return _('Could not fetch data from url. Document or access right not available:\n%s', error) @api.model def _parse_google_document(self, document_id, only_preview_fields): |
