Class: Fastlane::Actions::IosLintLocalizationsAction

Inherits:
Action
  • Object
show all
Defined in:
lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb

Constant Summary collapse

RETRY_MESSAGE =
<<~MSG
  Inconsistencies found during Localization linting.
  You need to fix them before continuing. From this point on, you should either:

  - Cancel this lane (reply 'No' below), then work with polyglots in #i18n
    to fix those directly in GlotPress – by rejecting the inconsistent
    translations, or by submitting a fixed copy. Rerun the lane when everything
    has been fixed.

    This is the recommended way to go, as it will fix the issues at their source.

  - Or manually edit the `Localizable.strings` files to fix the inconsistencies
    locally, commit them, then reply 'Yes' below to re-lint and validate that all
    inconsistencies have been fixed locally so you can continue with the build.

    This is only a workaround to allow you to submit a build if translators are
    not available to help you fix the issues in GlotPress in time. You will still
    need to let the translators know that they will need to fix those copies
    at some point before the next build to fix the root of the issue.

  Did you fix the `.strings` files locally and want to lint them again?
MSG
ABORT_MESSAGE =
<<~MSG
  Inconsistencies found during Localization linting. Aborting.
MSG

Documentation collapse

Class Method Summary collapse

Class Method Details

.authorsObject



210
211
212
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 210

def self.authors
  ['Automattic']
end

.available_optionsObject



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 123

def self.available_options
  [
    FastlaneCore::ConfigItem.new(
      key: :install_path,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_INSTALL_PATH',
      description: 'The path where to install the SwiftGen tooling needed to run the linting process. If a relative path, should be relative to your repo_root',
      type: String,
      optional: true,
      default_value: "vendor/swiftgen/#{Fastlane::Helper::Ios::L10nLinterHelper::SWIFTGEN_VERSION}"
    ),
    FastlaneCore::ConfigItem.new(
      key: :version,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_SWIFTGEN_VERSION',
      description: 'The version of SwiftGen to install and use for linting',
      type: String,
      optional: true,
      default_value: Fastlane::Helper::Ios::L10nLinterHelper::SWIFTGEN_VERSION
    ),
    FastlaneCore::ConfigItem.new(
      key: :input_dir,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_INPUT_DIR',
      description: 'The path to the directory containing the .lproj folders to lint, relative to your git repo root',
      type: String,
      optional: false
    ),
    FastlaneCore::ConfigItem.new(
      key: :base_lang,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_BASE_LANG',
      description: 'The language that should be used as the base language that every other language will be compared against',
      type: String,
      optional: true,
      default_value: Fastlane::Helper::Ios::L10nLinterHelper::DEFAULT_BASE_LANG
    ),
    FastlaneCore::ConfigItem.new(
      key: :only_langs,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_ONLY_LANGS',
      description: 'The list of languages to limit the analysis to',
      type: Array,
      optional: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :abort_on_violations,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_ABORT',
      description: 'Should we abort the rest of the lane with a global error if any violations are found?',
      optional: true,
      default_value: true,
      type: Boolean
    ),
    FastlaneCore::ConfigItem.new(
      key: :allow_retry,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_ALLOW_RETRY',
      description: 'If any violations are found, show an interactive prompt allowing the user to manually fix the issues locally and retry the linting',
      optional: true,
      default_value: false,
      type: Boolean
    ),
    FastlaneCore::ConfigItem.new(
      key: :check_duplicate_keys,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_CHECK_DUPLICATE_KEYS',
      description: 'Checks the input files for duplicate keys',
      optional: true,
      default_value: true,
      type: Boolean
    ),
    FastlaneCore::ConfigItem.new(
      key: :fail_on_strings_not_in_base_language,
      env_name: 'FL_IOS_LINT_TRANSLATIONS_FAIL_ON_STRINGS_NOT_IN_BASE_LANGUAGE',
      description: 'Should we report violations when finding strings in translations that are not present in the base language',
      optional: true,
      default_value: true,
      type: Boolean
    ),
  ]
end

.descriptionObject



115
116
117
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 115

def self.description
  'Lint the different *.lproj/.strings files for each locale and ensure the parameter placeholders are consistent.'
end

.detailsObject



119
120
121
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 119

def self.details
  'Compares the translations against a base language to find potential mismatches for the %s/%d/… parameter placeholders between locales.'
end

.find_duplicated_keys(params) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 51

def self.find_duplicated_keys(params)
  duplicate_keys = {}

  files_to_lint = Dir.glob('*.lproj/Localizable.strings', base: params[:input_dir])
  files_to_lint.each do |file|
    language = File.basename(File.dirname(file), '.lproj')
    path = File.join(params[:input_dir], file)

    file_type = Fastlane::Helper::Ios::L10nHelper.strings_file_type(path: path)
    if file_type == :text
      duplicates = Fastlane::Helper::Ios::StringsFileValidationHelper.find_duplicated_keys(file: path)
      duplicate_keys[language] = duplicates.map { |key, value| "`#{key}` was found at multiple lines: #{value.join(', ')}" } unless duplicates.empty?
    else
      UI.important <<~WRONG_FORMAT
        File `#{path}` is in #{file_type} format, while finding duplicate keys only make sense on files that are in ASCII-plist format.
        Since your files are in #{file_type} format, you should probably disable the `check_duplicate_keys` option from this `#{action_name}` call.
      WRONG_FORMAT
    end
  end

  duplicate_keys
end

.is_supported?(platform) ⇒ Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 214

def self.is_supported?(platform)
  %i[ios mac].include?(platform)
end

.outputObject



198
199
200
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 198

def self.output
  nil
end

.repo_rootObject



101
102
103
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 101

def self.repo_root
  @repo_root || `git rev-parse --show-toplevel`.chomp
end

.report(violations:, base_lang:) ⇒ Object



45
46
47
48
49
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 45

def self.report(violations:, base_lang:)
  violations.each do |lang, lang_violations|
    UI.error "Inconsistencies found between '#{base_lang}' and '#{lang}':\n\n#{lang_violations.join("\n")}\n"
  end
end

.resolve_path(path) ⇒ Object

If the path is relative, makes the path absolute by resolving it relative to the repository’s root. If the path is already absolute, it will not affect it and return it as-is.



107
108
109
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 107

def self.resolve_path(path)
  File.absolute_path(path, repo_root)
end

.return_typeObject



202
203
204
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 202

def self.return_type
  :hash
end

.return_valueObject



206
207
208
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 206

def self.return_value
  'A hash, keyed by language code, whose values are arrays of violations found for that language'
end

.run(params) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 6

def self.run(params)
  violations = nil

  loop do
    violations = run_linter(params)
    violations.default = [] # Set the default value for when querying a missing key

    if params[:check_duplicate_keys]
      find_duplicated_keys(params).each do |language, duplicates|
        violations[language] += duplicates
      end
    end

    report(violations: violations, base_lang: params[:base_lang])
    break unless !violations.empty? && params[:allow_retry] && UI.confirm(RETRY_MESSAGE)
  end

  UI.abort_with_message!(ABORT_MESSAGE) if !violations.empty? && params[:abort_on_violations]

  violations
end

.run_linter(params) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb', line 28

def self.run_linter(params)
  UI.message 'Linting localizations for parameter placeholders consistency...'

  require_relative '../../helper/ios/ios_l10n_linter_helper'
  helper = Fastlane::Helper::Ios::L10nLinterHelper.new(
    install_path: resolve_path(params[:install_path]),
    version: params[:version]
  )

  helper.run(
    input_dir: resolve_path(params[:input_dir]),
    base_lang: params[:base_lang],
    only_langs: params[:only_langs],
    fail_on_strings_not_in_base_language: params[:fail_on_strings_not_in_base_language]
  )
end