Add RuboCop rule Gettext/StaticIdentifier

What does this MR do and why?

This MR adds a new 👮 Gettext/StaticIdentifier to resolve #408337 (closed).

# bad
_("Hi #{name}")
_('Hi %{name}' % { name: 'Luki' })
_(format('Hi %{name}', name: 'Luki'))
                                      
# good
_('Hi %{name}') % { name: 'Luki' }
format(_('Hi %{name}', name: 'Luki'))
                                      
# also good
var = "Hi"
_(var)
_(some_method_call)
_(CONST)

With this MR the 👮 Cop/RubyInterpolationInTranslation is now no longer necessary as Gettext/StaticIdentifier also catches the interpolation case.

Offenses

The following offenses were caught by RuboCop.

Ruby (now TODOs)

Offenses:

app/graphql/types/project_type.rb:691:58: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
            Gitlab::Utils::ErrorMessage.to_user_facing(_(format('You must %s before using Security features.', add_file_docs_link.html_safe)).html_safe)
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/integrations/apple_app_store.rb:56:12: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
        s_(format("To get started, see the <a href='%{url}' target='_blank'>integration documentation</a> for instructions on how to generate App Store Connect credentials, and how to use this integration.", url: Rails.application.routes.url_helpers.help_page_url('user/project/integrations/apple_app_store'))).html_safe
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/integrations/confluence.rb:36:11: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
          'ConfluenceService|Your GitLab wiki is still available at %{wiki_link}. To re-enable the link to the GitLab wiki, disable this integration.' % ...
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/integrations/google_play.rb:47:12: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
        s_(format("To generate a Google Play service account key and use this integration, see the <a href='%{url}' target='_blank'>integration documentation</a>.", url: Rails.application.routes.url_helpers.help_page_url('user/project/integrations/google_play'))).html_safe
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/import/fogbugz_service.rb:41:12: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
        s_("Fogbugz|Fogbugz import failed due to an error: %{error}" % { error: e }),
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/issuable_links/create_service.rb:116:9: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      _('%{issuable}(s) already assigned' % { issuable: target_issuable_type.capitalize })
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/issuable_links/create_service.rb:120:9: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      _('No matching %{issuable} found. Make sure that you are adding a valid %{issuable} URL.' % { issuable: target_issuable_type })
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/issues/set_crm_contacts_service.rb:152:56: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      ServiceResponse.error(payload: issue, message: _("You can only add up to %{max_contacts} contacts at one time" % { max_contacts: MAX_ADDITIONAL_CONTACTS }))
                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/projects/create_from_template_service.rb:39:44: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      project.errors.add(:template_name, _("'%{template_name}' is unknown or invalid" % { template_name: template_name }))
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/security/ci_configuration/base_create_service.rb:23:21: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                  _(format('You must %s before using Security features.', docs_link.html_safe)).html_safe)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/users/banned_user_base_service.rb:27:15: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      error(_("You cannot %{action} %{state} users." % { action: action.to_s, state: user.state }), :forbidden)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/users/banned_user_base_service.rb:35:15: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      error(_("You are not allowed to %{action} a user" % { action: action.to_s }), :forbidden)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/services/work_items/widgets/hierarchy_service/base_service.rb:59:19: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
          error(_("One or more arguments are invalid: %{args}." % { args: params.keys.to_sentence }))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/controllers/admin/licenses_controller.rb:25:20: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                 _('The license was successfully uploaded and will be active from %{starts_at}. You can see the details below.' % { starts_at: @license.starts_at })
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/controllers/subscriptions/groups_controller.rb:20:22: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                   _('Welcome to GitLab, %{first_name}!' % { first_name: current_user.first_name })
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/controllers/subscriptions/groups_controller.rb:22:22: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                   _('Subscription successfully applied to "%{group_name}"' % { group_name: @group.name })
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/mailers/ee/emails/admin_notification.rb:19:26: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
          @ban_scope = _('your group (%{group_name})' % { group_name: group.name })
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/mailers/emails/namespace_storage_usage_mailer.rb:22:21: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
        subject: s_("NamespaceStorage|Action required: Storage has been exceeded for %{namespace_name}" % { namespace_name: namespace.name })
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/mailers/emails/namespace_storage_usage_mailer.rb:36:21: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
        subject: s_("NamespaceStorage|You have used %{used_storage_percentage}%% of the storage quota for %{namespace_name}" % ...
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/models/ee/member.rb:193:9: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
      _("email '%{email}' is not a verified email." % { email: user.email })
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/models/integrations/github.rb:52:10: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
      s_("GithubIntegration|This requires mirroring your GitHub repository to this project. %{docs_link}" % { docs_link: docs_link }).html_safe
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/ee/projects/create_from_template_service.rb:42:32: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                             _("%{template_project_id} is unknown or invalid" % { template_project_id: template_project_id }))
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/ee/projects/create_from_template_service.rb:44:48: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
          project.errors.add(:template_name, _("'%{template_name}' is unknown or invalid" % { template_name: template_name }))
                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/security/security_orchestration_policies/policy_configuration_validation_service.rb:21:15: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
            _("Policy management project does not have any policies in %{policy_path}" % { ...
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/timebox/rollup_report_service.rb:54:47: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                when :unsupported_type then _(format('%{timebox_type} does not support burnup charts', timebox_type: timebox_type))
                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/timebox/rollup_report_service.rb:55:47: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
                when :missing_dates    then _(format('%{timebox_type} must have a start and due date', timebox_type: timebox_type))
                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/timebox_report_service.rb:64:45: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
              when :unsupported_type then _('%{timebox_type} does not support burnup charts' % { timebox_type: timebox_type })
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/app/services/timebox_report_service.rb:65:45: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
              when :missing_dates    then _('%{timebox_type} must have a start and due date' % { timebox_type: timebox_type })
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/spec/controllers/groups/security/policies_controller_spec.rb:156:45: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
              expect(flash[:alert]).to eq(_("Policy management project does not have any policies in %{policy_path}" % { ...
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ee/spec/features/registrations/identity_verification_spec.rb:217:36: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method _(...).
    expect(page).to have_content(_(format('Welcome to GitLab, %{first_name}!', first_name: user.first_name)))
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/gitlab/github_import/settings.rb:34:23: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
            label: s_(format("GitHubImport|%{text}", text: data[:label])),
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/gitlab/github_import/settings.rb:35:25: C: Gettext/StaticIdentifier: Ensure to pass static strings to translation method s_(...).
            details: s_(format("GitHubImport|%{text}", text: data[:details]))
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

30579 files inspected, 32 offenses detected

HAML

Fixed in !118369 (merged).

app/views/projects/runners/edit.html.haml:7 [W] RuboCop: Gettext/StaticString: Ensure to pass static strings to translation method `s_(...)`.
app/views/shared/integrations/prometheus/_metrics.html.haml:36 [W] RuboCop: Gettext/StaticString: Ensure to pass static strings to translation method `s_(...)`.
app/views/shared/runners/_runner_details.html.haml:5 [W] RuboCop: Gettext/StaticString: Ensure to pass static strings to translation method `s_(...)`.
ee/app/views/admin/geo/shared/_replication_nav.haml:5 [W] RuboCop: Gettext/StaticString: Ensure to pass static strings to translation method `_(...)`.
ee/app/views/admin/licenses/_license_status.html.haml:13 [W] RuboCop: Gettext/StaticString: Ensure to pass static strings to translation method `_(...)`.
ee/app/views/subscriptions/groups/edit.html.haml:12 [W] RuboCop: Gettext/StaticString: Ensure to pass static strings to translation method `_(...)`.

2058 files inspected, 6 lints detected

ERB (undetected by RuboCop nor HAML lint)

Fixed in !118369 (merged).

$ rg '_\([^)]+? % .+?\)' -t erb app/views/ ee/app/views/
app/views/devise/mailer/user_admin_approval.text.erb
5:<%= _('Your username is %{username}.' % { username: @resource.username }) %>
7:<%= _('Your sign-in page is %{url}.' % { url: Gitlab.config.gitlab.url }) %>

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Peter Leitzen

Merge request reports

Loading