stringsdict files don't correctly handle NSStringLocalizedFormatKey skipping an argument

Originator:kevin
Number:rdar://39390733 Date Originated:4/12/2018
Status:Open Resolved:
Product:Foundation Product Version:
Classification:Serious Bug Reproducible:Always
 
Summary:
When using NSLocalizedString with a stringsdict file, if the NSStringLocalizedFormatKey specifies a format string that uses positional arguments in order to skip an argument, the string is mishandled such that the wrong plural string is chosen for the argument(s) after the skipped argument.

More generally, I believe that the code that determines what argument to look at in order to determine the plural category for a numeric argument doesn't understand positional arguments, so it ends up looking at the wrong spot.

For example, if I have three arguments %1$@, %2$lu, %3$lu, and I skip the second argument in the NSStringLocalizedFormatKey, it still uses the second argument to determine the plural rule to apply to the third.

However, it's even more broken than that; in that plural rule, if it just references %3$lu, the second argument actually gets substituted in that spot instead of the 3rd. However if the plural rule references both the second and third arguments, they get substituted correctly (though the wrong plural rule is still chosen).

I've attached a sample project that demonstrates this. It does 3 substitutions on 3 different strings. For each string the numeric parameter used to control the plural is 0, 1, and 2 in order. The first string doesn't skip any arguments and works correctly. The second string skips one argument and references %3$lu in the plural rule. In this one you can see it's applying the plural rule from the second argument instead of the third (the second argument here is ordered 2, 0, 1). It also only references %3$lu in the plural rule, but the actual substitution is using the second argument. The third string is the same but it references both %2$lu and %3$lu in the plural rule, so you can see it's suddenly substituting the correct argument (though again, with the wrong plural rule).

Steps to Reproduce:
1. Build and run the attached project.

Expected Results:
2. All 3 sections of the output should look like Correct (with the slight modification that the third section should say "(zero: 0 - 2)" and "(one: 1 - 0)").

Actual Results:
The first section is correct, but the other 2 sections are incorrect. They're picking the wrong plural rule to apply, and the second section is substituting the wrong argument in the zero/one plural rules.

Version/Build:
iOS 11.2 (15C107)

Configuration:
iPhone X Simulator

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!