From cd6f77409359de53c20c99c5d291ada3545d9d28 Mon Sep 17 00:00:00 2001
From: Martin Wortschack <mwortschack@gitlab.com>
Date: Fri, 12 Apr 2019 12:28:07 +0000
Subject: [PATCH] Externalize strings in app/models

- Update PO file
---
 app/models/application_setting.rb             |   4 +-
 app/models/concerns/group_descendant.rb       |   4 +-
 .../token_authenticatable_strategies/base.rb  |   2 +-
 .../encrypted.rb                              |   6 +-
 app/models/milestone.rb                       |  10 +-
 app/models/project.rb                         |  32 +-
 app/models/project_group_link.rb              |   4 +-
 app/models/project_services/asana_service.rb  |   8 +-
 app/models/project_services/bamboo_service.rb |  12 +-
 .../project_services/discord_service.rb       |   4 +-
 .../emails_on_push_service.rb                 |  14 +-
 .../project_services/external_wiki_service.rb |   6 +-
 .../project_services/flowdock_service.rb      |   4 +-
 app/models/project_services/jira_service.rb   |  20 +-
 .../pipelines_email_service.rb                |   6 +-
 .../pivotaltracker_service.rb                 |   8 +-
 .../project_services/pushover_service.rb      |  26 +-
 app/models/u2f_registration.rb                |   2 +-
 app/models/upload.rb                          |   6 +-
 app/models/user.rb                            |  12 +-
 locale/gitlab.pot                             | 282 ++++++++++++++++++
 21 files changed, 377 insertions(+), 95 deletions(-)

diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index eb6ddaac871b..2f9b4c4eaa2c 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -198,7 +198,7 @@ class ApplicationSetting < ApplicationRecord
   validates_each :restricted_visibility_levels do |record, attr, value|
     value&.each do |level|
       unless Gitlab::VisibilityLevel.options.value?(level)
-        record.errors.add(attr, "'#{level}' is not a valid visibility level")
+        record.errors.add(attr, _("'%{level}' is not a valid visibility level") % { level: level })
       end
     end
   end
@@ -206,7 +206,7 @@ class ApplicationSetting < ApplicationRecord
   validates_each :import_sources do |record, attr, value|
     value&.each do |source|
       unless Gitlab::ImportSources.options.value?(source)
-        record.errors.add(attr, "'#{source}' is not a import source")
+        record.errors.add(attr, _("'%{source}' is not a import source") % { source: source })
       end
     end
   end
diff --git a/app/models/concerns/group_descendant.rb b/app/models/concerns/group_descendant.rb
index 05cd42651339..cfffd845e437 100644
--- a/app/models/concerns/group_descendant.rb
+++ b/app/models/concerns/group_descendant.rb
@@ -22,7 +22,7 @@ def self.build_hierarchy(descendants, hierarchy_top = nil)
     return [] if descendants.empty?
 
     unless descendants.all? { |hierarchy| hierarchy.is_a?(GroupDescendant) }
-      raise ArgumentError.new('element is not a hierarchy')
+      raise ArgumentError.new(_('element is not a hierarchy'))
     end
 
     all_hierarchies = descendants.map do |descendant|
@@ -56,7 +56,7 @@ def expand_hierarchy_for_child(child, hierarchy, hierarchy_top, preloaded)
     end
 
     if parent.nil? && hierarchy_top.present?
-      raise ArgumentError.new('specified top is not part of the tree')
+      raise ArgumentError.new(_('specified top is not part of the tree'))
     end
 
     if parent && parent != hierarchy_top
diff --git a/app/models/concerns/token_authenticatable_strategies/base.rb b/app/models/concerns/token_authenticatable_strategies/base.rb
index df14e6e4754d..aafd0b538a3b 100644
--- a/app/models/concerns/token_authenticatable_strategies/base.rb
+++ b/app/models/concerns/token_authenticatable_strategies/base.rb
@@ -41,7 +41,7 @@ def reset_token!(instance)
 
     def self.fabricate(model, field, options)
       if options[:digest] && options[:encrypted]
-        raise ArgumentError, 'Incompatible options set!'
+        raise ArgumentError, _('Incompatible options set!')
       end
 
       if options[:digest]
diff --git a/app/models/concerns/token_authenticatable_strategies/encrypted.rb b/app/models/concerns/token_authenticatable_strategies/encrypted.rb
index 2c7fa2c5b3cc..4728cb658dc9 100644
--- a/app/models/concerns/token_authenticatable_strategies/encrypted.rb
+++ b/app/models/concerns/token_authenticatable_strategies/encrypted.rb
@@ -13,7 +13,7 @@ def find_token_authenticatable(token, unscoped = false)
       elsif migrating?
         find_by_plaintext_token(token, unscoped)
       else
-        raise ArgumentError, "Unknown encryption strategy: #{encrypted_strategy}!"
+        raise ArgumentError, _("Unknown encryption strategy: %{encrypted_strategy}!") % { encrypted_strategy: encrypted_strategy }
       end
     end
 
@@ -32,7 +32,7 @@ def ensure_token(instance)
       return super if instance.has_attribute?(encrypted_field)
 
       if required?
-        raise ArgumentError, 'Using required encryption strategy when encrypted field is missing!'
+        raise ArgumentError, _('Using required encryption strategy when encrypted field is missing!')
       else
         insecure_strategy.ensure_token(instance)
       end
@@ -74,7 +74,7 @@ def encrypted_strategy
       value = value.call if value.is_a?(Proc)
 
       unless value.in?([:required, :optional, :migrating])
-        raise ArgumentError, 'encrypted: needs to be a :required, :optional or :migrating!'
+        raise ArgumentError, _('encrypted: needs to be a :required, :optional or :migrating!')
       end
 
       value
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index b4aad9e512e0..787600569fa9 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -291,22 +291,22 @@ def uniqueness_of_title
     end
 
     title_exists = relation.find_by_title(title)
-    errors.add(:title, "already being used for another group or project milestone.") if title_exists
+    errors.add(:title, _("already being used for another group or project milestone.")) if title_exists
   end
 
   # Milestone should be either a project milestone or a group milestone
   def milestone_type_check
     if group_id && project_id
       field = project_id_changed? ? :project_id : :group_id
-      errors.add(field, "milestone should belong either to a project or a group.")
+      errors.add(field, _("milestone should belong either to a project or a group."))
     end
   end
 
   def milestone_format_reference(format = :iid)
-    raise ArgumentError, 'Unknown format' unless [:iid, :name].include?(format)
+    raise ArgumentError, _('Unknown format') unless [:iid, :name].include?(format)
 
     if group_milestone? && format == :iid
-      raise ArgumentError, 'Cannot refer to a group milestone by an internal id!'
+      raise ArgumentError, _('Cannot refer to a group milestone by an internal id!')
     end
 
     if format == :name && !name.include?('"')
@@ -322,7 +322,7 @@ def sanitize_title(value)
 
   def start_date_should_be_less_than_due_date
     if due_date <= start_date
-      errors.add(:due_date, "must be greater than start date")
+      errors.add(:due_date, _("must be greater than start date"))
     end
   end
 
diff --git a/app/models/project.rb b/app/models/project.rb
index c838df03c0d4..2fb6f5cb6a7c 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -313,7 +313,7 @@ class Project < ApplicationRecord
   validates :description, length: { maximum: 2000 }, allow_blank: true
   validates :ci_config_path,
     format: { without: %r{(\.{2}|\A/)},
-              message: 'cannot include leading slash or directory traversal.' },
+              message: _('cannot include leading slash or directory traversal.') },
     length: { maximum: 255 },
     allow_blank: true
   validates :name,
@@ -420,13 +420,13 @@ class Project < ApplicationRecord
   enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }
 
   chronic_duration_attr :build_timeout_human_readable, :build_timeout,
-    default: 3600, error_message: 'Maximum job timeout has a value which could not be accepted'
+    default: 3600, error_message: _('Maximum job timeout has a value which could not be accepted')
 
   validates :build_timeout, allow_nil: true,
                             numericality: { greater_than_or_equal_to: 10.minutes,
                                             less_than: 1.month,
                                             only_integer: true,
-                                            message: 'needs to be beetween 10 minutes and 1 month' }
+                                            message: _('needs to be beetween 10 minutes and 1 month') }
 
   # Used by Projects::CleanupService to hold a map of rewritten object IDs
   mount_uploader :bfg_object_map, AttachmentUploader
@@ -850,7 +850,7 @@ def update_remote_mirrors
   def mark_stuck_remote_mirrors_as_failed!
     remote_mirrors.stuck.update_all(
       update_status: :failed,
-      last_error: 'The remote mirror took to long to complete.',
+      last_error: _('The remote mirror took to long to complete.'),
       last_update_at: Time.now
     )
   end
@@ -887,14 +887,14 @@ def visibility_level_allowed_by_group
 
     level_name = Gitlab::VisibilityLevel.level_name(self.visibility_level).downcase
     group_level_name = Gitlab::VisibilityLevel.level_name(self.group.visibility_level).downcase
-    self.errors.add(:visibility_level, "#{level_name} is not allowed in a #{group_level_name} group.")
+    self.errors.add(:visibility_level, _("%{level_name} is not allowed in a %{group_level_name} group.") % { level_name: level_name, group_level_name: group_level_name })
   end
 
   def visibility_level_allowed_as_fork
     return if visibility_level_allowed_as_fork?
 
     level_name = Gitlab::VisibilityLevel.level_name(self.visibility_level).downcase
-    self.errors.add(:visibility_level, "#{level_name} is not allowed since the fork source project has lower visibility.")
+    self.errors.add(:visibility_level, _("%{level_name} is not allowed since the fork source project has lower visibility.") % { level_name: level_name })
   end
 
   def check_wiki_path_conflict
@@ -903,7 +903,7 @@ def check_wiki_path_conflict
     path_to_check = path.ends_with?('.wiki') ? path.chomp('.wiki') : "#{path}.wiki"
 
     if Project.where(namespace_id: namespace_id, path: path_to_check).exists?
-      errors.add(:name, 'has already been taken')
+      errors.add(:name, _('has already been taken'))
     end
   end
 
@@ -923,7 +923,7 @@ def validate_pages_https_only
     return unless pages_https_only?
 
     unless pages_domains.all?(&:https?)
-      errors.add(:pages_https_only, "cannot be enabled unless all domains have TLS certificates")
+      errors.add(:pages_https_only, _("cannot be enabled unless all domains have TLS certificates"))
     end
   end
 
@@ -1203,7 +1203,7 @@ def execute_services(data, hooks_scope = :push_hooks)
   def valid_repo?
     repository.exists?
   rescue
-    errors.add(:path, 'Invalid repository path')
+    errors.add(:path, _('Invalid repository path'))
     false
   end
 
@@ -1294,7 +1294,7 @@ def check_repository_path_availability
     # Check if repository with same path already exists on disk we can
     # skip this for the hashed storage because the path does not change
     if legacy_storage? && repository_with_same_path_already_exists?
-      errors.add(:base, 'There is already a repository with that name on disk')
+      errors.add(:base, _('There is already a repository with that name on disk'))
       return false
     end
 
@@ -1316,7 +1316,7 @@ def create_repository(force: false)
       repository.after_create
       true
     else
-      errors.add(:base, 'Failed to create repository via gitlab-shell')
+      errors.add(:base, _('Failed to create repository via gitlab-shell'))
       false
     end
   end
@@ -1392,7 +1392,7 @@ def change_head(branch)
       ProjectCacheWorker.perform_async(self.id, [], [:commit_count])
       reload_default_branch
     else
-      errors.add(:base, "Could not change HEAD: branch '#{branch}' does not exist")
+      errors.add(:base, _("Could not change HEAD: branch '%{branch}' does not exist") % { branch: branch })
       false
     end
   end
@@ -1444,7 +1444,7 @@ def create_wiki
     ProjectWiki.new(self, self.owner).wiki
     true
   rescue ProjectWiki::CouldNotCreateWikiError
-    errors.add(:base, 'Failed create wiki')
+    errors.add(:base, _('Failed create wiki'))
     false
   end
 
@@ -1933,7 +1933,7 @@ def legacy_storage?
   #
   # @param [Symbol] feature that needs to be rolled out for the project (:repository, :attachments)
   def hashed_storage?(feature)
-    raise ArgumentError, "Invalid feature" unless HASHED_STORAGE_FEATURES.include?(feature)
+    raise ArgumentError, _("Invalid feature") unless HASHED_STORAGE_FEATURES.include?(feature)
 
     self.storage_version && self.storage_version >= HASHED_STORAGE_FEATURES[feature]
   end
@@ -2165,7 +2165,7 @@ def check_repository_absence!
     return if skip_disk_validation
 
     if repository_storage.blank? || repository_with_same_path_already_exists?
-      errors.add(:base, 'There is already a repository with that name on disk')
+      errors.add(:base, _('There is already a repository with that name on disk'))
       throw :abort
     end
   end
@@ -2211,7 +2211,7 @@ def check_pending_delete
       errors.delete(error)
     end
 
-    errors.add(:base, "The project is still being deleted. Please try again later.")
+    errors.add(:base, _("The project is still being deleted. Please try again later."))
   end
 
   def pending_delete_twin
diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb
index 58b555c35811..feaf172d48dd 100644
--- a/app/models/project_group_link.rb
+++ b/app/models/project_group_link.rb
@@ -14,7 +14,7 @@ class ProjectGroupLink < ApplicationRecord
 
   validates :project_id, presence: true
   validates :group, presence: true
-  validates :group_id, uniqueness: { scope: [:project_id], message: "already shared with this group" }
+  validates :group_id, uniqueness: { scope: [:project_id], message: _("already shared with this group") }
   validates :group_access, presence: true
   validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true
   validate :different_group
@@ -44,7 +44,7 @@ def different_group
     group_ids = project_group.ancestors.map(&:id).push(project_group.id)
 
     if group_ids.include?(self.group.id)
-      errors.add(:base, "Project cannot be shared with the group it is in or one of its ancestors.")
+      errors.add(:base, _("Project cannot be shared with the group it is in or one of its ancestors."))
     end
   end
 
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index cc5f12076534..3e28dc237821 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -11,7 +11,7 @@ def title
   end
 
   def description
-    'Asana - Teamwork without email'
+    s_('AsanaService|Asana - Teamwork without email')
   end
 
   def help
@@ -36,13 +36,13 @@ def fields
       {
         type: 'text',
         name: 'api_key',
-        placeholder: 'User Personal Access Token. User must have access to task, all comments will be attributed to this user.',
+        placeholder: s_('AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user.'),
         required: true
       },
       {
         type: 'text',
         name: 'restrict_to_branch',
-        placeholder: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.'
+        placeholder: s_('AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.')
       }
     ]
   end
@@ -73,7 +73,7 @@ def execute(data)
     project_name = project.full_name
 
     data[:commits].each do |commit|
-      push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} ):"
+      push_msg = s_("AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):") % { user: user, branch: branch, project_name: project_name, commit_url: commit[:url] }
       check_commit(commit[:message], push_msg)
     end
   end
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 71f5607dbdb9..dfeb21680a9e 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -31,15 +31,15 @@ def reset_password
   end
 
   def title
-    'Atlassian Bamboo CI'
+    s_('BambooService|Atlassian Bamboo CI')
   end
 
   def description
-    'A continuous integration and build server'
+    s_('BambooService|A continuous integration and build server')
   end
 
   def help
-    'You must set up automatic revision labeling and a repository trigger in Bamboo.'
+    s_('BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo.')
   end
 
   def self.to_param
@@ -49,11 +49,11 @@ def self.to_param
   def fields
     [
         { type: 'text', name: 'bamboo_url',
-          placeholder: 'Bamboo root URL like https://bamboo.example.com', required: true },
+          placeholder: s_('BambooService|Bamboo root URL like https://bamboo.example.com'), required: true },
         { type: 'text', name: 'build_key',
-          placeholder: 'Bamboo build plan key like KEY', required: true },
+          placeholder: s_('BambooService|Bamboo build plan key like KEY'), required: true },
         { type: 'text', name: 'username',
-          placeholder: 'A user with API access, if applicable' },
+          placeholder: s_('BambooService|A user with API access, if applicable') },
         { type: 'password', name: 'password' }
     ]
   end
diff --git a/app/models/project_services/discord_service.rb b/app/models/project_services/discord_service.rb
index 21afd14dbffb..405676792de9 100644
--- a/app/models/project_services/discord_service.rb
+++ b/app/models/project_services/discord_service.rb
@@ -4,11 +4,11 @@
 
 class DiscordService < ChatNotificationService
   def title
-    "Discord Notifications"
+    s_("DiscordService|Discord Notifications")
   end
 
   def description
-    "Receive event notifications in Discord"
+    s_("DiscordService|Receive event notifications in Discord")
   end
 
   def self.to_param
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index fb73d430fb17..45de64a9990d 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -7,11 +7,11 @@ class EmailsOnPushService < Service
   validates :recipients, presence: true, if: :valid_recipients?
 
   def title
-    'Emails on push'
+    s_('EmailsOnPushService|Emails on push')
   end
 
   def description
-    'Email the commits and diff of each push to a list of recipients.'
+    s_('EmailsOnPushService|Email the commits and diff of each push to a list of recipients.')
   end
 
   def self.to_param
@@ -45,11 +45,11 @@ def disable_diffs?
   def fields
     domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ")
     [
-      { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer",
-        help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." },
-      { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs",
-        help: "Don't include possibly sensitive code diffs in notification body." },
-      { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }
+      { type: 'checkbox', name: 'send_from_committer_email', title: s_("EmailsOnPushService|Send from committer"),
+        help: s_("EmailsOnPushService|Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. %{domains}).") % { domains: domains } },
+      { type: 'checkbox', name: 'disable_diffs', title: s_("EmailsOnPushService|Disable code diffs"),
+        help: s_("EmailsOnPushService|Don't include possibly sensitive code diffs in notification body.") },
+      { type: 'textarea', name: 'recipients', placeholder: s_('EmailsOnPushService|Emails separated by whitespace') }
     ]
   end
 end
diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb
index d2835c6ac827..593ce69b0fda 100644
--- a/app/models/project_services/external_wiki_service.rb
+++ b/app/models/project_services/external_wiki_service.rb
@@ -6,11 +6,11 @@ class ExternalWikiService < Service
   validates :external_wiki_url, presence: true, public_url: true, if: :activated?
 
   def title
-    'External Wiki'
+    s_('ExternalWikiService|External Wiki')
   end
 
   def description
-    'Replaces the link to the internal wiki with a link to an external wiki.'
+    s_('ExternalWikiService|Replaces the link to the internal wiki with a link to an external wiki.')
   end
 
   def self.to_param
@@ -19,7 +19,7 @@ def self.to_param
 
   def fields
     [
-      { type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki', required: true }
+      { type: 'text', name: 'external_wiki_url', placeholder: s_('ExternalWikiService|The URL of the external Wiki'), required: true }
     ]
   end
 
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 76624263aaba..094488cb431b 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -9,7 +9,7 @@ def title
   end
 
   def description
-    'Flowdock is a collaboration web app for technical teams.'
+    s_('FlowdockService|Flowdock is a collaboration web app for technical teams.')
   end
 
   def self.to_param
@@ -18,7 +18,7 @@ def self.to_param
 
   def fields
     [
-      { type: 'text', name: 'token', placeholder: 'Flowdock Git source token', required: true }
+      { type: 'text', name: 'token', placeholder: s_('FlowdockService|Flowdock Git source token'), required: true }
     ]
   end
 
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 81302c516c2f..ebf28dc842c5 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -11,7 +11,7 @@ class JiraService < IssueTrackerService
   validates :password, presence: true, if: :activated?
 
   validates :jira_issue_transition_id,
-            format: { with: Gitlab::Regex.jira_transition_id_regex, message: "transition ids can have only numbers which can be split with , or ;" },
+            format: { with: Gitlab::Regex.jira_transition_id_regex, message: s_("JiraService|transition ids can have only numbers which can be split with , or ;") },
             allow_blank: true
 
   # JIRA cloud version is deprecating authentication via username and password.
@@ -86,7 +86,7 @@ def description
     if self.properties && self.properties['description'].present?
       self.properties['description']
     else
-      'Jira issue tracker'
+      s_('JiraService|Jira issue tracker')
     end
   end
 
@@ -96,11 +96,11 @@ def self.to_param
 
   def fields
     [
-      { type: 'text', name: 'url', title: 'Web URL', placeholder: 'https://jira.example.com', required: true },
-      { type: 'text', name: 'api_url', title: 'JIRA API URL', placeholder: 'If different from Web URL' },
-      { type: 'text', name: 'username', title: 'Username or Email', placeholder: 'Use a username for server version and an email for cloud version', required: true },
-      { type: 'password', name: 'password', title: 'Password or API token', placeholder: 'Use a password for server version and an API token for cloud version', required: true },
-      { type: 'text', name: 'jira_issue_transition_id', title: 'Transition ID(s)', placeholder: 'Use , or ; to separate multiple transition IDs' }
+      { type: 'text', name: 'url', title: s_('JiraService|Web URL'), placeholder: 'https://jira.example.com', required: true },
+      { type: 'text', name: 'api_url', title: s_('JiraService|JIRA API URL'), placeholder: s_('JiraService|If different from Web URL') },
+      { type: 'text', name: 'username', title: s_('JiraService|Username or Email'), placeholder: s_('JiraService|Use a username for server version and an email for cloud version'), required: true },
+      { type: 'password', name: 'password', title: s_('JiraService|Password or API token'), placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'), required: true },
+      { type: 'text', name: 'jira_issue_transition_id', title: s_('JiraService|Transition ID(s)'), placeholder: s_('JiraService|Use , or ; to separate multiple transition IDs') }
     ]
   end
 
@@ -139,7 +139,7 @@ def close_issue(entity, external_issue)
 
   def create_cross_reference_note(mentioned, noteable, author)
     unless can_cross_reference?(noteable)
-      return "Events for #{noteable.model_name.plural.humanize(capitalize: false)} are disabled."
+      return s_("JiraService|Events for %{noteable_model_name} are disabled.") % { noteable_model_name: noteable.model_name.plural.humanize(capitalize: false) }
     end
 
     jira_issue = jira_request { client.Issue.find(mentioned.id) }
@@ -338,9 +338,9 @@ def reset_password?
   def self.event_description(event)
     case event
     when "merge_request", "merge_request_events"
-      "JIRA comments will be created when an issue gets referenced in a merge request."
+      s_("JiraService|JIRA comments will be created when an issue gets referenced in a merge request.")
     when "commit", "commit_events"
-      "JIRA comments will be created when an issue gets referenced in a commit."
+      s_("JiraService|JIRA comments will be created when an issue gets referenced in a commit.")
     end
   end
 end
diff --git a/app/models/project_services/pipelines_email_service.rb b/app/models/project_services/pipelines_email_service.rb
index d60a6a7efa32..7ba69370f144 100644
--- a/app/models/project_services/pipelines_email_service.rb
+++ b/app/models/project_services/pipelines_email_service.rb
@@ -10,11 +10,11 @@ def initialize_properties
   end
 
   def title
-    'Pipelines emails'
+    _('Pipelines emails')
   end
 
   def description
-    'Email the pipelines status to a list of recipients.'
+    _('Email the pipelines status to a list of recipients.')
   end
 
   def self.to_param
@@ -51,7 +51,7 @@ def fields
     [
       { type: 'textarea',
         name: 'recipients',
-        placeholder: 'Emails separated by comma',
+        placeholder: _('Emails separated by comma'),
         required: true },
       { type: 'checkbox',
         name: 'notify_only_broken_pipelines' }
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index 617e502b639b..c15993bdc062 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -11,7 +11,7 @@ def title
   end
 
   def description
-    'Project Management Software (Source Commits Endpoint)'
+    s_('PivotalTrackerService|Project Management Software (Source Commits Endpoint)')
   end
 
   def self.to_param
@@ -23,14 +23,14 @@ def fields
       {
         type: 'text',
         name: 'token',
-        placeholder: 'Pivotal Tracker API token.',
+        placeholder: s_('PivotalTrackerService|Pivotal Tracker API token.'),
         required: true
       },
       {
         type: 'text',
         name: 'restrict_to_branch',
-        placeholder: 'Comma-separated list of branches which will be ' \
-          'automatically inspected. Leave blank to include all branches.'
+        placeholder: s_('PivotalTrackerService|Comma-separated list of branches which will be ' \
+          'automatically inspected. Leave blank to include all branches.')
       }
     ]
   end
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
index 4e48c348b45a..0d35bab7f806 100644
--- a/app/models/project_services/pushover_service.rb
+++ b/app/models/project_services/pushover_service.rb
@@ -11,7 +11,7 @@ def title
   end
 
   def description
-    'Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.'
+    s_('PushoverService|Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.')
   end
 
   def self.to_param
@@ -20,15 +20,15 @@ def self.to_param
 
   def fields
     [
-      { type: 'text', name: 'api_key', placeholder: 'Your application key', required: true },
-      { type: 'text', name: 'user_key', placeholder: 'Your user key', required: true },
-      { type: 'text', name: 'device', placeholder: 'Leave blank for all active devices' },
+      { type: 'text', name: 'api_key', placeholder: s_('PushoverService|Your application key'), required: true },
+      { type: 'text', name: 'user_key', placeholder: s_('PushoverService|Your user key'), required: true },
+      { type: 'text', name: 'device', placeholder: s_('PushoverService|Leave blank for all active devices') },
       { type: 'select', name: 'priority', required: true, choices:
         [
-          ['Lowest Priority', -2],
-          ['Low Priority', -1],
-          ['Normal Priority', 0],
-          ['High Priority', 1]
+          [s_('PushoverService|Lowest Priority'), -2],
+          [s_('PushoverService|Low Priority'), -1],
+          [s_('PushoverService|Normal Priority'), 0],
+          [s_('PushoverService|High Priority'), 1]
         ],
         default_choice: 0 },
       { type: 'select', name: 'sound', choices:
@@ -73,15 +73,15 @@ def execute(data)
 
     message =
       if Gitlab::Git.blank_ref?(before)
-        "#{data[:user_name]} pushed new branch \"#{ref}\"."
+        s_("PushoverService|%{user_name} pushed new branch \"%{ref}\".") % { user_name: data[:user_name], ref: ref }
       elsif Gitlab::Git.blank_ref?(after)
-        "#{data[:user_name]} deleted branch \"#{ref}\"."
+        s_("PushoverService|%{user_name} deleted branch \"%{ref}\".") % { user_name: data[:user_name], ref: ref }
       else
-        "#{data[:user_name]} push to branch \"#{ref}\"."
+        s_("PushoverService|%{user_name} push to branch \"%{ref}\".") % { user_name: data[:user_name], ref: ref }
       end
 
     if data[:total_commits_count] > 0
-      message = [message, "Total commits count: #{data[:total_commits_count]}"].join("\n")
+      message = [message, s_("PushoverService|Total commits count: %{total_commits_count}") % { total_commits_count: data[:total_commits_count] }].join("\n")
     end
 
     pushover_data = {
@@ -92,7 +92,7 @@ def execute(data)
       title: "#{project.full_name}",
       message: message,
       url: data[:project][:web_url],
-      url_title: "See project #{project.full_name}"
+      url_title: s_("PushoverService|See project %{project_full_name}") % { project_full_name: project.full_name }
     }
 
     # Sound parameter MUST NOT be sent to API if not selected
diff --git a/app/models/u2f_registration.rb b/app/models/u2f_registration.rb
index b46454623143..81415eb383b2 100644
--- a/app/models/u2f_registration.rb
+++ b/app/models/u2f_registration.rb
@@ -19,7 +19,7 @@ def self.register(user, app_id, params, challenges)
                           user: user,
                           name: params[:name])
     rescue JSON::ParserError, NoMethodError, ArgumentError
-      registration.errors.add(:base, 'Your U2F device did not send a valid JSON response.')
+      registration.errors.add(:base, _('Your U2F device did not send a valid JSON response.'))
     rescue U2F::Error => e
       registration.errors.add(:base, e.message)
     end
diff --git a/app/models/upload.rb b/app/models/upload.rb
index 9bffdcdb2e7c..ca74f16b3b88 100644
--- a/app/models/upload.rb
+++ b/app/models/upload.rb
@@ -45,7 +45,7 @@ def finalize_fast_destroy(keys)
   end
 
   def absolute_path
-    raise ObjectStorage::RemoteStoreError, "Remote object has no absolute path." unless local?
+    raise ObjectStorage::RemoteStoreError, _("Remote object has no absolute path.") unless local?
     return path unless relative_path?
 
     uploader_class.absolute_path(self)
@@ -71,10 +71,10 @@ def exist?
     # Help sysadmins find missing upload files
     if persisted? && !exist
       if Gitlab::Sentry.enabled?
-        Raven.capture_message("Upload file does not exist", extra: self.attributes)
+        Raven.capture_message(_("Upload file does not exist"), extra: self.attributes)
       end
 
-      Gitlab::Metrics.counter(:upload_file_does_not_exist_total, 'The number of times an upload record could not find its file').increment
+      Gitlab::Metrics.counter(:upload_file_does_not_exist_total, _('The number of times an upload record could not find its file')).increment
     end
 
     exist
diff --git a/app/models/user.rb b/app/models/user.rb
index b08ac638949b..551eb58a4deb 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -517,7 +517,7 @@ def reference_pattern
     def ghost
       email = 'ghost%s@example.com'
       unique_internal(where(ghost: true), 'ghost', email) do |u|
-        u.bio = 'This is a "Ghost User", created to hold all issues authored by users that have since been deleted. This user cannot be removed.'
+        u.bio = _('This is a "Ghost User", created to hold all issues authored by users that have since been deleted. This user cannot be removed.')
         u.name = 'Ghost User'
       end
     end
@@ -622,32 +622,32 @@ def two_factor_u2f_enabled?
 
   def namespace_move_dir_allowed
     if namespace&.any_project_has_container_registry_tags?
-      errors.add(:username, 'cannot be changed if a personal project has container registry tags.')
+      errors.add(:username, _('cannot be changed if a personal project has container registry tags.'))
     end
   end
 
   def unique_email
     if !emails.exists?(email: email) && Email.exists?(email: email)
-      errors.add(:email, 'has already been taken')
+      errors.add(:email, _('has already been taken'))
     end
   end
 
   def owns_notification_email
     return if temp_oauth_email?
 
-    errors.add(:notification_email, "is not an email you own") unless all_emails.include?(notification_email)
+    errors.add(:notification_email, _("is not an email you own")) unless all_emails.include?(notification_email)
   end
 
   def owns_public_email
     return if public_email.blank?
 
-    errors.add(:public_email, "is not an email you own") unless all_emails.include?(public_email)
+    errors.add(:public_email, _("is not an email you own")) unless all_emails.include?(public_email)
   end
 
   def owns_commit_email
     return if read_attribute(:commit_email).blank?
 
-    errors.add(:commit_email, "is not an email you own") unless verified_emails.include?(commit_email)
+    errors.add(:commit_email, _("is not an email you own")) unless verified_emails.include?(commit_email)
   end
 
   # Define commit_email-related attribute methods explicitly instead of relying
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index cfd630ae8e21..4f401acccf9a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -132,6 +132,12 @@ msgstr ""
 msgid "%{label_for_message} unavailable"
 msgstr ""
 
+msgid "%{level_name} is not allowed in a %{group_level_name} group."
+msgstr ""
+
+msgid "%{level_name} is not allowed since the fork source project has lower visibility."
+msgstr ""
+
 msgid "%{level_name} visibility has been restricted by the administrator."
 msgstr ""
 
@@ -203,6 +209,12 @@ msgstr ""
 msgid "%{user_name} profile page"
 msgstr ""
 
+msgid "'%{level}' is not a valid visibility level"
+msgstr ""
+
+msgid "'%{source}' is not a import source"
+msgstr ""
+
 msgid "(external source)"
 msgstr ""
 
@@ -978,6 +990,18 @@ msgstr ""
 msgid "Artifacts"
 msgstr ""
 
+msgid "AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):"
+msgstr ""
+
+msgid "AsanaService|Asana - Teamwork without email"
+msgstr ""
+
+msgid "AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches."
+msgstr ""
+
+msgid "AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user."
+msgstr ""
+
 msgid "Ask your group maintainer to set up a group Runner."
 msgstr ""
 
@@ -1221,6 +1245,24 @@ msgstr ""
 msgid "Badges|e.g. %{exampleUrl}"
 msgstr ""
 
+msgid "BambooService|A continuous integration and build server"
+msgstr ""
+
+msgid "BambooService|A user with API access, if applicable"
+msgstr ""
+
+msgid "BambooService|Atlassian Bamboo CI"
+msgstr ""
+
+msgid "BambooService|Bamboo build plan key like KEY"
+msgstr ""
+
+msgid "BambooService|Bamboo root URL like https://bamboo.example.com"
+msgstr ""
+
+msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
+msgstr ""
+
 msgid "Be careful. Changing the project's namespace can have unintended side effects."
 msgstr ""
 
@@ -1515,6 +1557,9 @@ msgstr ""
 msgid "Cannot modify managed Kubernetes cluster"
 msgstr ""
 
+msgid "Cannot refer to a group milestone by an internal id!"
+msgstr ""
+
 msgid "Cannot render the image. Maximum character count (%{charLimit}) has been exceeded."
 msgstr ""
 
@@ -2600,6 +2645,9 @@ msgstr ""
 msgid "Could not authorize chat nickname. Try again!"
 msgstr ""
 
+msgid "Could not change HEAD: branch '%{branch}' does not exist"
+msgstr ""
+
 msgid "Could not connect to FogBugz, check your URL"
 msgstr ""
 
@@ -3109,6 +3157,12 @@ msgstr ""
 msgid "Discard draft"
 msgstr ""
 
+msgid "DiscordService|Discord Notifications"
+msgstr ""
+
+msgid "DiscordService|Receive event notifications in Discord"
+msgstr ""
+
 msgid "Discover projects, groups and snippets. Share your projects with others"
 msgstr ""
 
@@ -3235,6 +3289,9 @@ msgstr ""
 msgid "Email patch"
 msgstr ""
 
+msgid "Email the pipelines status to a list of recipients."
+msgstr ""
+
 msgid "EmailError|It appears that the email is blank. Make sure your reply is at the top of the email, we can't process inline replies."
 msgstr ""
 
@@ -3262,6 +3319,30 @@ msgstr ""
 msgid "Emails"
 msgstr ""
 
+msgid "Emails separated by comma"
+msgstr ""
+
+msgid "EmailsOnPushService|Disable code diffs"
+msgstr ""
+
+msgid "EmailsOnPushService|Don't include possibly sensitive code diffs in notification body."
+msgstr ""
+
+msgid "EmailsOnPushService|Email the commits and diff of each push to a list of recipients."
+msgstr ""
+
+msgid "EmailsOnPushService|Emails on push"
+msgstr ""
+
+msgid "EmailsOnPushService|Emails separated by whitespace"
+msgstr ""
+
+msgid "EmailsOnPushService|Send from committer"
+msgstr ""
+
+msgid "EmailsOnPushService|Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. %{domains})."
+msgstr ""
+
 msgid "Embed"
 msgstr ""
 
@@ -3751,6 +3832,15 @@ msgstr ""
 msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
 msgstr ""
 
+msgid "ExternalWikiService|External Wiki"
+msgstr ""
+
+msgid "ExternalWikiService|Replaces the link to the internal wiki with a link to an external wiki."
+msgstr ""
+
+msgid "ExternalWikiService|The URL of the external Wiki"
+msgstr ""
+
 msgid "Facebook"
 msgstr ""
 
@@ -3760,12 +3850,18 @@ msgstr ""
 msgid "Failed Jobs"
 msgstr ""
 
+msgid "Failed create wiki"
+msgstr ""
+
 msgid "Failed to change the owner"
 msgstr ""
 
 msgid "Failed to check related branches."
 msgstr ""
 
+msgid "Failed to create repository via gitlab-shell"
+msgstr ""
+
 msgid "Failed to create resources"
 msgstr ""
 
@@ -3921,6 +4017,12 @@ msgstr ""
 msgid "FirstPushedBy|pushed by"
 msgstr ""
 
+msgid "FlowdockService|Flowdock Git source token"
+msgstr ""
+
+msgid "FlowdockService|Flowdock is a collaboration web app for technical teams."
+msgstr ""
+
 msgid "FogBugz Email"
 msgstr ""
 
@@ -4607,6 +4709,9 @@ msgstr ""
 msgid "Incompatible Project"
 msgstr ""
 
+msgid "Incompatible options set!"
+msgstr ""
+
 msgid "Indicates whether this runner can pick jobs without tags"
 msgstr ""
 
@@ -4682,6 +4787,9 @@ msgstr ""
 msgid "Invalid Login or password"
 msgstr ""
 
+msgid "Invalid feature"
+msgstr ""
+
 msgid "Invalid file."
 msgstr ""
 
@@ -4691,6 +4799,9 @@ msgstr ""
 msgid "Invalid pin code"
 msgstr ""
 
+msgid "Invalid repository path"
+msgstr ""
+
 msgid "Invalid two-factor code."
 msgstr ""
 
@@ -4751,6 +4862,48 @@ msgstr ""
 msgid "January"
 msgstr ""
 
+msgid "JiraService|Events for %{noteable_model_name} are disabled."
+msgstr ""
+
+msgid "JiraService|If different from Web URL"
+msgstr ""
+
+msgid "JiraService|JIRA API URL"
+msgstr ""
+
+msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgstr ""
+
+msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgstr ""
+
+msgid "JiraService|Jira issue tracker"
+msgstr ""
+
+msgid "JiraService|Password or API token"
+msgstr ""
+
+msgid "JiraService|Transition ID(s)"
+msgstr ""
+
+msgid "JiraService|Use , or ; to separate multiple transition IDs"
+msgstr ""
+
+msgid "JiraService|Use a password for server version and an API token for cloud version"
+msgstr ""
+
+msgid "JiraService|Use a username for server version and an email for cloud version"
+msgstr ""
+
+msgid "JiraService|Username or Email"
+msgstr ""
+
+msgid "JiraService|Web URL"
+msgstr ""
+
+msgid "JiraService|transition ids can have only numbers which can be split with , or ;"
+msgstr ""
+
 msgid "Job"
 msgstr ""
 
@@ -5187,6 +5340,9 @@ msgstr ""
 msgid "Maximum job timeout"
 msgstr ""
 
+msgid "Maximum job timeout has a value which could not be accepted"
+msgstr ""
+
 msgid "Maximum push size (MB)"
 msgstr ""
 
@@ -6133,6 +6289,9 @@ msgstr ""
 msgid "Pipelines charts"
 msgstr ""
 
+msgid "Pipelines emails"
+msgstr ""
+
 msgid "Pipelines for last month"
 msgstr ""
 
@@ -6256,6 +6415,15 @@ msgstr ""
 msgid "Pipeline|with stages"
 msgstr ""
 
+msgid "PivotalTrackerService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches."
+msgstr ""
+
+msgid "PivotalTrackerService|Pivotal Tracker API token."
+msgstr ""
+
+msgid "PivotalTrackerService|Project Management Software (Source Commits Endpoint)"
+msgstr ""
+
 msgid "Plain diff"
 msgstr ""
 
@@ -6667,6 +6835,9 @@ msgstr ""
 msgid "Project avatar"
 msgstr ""
 
+msgid "Project cannot be shared with the group it is in or one of its ancestors."
+msgstr ""
+
 msgid "Project configuration, including services"
 msgstr ""
 
@@ -6928,6 +7099,45 @@ msgstr ""
 msgid "Push to create a project"
 msgstr ""
 
+msgid "PushoverService|%{user_name} deleted branch \"%{ref}\"."
+msgstr ""
+
+msgid "PushoverService|%{user_name} push to branch \"%{ref}\"."
+msgstr ""
+
+msgid "PushoverService|%{user_name} pushed new branch \"%{ref}\"."
+msgstr ""
+
+msgid "PushoverService|High Priority"
+msgstr ""
+
+msgid "PushoverService|Leave blank for all active devices"
+msgstr ""
+
+msgid "PushoverService|Low Priority"
+msgstr ""
+
+msgid "PushoverService|Lowest Priority"
+msgstr ""
+
+msgid "PushoverService|Normal Priority"
+msgstr ""
+
+msgid "PushoverService|Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop."
+msgstr ""
+
+msgid "PushoverService|See project %{project_full_name}"
+msgstr ""
+
+msgid "PushoverService|Total commits count: %{total_commits_count}"
+msgstr ""
+
+msgid "PushoverService|Your application key"
+msgstr ""
+
+msgid "PushoverService|Your user key"
+msgstr ""
+
 msgid "Quick actions can be used in the issues description and comment boxes."
 msgstr ""
 
@@ -7014,6 +7224,9 @@ msgstr ""
 msgid "Remind later"
 msgstr ""
 
+msgid "Remote object has no absolute path."
+msgstr ""
+
 msgid "Remove"
 msgstr ""
 
@@ -8427,6 +8640,9 @@ msgstr ""
 msgid "The name %{entryName} is already taken in this directory."
 msgstr ""
 
+msgid "The number of times an upload record could not find its file"
+msgstr ""
+
 msgid "The passphrase required to decrypt the private key. This is optional and the value is encrypted at rest."
 msgstr ""
 
@@ -8454,12 +8670,18 @@ msgstr ""
 msgid "The project can be accessed without any authentication."
 msgstr ""
 
+msgid "The project is still being deleted. Please try again later."
+msgstr ""
+
 msgid "The project was successfully forked."
 msgstr ""
 
 msgid "The project was successfully imported."
 msgstr ""
 
+msgid "The remote mirror took to long to complete."
+msgstr ""
+
 msgid "The remote repository is being updated..."
 msgstr ""
 
@@ -8559,6 +8781,9 @@ msgstr ""
 msgid "There are no unstaged changes"
 msgstr ""
 
+msgid "There is already a repository with that name on disk"
+msgstr ""
+
 msgid "There was an error loading users activity calendar."
 msgstr ""
 
@@ -8655,6 +8880,9 @@ msgstr ""
 msgid "This group does not provide any group Runners yet."
 msgstr ""
 
+msgid "This is a \"Ghost User\", created to hold all issues authored by users that have since been deleted. This user cannot be removed."
+msgstr ""
+
 msgid "This is a confidential issue."
 msgstr ""
 
@@ -9196,6 +9424,12 @@ msgstr ""
 msgid "Unfortunately, your email message to GitLab could not be processed."
 msgstr ""
 
+msgid "Unknown encryption strategy: %{encrypted_strategy}!"
+msgstr ""
+
+msgid "Unknown format"
+msgstr ""
+
 msgid "Unlock"
 msgstr ""
 
@@ -9292,6 +9526,9 @@ msgstr ""
 msgid "Upload file"
 msgstr ""
 
+msgid "Upload file does not exist"
+msgstr ""
+
 msgid "Upload object map"
 msgstr ""
 
@@ -9457,6 +9694,9 @@ msgstr ""
 msgid "Users were successfully added."
 msgstr ""
 
+msgid "Using required encryption strategy when encrypted field is missing!"
+msgstr ""
+
 msgid "Validate"
 msgstr ""
 
@@ -10038,6 +10278,9 @@ msgstr ""
 msgid "Your Todos"
 msgstr ""
 
+msgid "Your U2F device did not send a valid JSON response."
+msgstr ""
+
 msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
 msgstr ""
 
@@ -10119,6 +10362,12 @@ msgstr ""
 msgid "allowed to fail"
 msgstr ""
 
+msgid "already being used for another group or project milestone."
+msgstr ""
+
+msgid "already shared with this group"
+msgstr ""
+
 msgid "among other things"
 msgstr ""
 
@@ -10131,6 +10380,15 @@ msgstr ""
 msgid "branch name"
 msgstr ""
 
+msgid "cannot be changed if a personal project has container registry tags."
+msgstr ""
+
+msgid "cannot be enabled unless all domains have TLS certificates"
+msgstr ""
+
+msgid "cannot include leading slash or directory traversal."
+msgstr ""
+
 msgid "commented on %{link_to_project}"
 msgstr ""
 
@@ -10174,9 +10432,15 @@ msgstr[1] ""
 msgid "done"
 msgstr ""
 
+msgid "element is not a hierarchy"
+msgstr ""
+
 msgid "enabled"
 msgstr ""
 
+msgid "encrypted: needs to be a :required, :optional or :migrating!"
+msgstr ""
+
 msgid "error"
 msgstr ""
 
@@ -10210,6 +10474,9 @@ msgstr ""
 msgid "group"
 msgstr ""
 
+msgid "has already been taken"
+msgstr ""
+
 msgid "here"
 msgstr ""
 
@@ -10237,6 +10504,9 @@ msgstr ""
 msgid "is not a valid X509 certificate."
 msgstr ""
 
+msgid "is not an email you own"
+msgstr ""
+
 msgid "issue boards"
 msgstr ""
 
@@ -10269,6 +10539,9 @@ msgid_plural "merge requests"
 msgstr[0] ""
 msgstr[1] ""
 
+msgid "milestone should belong either to a project or a group."
+msgstr ""
+
 msgid "missing"
 msgstr ""
 
@@ -10476,9 +10749,15 @@ msgstr ""
 msgid "mrWidget|to be merged automatically when the pipeline succeeds"
 msgstr ""
 
+msgid "must be greater than start date"
+msgstr ""
+
 msgid "n/a"
 msgstr ""
 
+msgid "needs to be beetween 10 minutes and 1 month"
+msgstr ""
+
 msgid "new merge request"
 msgstr ""
 
@@ -10566,6 +10845,9 @@ msgstr ""
 msgid "source diff"
 msgstr ""
 
+msgid "specified top is not part of the tree"
+msgstr ""
+
 msgid "spendCommand|%{slash_command} will update the sum of the time spent."
 msgstr ""
 
-- 
GitLab