diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_prune_orphaned_translations_action.rb b/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_prune_orphaned_translations_action.rb index 0bd0e1bb0..efb850ca5 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_prune_orphaned_translations_action.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_prune_orphaned_translations_action.rb @@ -6,11 +6,19 @@ module Fastlane module Actions class AndroidPruneOrphanedTranslationsAction < Action - # Matches an Android `values-` directory whose qualifier is a locale (a language code, optional - # region, or a BCP-47 `b+` form), so non-locale qualifier dirs (e.g. `values-night`, `values-v21`, - # `values-land`) are left untouched. + # Matches an Android `values-` directory whose qualifier is a locale: a 2- or 3-letter language + # code (`fr`, `kmr`), an optional region (`pt-rBR`, `es-r419`), or a BCP-47 `b+` form (`b+sr+Latn`), so + # non-locale qualifier dirs (e.g. `values-night`, `values-v21`, `values-land`) are left untouched. LOCALE_VALUES_DIR_REGEX = /\Avalues-(?:b\+[a-zA-Z]+(?:\+[a-zA-Z0-9]+)*|[a-z]{2,3}(?:-r(?:[A-Z]{2}|\d{3}))?)\z/ + # Android UI-mode qualifiers, which are never locales: + # https://developer.android.com/guide/topics/resources/providing-resources#UiModeQualifier + # `car` is indistinguishable by shape from a 3-letter ISO 639 language code, so `LOCALE_VALUES_DIR_REGEX` + # would otherwise treat `values-car` as a locale and prune its (valid) car-mode resources. There's no purely + # syntactic way to tell the two apart, so we exclude the documented UI-mode qualifiers explicitly. (`car` is + # the only one short enough to currently match the regex; the rest are listed to capture the full set.) + UI_MODE_QUALIFIERS = %w[car desk television appliance watch vrheadset].freeze + DEFAULT_SOURCE_STRINGS_FILE_NAME = 'strings.xml' DEFAULT_SOURCE_STRINGS_RELATIVE_PATH = File.join('values', DEFAULT_SOURCE_STRINGS_FILE_NAME).freeze @@ -20,7 +28,8 @@ def self.run(params) valid_keys = collect_keys(source_paths) locale_files = Dir.glob(File.join(res_dir, 'values-*', DEFAULT_SOURCE_STRINGS_FILE_NAME)).select do |file| - File.basename(File.dirname(file)).match?(LOCALE_VALUES_DIR_REGEX) + dir_name = File.basename(File.dirname(file)) + dir_name.match?(LOCALE_VALUES_DIR_REGEX) && !UI_MODE_QUALIFIERS.include?(dir_name.delete_prefix('values-')) end total_pruned = 0 diff --git a/spec/android_prune_orphaned_translations_spec.rb b/spec/android_prune_orphaned_translations_spec.rb index 3ae43e5b2..9f731e06f 100644 --- a/spec/android_prune_orphaned_translations_spec.rb +++ b/spec/android_prune_orphaned_translations_spec.rb @@ -109,6 +109,30 @@ def write_file(path, content) end end + # `kmr` (Northern Kurdish) is a real 3-letter legacy locale used by e.g. WordPress-Android, so it must still be + # pruned — guarding against an over-eager "restrict locales to 2 letters" fix for the `values-car` collision. + it 'prunes 3-letter legacy locale directories (e.g. values-kmr)' do + Dir.mktmpdir do |dir| + res_dir = File.join(dir, 'res') + write_file(File.join(res_dir, 'values', 'strings.xml'), default_strings) + kmr_file = File.join(res_dir, 'values-kmr', 'strings.xml') + write_file(kmr_file, <<~XML) + + + Silav + Sêwî + + XML + + pruned = run_described_fastlane_action(res_dir: res_dir) + + expect(pruned).to eq(1) + content = File.read(kmr_file) + expect(content).to include('name="hello"') + expect(content).not_to include('orphan_string') + end + end + it 'treats keys from `additional_source_strings_paths` as valid (flavor overlay case)' do Dir.mktmpdir do |dir| res_dir = File.join(dir, 'res')