Skip to content

Commit 535c167

Browse files
committed
Prefix unquoted keys and values in merge_strings
`L10nHelper.merge_strings` rewrites each key to add the caller's prefix, but its line matcher only handled `[A-Z0-9_]` keys with a *quoted* value. An unquoted key containing `. - $ : /`, or any line with an *unquoted* value (`CFBundleName = WordPress;`), was written to the merged file without the prefix while still being bookkept *with* it — an inconsistency that can resurface the collisions the prefix avoids and break downstream key extraction. The matcher now accepts the full unquoted-string character set `plutil` allows. The unquoted-value case keys on the fact that an unquoted string can't contain spaces, so it won't mistake comment prose (`and = a red herring ...`) for a key/value pair — a case the fixtures deliberately guard.
1 parent 9de2a6c commit 535c167

3 files changed

Lines changed: 33 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ _None_
1717
- `StringsFileValidationHelper.find_duplicated_keys` now parses *unquoted* keys and values (valid `.strings` syntax, common in `InfoPlist.strings`) instead of raising `Invalid character`, matching the character set `plutil` accepts for unquoted strings (alphanumerics plus `_ . - $ : /`). This lets `ios_lint_localizations`' `check_duplicate_keys` work on `InfoPlist.strings`-style files. [#741]
1818
- `StringsFileValidationHelper.find_duplicated_keys` now also accepts comments placed *between* the tokens of a statement (e.g. `"key" /* note */ = "value";`), which `plutil` allows, instead of raising `Invalid character` on the `/`. [#741]
1919
- `ios_lint_localizations`' `check_duplicate_keys` no longer crashes the lane on a file that parses as a property list but isn't a flat `.strings` (e.g. a nested-dictionary value); it now warns via `UI.important` and skips that file. [#741]
20+
- `L10nHelper.merge_strings` now applies the key prefix to unquoted keys containing `. - $ : /` and to lines with an *unquoted* value (e.g. `CFBundleName = WordPress;`), matching the unquoted-string grammar `plutil` accepts. Previously those keys were written to the merged file without the prefix while still being bookkept *with* it, leaving the output inconsistent with the reported keys (which could resurface the very collisions the prefix avoids and break downstream key extraction). [#741]
2021

2122
### Internal Changes
2223

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,17 @@ def self.merge_strings(paths:, output_path:)
102102
# Read line-by-line to reduce memory footprint during content copy
103103
read_utf8_lines(input_file).each do |line|
104104
unless prefix.nil? || prefix.empty?
105-
# The `/u` modifier on the RegExps is to make them UTF-8
105+
# The `/u` modifier on the RegExps is to make them UTF-8.
106+
# The unquoted-key character set below matches what `plutil` accepts (alphanumerics plus
107+
# `_ . - $ : /`, as in `StringsFileValidationHelper::UNQUOTED_STRING_CHARACTER`) so that keys
108+
# containing `. - $ : /` (e.g. reverse-DNS keys) are prefixed like any other.
106109
line.gsub!(/^(\s*")/u, "\\1#{prefix}") # Lines starting with a quote are considered to be start of a key; add prefix right after the quote
107-
line.gsub!(/^(\s*)([A-Z0-9_]+)(\s*=\s*")/ui, "\\1\"#{prefix}\\2\"\\3") # Lines starting with an identifier followed by a '=' are considered to be an unquoted key (typical in InfoPlist.strings files for example)
110+
# Lines starting with an unquoted key followed by a `=` and a *quoted* value (typical in `InfoPlist.strings`).
111+
line.gsub!(%r{^(\s*)([a-zA-Z0-9_.$:/-]+)(\s*=\s*")}u, "\\1\"#{prefix}\\2\"\\3")
112+
# Lines starting with an unquoted key followed by a `=` and an *unquoted* value (e.g. `CFBundleName = WordPress;`).
113+
# The value is required to be a single unquoted token ending in `;` — an unquoted string can't contain spaces, so
114+
# this won't mistake comment prose like `and = a red herring for when…` (spaces in the "value") for a key/value pair.
115+
line.gsub!(%r{^(\s*)([a-zA-Z0-9_.$:/-]+)(\s*=\s*)([a-zA-Z0-9_.$:/-]+\s*;)}u, "\\1\"#{prefix}\\2\"\\3\\4")
108116
end
109117
tmp_file.write(line)
110118
end

spec/ios_l10n_helper_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,28 @@ def file_encoding(path)
100100
end
101101
end
102102

103+
it 'prefixes unquoted keys with unquoted values and keys containing `. - $ : /`' do
104+
# Regression: prefixing must cover the full unquoted-string grammar `plutil` accepts — unquoted *values*
105+
# (e.g. `CFBundleName = WordPress;`) and keys containing `. - $ : /` — so the written file stays consistent
106+
# with the prefixed keys we report. (Previously only `[A-Z0-9_]` keys with a *quoted* value were prefixed,
107+
# leaving these written without the prefix and resurfacing the very collisions the prefix avoids.)
108+
content = <<~STRINGS
109+
CFBundleName = WordPress;
110+
com.automattic.app-id = "X";
111+
"QuotedKey" = "Y";
112+
STRINGS
113+
Dir.mktmpdir('a8c-release-toolkit-l10n-helper-tests-') do |tmp_dir|
114+
input_file = File.join(tmp_dir, 'InfoPlist.strings')
115+
File.write(input_file, content)
116+
output_file = File.join(tmp_dir, 'output.strings')
117+
described_class.merge_strings(paths: { input_file => 'pfx.' }, output_path: output_file)
118+
merged = File.read(output_file)
119+
expect(merged).to include('"pfx.CFBundleName" = WordPress;')
120+
expect(merged).to include('"pfx.com.automattic.app-id" = "X";')
121+
expect(merged).to include('"pfx.QuotedKey" = "Y";')
122+
end
123+
end
124+
103125
it 'returns duplicate keys found' do
104126
paths = { fixture('Localizable-utf16.strings') => nil, fixture('non-latin-utf16.strings') => nil }
105127
Dir.mktmpdir('a8c-release-toolkit-l10n-helper-tests-') do |tmp_dir|

0 commit comments

Comments
 (0)