Skip to content

Commit 27ac9cb

Browse files
committed
Surface foreseeable stringsdict conversion failures as clean user errors
The helper raised bare `RuntimeError`s for input/config problems a user can fix — a missing or malformed `.stringsdict`/`.po`, colliding keys, a source entry with no `other` form, or a `.po` whose declared `nplurals` has drifted from the `PluralRules` table. fastlane treats a non-`Fastlane` `Error` as an internal crash, so these surfaced as a stack trace with a "report this bug" prompt instead of an actionable message — including the plural-count guard, which is precisely the signal to regenerate the table. Route them through `UI.user_error!` (the convention the other helpers follow), so they raise `FastlaneCore::Interface::FastlaneError` and fastlane prints them cleanly. `PluralRules::UnknownLocaleError` stays a plain error converted by the reverse action, keeping that module free of a UI dependency. The existing specs now assert the `FastlaneError` type so this can't regress to a bare `raise`.
1 parent a7b17fd commit 27ac9cb

2 files changed

Lines changed: 22 additions & 22 deletions

File tree

lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_stringsdict_helper.rb

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ class StringsdictHelper
5555
#
5656
# @param [String] path The path to the `.stringsdict` file.
5757
# @return [Hash] The parsed plist dictionary.
58-
# @raise [RuntimeError] If the file is missing or is not a plist dictionary.
58+
# @raise [FastlaneCore::Interface::FastlaneError] If the file is missing or is not a plist dictionary.
5959
def self.read(path:)
60-
raise "Stringsdict file not found: #{path}" unless File.exist?(path)
60+
UI.user_error!("Stringsdict file not found: #{path}") unless File.exist?(path)
6161

6262
data = Plist.parse_xml(path)
63-
raise "Invalid stringsdict file (expected a plist dictionary at the root): #{path}" unless data.is_a?(Hash)
63+
UI.user_error!("Invalid stringsdict file (expected a plist dictionary at the root): #{path}") unless data.is_a?(Hash)
6464

6565
data
6666
end
@@ -84,7 +84,7 @@ def self.write(data:, path:)
8484
# source `.stringsdict` files.
8585
# @param [String] output_path The `.pot` file to write.
8686
# @return [Integer] The number of plural entries written.
87-
# @raise [RuntimeError] If two entries would produce the same `msgctxt`.
87+
# @raise [FastlaneCore::Interface::FastlaneError] If two entries would produce the same `msgctxt`.
8888
def self.generate_pot(stringsdict_paths:, output_path:)
8989
po = GetText::PO.new
9090
po.order = :none
@@ -99,8 +99,8 @@ def self.generate_pot(stringsdict_paths:, output_path:)
9999
variables.each do |var_name, var_dict|
100100
context = context_for(key: key, variable: var_name, single_variable: single)
101101
if seen_contexts.key?(context)
102-
raise "Duplicate translation context '#{context}' generated from `#{path}` (also produced by " \
103-
"`#{seen_contexts[context]}`). Stringsdict keys must be unique across the files being converted."
102+
UI.user_error!("Duplicate translation context '#{context}' generated from `#{path}` (also produced by " \
103+
"`#{seen_contexts[context]}`). Stringsdict keys must be unique across the files being converted.")
104104
end
105105
seen_contexts[context] = path
106106
entries << build_pot_entry(context: context, var_dict: var_dict, key: key, variable: var_name)
@@ -130,8 +130,8 @@ def self.generate_pot(stringsdict_paths:, output_path:)
130130
# @return [Array<String>] Contexts present in the template for which the
131131
# `.po` had no usable translation (filled from English as fallback).
132132
# @raise [PluralRules::UnknownLocaleError] If the locale has no mapping.
133-
# @raise [RuntimeError] If a translated entry's form count doesn't match
134-
# the locale's expected plural-category count.
133+
# @raise [FastlaneCore::Interface::FastlaneError] If a translated entry's form count
134+
# doesn't match the locale's expected plural-category count.
135135
def self.generate_stringsdict_from_po(po_path:, template_path:, locale:, output_path:)
136136
template = read(path: template_path)
137137
po = parse_po(po_path)
@@ -205,8 +205,8 @@ def self.build_pot_entry(context:, var_dict:, key:, variable:)
205205
singular = var_dict['one'] || var_dict['other']
206206
plural = var_dict['other']
207207
if singular.nil? || plural.nil?
208-
raise "Stringsdict entry '#{key}' is missing a required plural form " \
209-
"(needs at least 'other'; 'one' recommended for the singular)."
208+
UI.user_error!("Stringsdict entry '#{key}' is missing a required plural form " \
209+
"(needs at least 'other'; 'one' recommended for the singular).")
210210
end
211211

212212
warn_dropped_categories(key: key, variable: variable, var_dict: var_dict)
@@ -256,9 +256,9 @@ def self.translated_forms(parsed_po:, context:, source_var:)
256256
def self.validate_form_count!(forms:, categories:, context:, locale:)
257257
return if forms.size == categories.size
258258

259-
raise "Translation for '#{context}' has #{forms.size} plural form(s) but locale '#{locale}' " \
260-
"expects #{categories.size} (#{categories.join(', ')}). The translation system's plural " \
261-
'configuration for this locale does not match the expected CLDR categories.'
259+
UI.user_error!("Translation for '#{context}' has #{forms.size} plural form(s) but locale '#{locale}' " \
260+
"expects #{categories.size} (#{categories.join(', ')}). The translation system's plural " \
261+
'configuration for this locale does not match the expected CLDR categories.')
262262
end
263263

264264
# A translated entry that has some — but not all — of its plural forms
@@ -313,7 +313,7 @@ def self.english_variable(source_var)
313313
end
314314

315315
def self.parse_po(path)
316-
raise "PO file not found: #{path}" unless File.exist?(path)
316+
UI.user_error!("PO file not found: #{path}") unless File.exist?(path)
317317

318318
po = GetText::PO.new
319319
GetText::POParser.new.parse(File.read(path), po)
@@ -339,10 +339,10 @@ def self.guard_po_plural_count!(po_path:, locale:, categories:)
339339
declared = declared_nplurals(po_path)
340340
return if declared.nil? || declared == categories.size
341341

342-
raise "Locale '#{locale}': the .po declares nplurals=#{declared}, but the expected plural mapping has " \
343-
"#{categories.size} categor#{categories.size == 1 ? 'y' : 'ies'} (#{categories.join(', ')}). " \
344-
"GlotPress's plural rule for this locale no longer matches the PluralRules table — regenerate it " \
345-
'(rakelib/generate_ios_plural_rules.rb).'
342+
UI.user_error!("Locale '#{locale}': the .po declares nplurals=#{declared}, but the expected plural mapping has " \
343+
"#{categories.size} categor#{categories.size == 1 ? 'y' : 'ies'} (#{categories.join(', ')}). " \
344+
"GlotPress's plural rule for this locale no longer matches the PluralRules table — regenerate it " \
345+
'(rakelib/generate_ios_plural_rules.rb).')
346346
end
347347

348348
def self.add_header(po_data)

spec/ios_stringsdict_helper_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def convert_po_to_stringsdict(po_content, template:, locale:)
5151

5252
it 'raises if the file is missing' do
5353
expect { described_class.read(path: 'does-not-exist.stringsdict') }
54-
.to raise_error(/Stringsdict file not found/)
54+
.to raise_error(FastlaneCore::Interface::FastlaneError, /Stringsdict file not found/)
5555
end
5656
end
5757

@@ -112,7 +112,7 @@ def convert_po_to_stringsdict(po_content, template:, locale:)
112112
stringsdict_paths: [fixture('simple.stringsdict'), fixture('simple.stringsdict')],
113113
output_path: pot
114114
)
115-
end.to raise_error(/Duplicate translation context/)
115+
end.to raise_error(FastlaneCore::Interface::FastlaneError, /Duplicate translation context/)
116116
end
117117
end
118118

@@ -129,7 +129,7 @@ def convert_po_to_stringsdict(po_content, template:, locale:)
129129
path: bad
130130
)
131131
expect { described_class.generate_pot(stringsdict_paths: bad, output_path: File.join(dir, 'o.pot')) }
132-
.to raise_error(/missing a required plural form/)
132+
.to raise_error(FastlaneCore::Interface::FastlaneError, /missing a required plural form/)
133133
end
134134
end
135135

@@ -302,7 +302,7 @@ def convert_po_to_stringsdict(po_content, template:, locale:)
302302
# plural rule has drifted from the table — the signal to regenerate it.
303303
expect do
304304
convert_po_to_stringsdict(simple_po(forms: %w[a b], nplurals: 2), template: simple, locale: 'ru')
305-
end.to raise_error(/declares nplurals=2.*3 categor/m)
305+
end.to raise_error(FastlaneCore::Interface::FastlaneError, /declares nplurals=2.*3 categor/m)
306306
end
307307
end
308308
end

0 commit comments

Comments
 (0)