Skip to content

Commit

Permalink
Add parameter to iOS Lint to make failing on extra strings optional (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
iangmaia authored Feb 19, 2025
2 parents 9c1a377 + e90cd9b commit 9b130c7
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 11 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

### New Features

_None_
- The `ios_lint_localizations` action now accepts a `fail_on_strings_not_in_base_language` parameter (defaulting to `true`) to control whether to report violations when finding strings in translations that are not present in the base language. [#631]

### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def self.run_linter(params)
helper.run(
input_dir: resolve_path(params[:input_dir]),
base_lang: params[:base_lang],
only_langs: params[:only_langs]
only_langs: params[:only_langs],
fail_on_strings_not_in_base_language: params[:fail_on_strings_not_in_base_language]
)
end

Expand Down Expand Up @@ -183,6 +184,14 @@ def self.available_options
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,12 @@ def install_swiftgen!
#
# @param [String] input_dir The path (ideally absolute) to the directory containing the `.lproj` folders to parse
# @param [String] base_lang The code name (i.e the basename of one of the `.lproj` folders) of the locale to use as the baseline
# @param [String] fail_on_strings_not_in_base_language Whether to fail on strings not in base language
# @return [Hash<String, Array<String>>] A hash of violations, keyed by language code, whose values are the list of violation messages for that language
#
def run(input_dir:, base_lang: DEFAULT_BASE_LANG, only_langs: nil)
def run(input_dir:, base_lang: DEFAULT_BASE_LANG, only_langs: nil, fail_on_strings_not_in_base_language: true)
check_swiftgen_installed || install_swiftgen!
find_diffs(input_dir: input_dir, base_lang: base_lang, only_langs: only_langs)
find_diffs(input_dir: input_dir, base_lang: base_lang, only_langs: only_langs, fail_on_strings_not_in_base_language: fail_on_strings_not_in_base_language)
end

##################
Expand Down Expand Up @@ -160,11 +161,12 @@ def placeholder_types_for_keys(dir, lang)
# @param [String] input_dir The directory where the `.lproj` folders to scan are located
# @param [String] base_lang The base language used as source of truth that all other languages will be compared against
# @param [Array<String>] only_langs The list of languages to limit the generation for. Useful to focus only on a couple of issues or just one language
# @param [Boolean] fail_on_strings_not_in_base_language Whether to fail on strings not in base language
# @return [Hash<String, Array<String>>] A hash of violations, keyed by language code, whose values are the list of violation messages for that language
#
# @note The returned Hash contains keys only for locales with violations. Locales parsed but without any violations found will not appear in the resulting hash.
#
def find_diffs(input_dir:, base_lang:, only_langs: nil)
def find_diffs(input_dir:, base_lang:, only_langs: nil, fail_on_strings_not_in_base_language: true)
Dir.mktmpdir('a8c-lint-translations-') do |tmpdir|
# Run SwiftGen
langs = only_langs.nil? ? nil : (only_langs + [base_lang]).uniq
Expand All @@ -181,8 +183,8 @@ def find_diffs(input_dir:, base_lang:, only_langs: nil)
next nil if params_for_lang.nil? || params_for_lang.empty?

violations = params_for_lang.map do |key, param_types|
next "`#{key}` was unexpected, as it is not present in the base locale." if params_for_base_lang[key].nil?
next "`#{key}` expected placeholders for #{params_for_base_lang[key]} but found #{param_types} instead." if params_for_base_lang[key] != param_types
next "`#{key}` was unexpected, as it is not present in the base locale." if params_for_base_lang[key].nil? && fail_on_strings_not_in_base_language
next "`#{key}` expected placeholders for #{params_for_base_lang[key]} but found #{param_types} instead." if !params_for_base_lang[key].nil? && params_for_base_lang[key] != param_types
end.compact

[lang, violations] unless violations.empty?
Expand Down
30 changes: 26 additions & 4 deletions spec/ios_lint_localizations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,14 @@
# Helper function that DRYs the code running each test.
#
# @param [String] data_file The name, without extension or "test-lint-ios-" prefix, of the YML file containing the test input and expected output.
# @param [Bool|nil] check_duplicate_keys If `nil`, the test will run the action with the default `check_duplicate_keys` parameter value.
# If a `Bool` value is given, it will pass that.
# Using either `Bool` or `nil` adds some cruft, but lets us validate the action default behavior, so it doesn't change unexpectedly.
# @param [Boolean, nil] check_duplicate_keys If `nil`, the test will run the action with the default `check_duplicate_keys` parameter value.
# If a `Boolean` value is given, it will pass that.
# Using either `Boolean` or `nil` adds some cruft, but lets us validate the action default behavior, so it doesn't change unexpectedly.
# @param [Boolean, nil] fail_on_strings_not_in_base_language If `nil`, the test will run the action with the default `fail_on_strings_not_in_base_language` parameter value.
# If a `Boolean` value is given, it will pass that.
# Controls whether to report violations when finding strings in translations that are not present in the base language.
#
def run_l10n_linter_test(data_file:, check_duplicate_keys: nil)
def run_l10n_linter_test(data_file:, check_duplicate_keys: nil, fail_on_strings_not_in_base_language: nil)
# Arrange: Prepare test files
test_file = File.join(File.dirname(__FILE__), 'test-data', 'translations', 'ios_lint_localizations', "#{data_file}.yaml")
yml = YAML.load_file(test_file)
Expand All @@ -86,6 +89,7 @@ def run_l10n_linter_test(data_file:, check_duplicate_keys: nil)
base_lang: 'en'
}
parameters[:check_duplicate_keys] = check_duplicate_keys unless check_duplicate_keys.nil?
parameters[:fail_on_strings_not_in_base_language] = fail_on_strings_not_in_base_language unless fail_on_strings_not_in_base_language.nil?
result = run_described_fastlane_action(parameters)

# Assert
Expand Down Expand Up @@ -205,5 +209,23 @@ def run_l10n_linter_test(data_file:, check_duplicate_keys: nil)

expect(result).to eq({ 'fr' => ['`key3` expected placeholders for [Int] but found [] instead.'] })
end

it 'fails on strings not in base language by default' do
run_l10n_linter_test(data_file: 'extra-strings-in-translations-error')
end

it 'does not report strings not in base language when fail_on_strings_not_in_base_language is false' do
run_l10n_linter_test(
data_file: 'extra-strings-in-translations-no-error',
fail_on_strings_not_in_base_language: false
)
end

it 'does report strings not in base language when fail_on_strings_not_in_base_language is true' do
run_l10n_linter_test(
data_file: 'extra-strings-in-translations-error',
fail_on_strings_not_in_base_language: true
)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
test_data:
en: |-
"base_string" = "This is in the base language";
fr: |-
"base_string" = "This is in French";
"extra_string" = "This string only exists in French";
result:
fr:
- '`extra_string` was unexpected, as it is not present in the base locale.'
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
test_data:
en: |-
"base_string" = "This is in the base language";
fr: |-
"base_string" = "This is in French";
"extra_string" = "This string only exists in French";
result: {}

0 comments on commit 9b130c7

Please sign in to comment.