messageformat.net icon indicating copy to clipboard operation
messageformat.net copied to clipboard

Supporting choice format

Open NightOwl888 opened this issue 4 years ago • 9 comments

I am porting some code over to .NET from Java and it uses the JDK's MessageFormat class to format some strings. I am having 2 issues with compatibility here as far as support goes:

  1. messageformat.net doesn't support the choice format
  2. The args parameter that MessageFormat expects is an object array (which is what I have), and MessageFormatter expects a dictionary.

Inputs

Pattern: "{0,choice,0#|1#{1}|2#{1} to {2}}" Args: object[] args = new object[] { 2, "Any", "Hex Escape" };

Attempt

I think I have worked around the second issue by converting the object array to a dictionary like so:

object[] args = new object[] { 2, "Any", "Hex Escape" };
var dic = new Dictionary<string, object>();
for (int j = 0; j < args.Length; j++)
{
	dic.Add(j.ToString(), args[j]);
}

But that causes MessageFormatter to throw:

format.FormatMessage(pattern, dic)' threw an exception of type 'Jeffijoe.MessageFormat.FormatterNotFoundException' Message: "Format 'choice' could not be resolved.\r\nLine 1, position 1\r\nSource literal: '0,choice,0#|1#{1}|2#{1} to {2}'" Source: "Jeffijoe.MessageFormat" StackTrace: " at Jeffijoe.MessageFormat.Formatting.FormatterLibrary.GetFormatter(FormatterRequest request)\r\n at Jeffijoe.MessageFormat.MessageFormatter.FormatMessage(String pattern, IDictionary`2 args)"

Questions

  1. First of all, is there a workaround for this with messageformat.net?
  2. Is this something that can be supported by messageformat.net, or should I be considering porting MessageFormat from the JDK?
  3. If it can be supported, is this something you would be willing to support?

NightOwl888 avatar Jul 18 '19 04:07 NightOwl888

MessageFormat.NET only supports plural and select formatters, I'm not really sure what choice is for?

jeffijoe avatar Jul 18 '19 13:07 jeffijoe

Sorry, I guess I should have included a link to MessageFormat.

For more sophisticated patterns, you can use a ChoiceFormat to produce correct forms for singular and plural:

 MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
 double[] filelimits = {0,1,2};
 String[] filepart = {"no files","one file","{0,number} files"};
 ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
 form.setFormatByArgumentIndex(0, fileform);

 int fileCount = 1273;
 String diskName = "MyDisk";
 Object[] testArgs = {new Long(fileCount), diskName};

 System.out.println(form.format(testArgs));
 

Do note that ICU's MessageFormat also supports choice (even though they recommend not to use it, but hey, it is their code I am porting and they are using it).

NightOwl888 avatar Jul 18 '19 14:07 NightOwl888

So that example seems like it should be using plural instead.

jeffijoe avatar Jul 18 '19 14:07 jeffijoe

Well, I can't change the original strings because they are in resource files. If it is simple enough, I could try using Replace("choice", "plural") on the string though (a little hokey).

pattern = pattern.Replace("choice", "plural");

But I did make an attempt to do that before contacting you, and I got the following error:

'format.FormatMessage(pattern, dic)' threw an exception of type 'Jeffijoe.MessageFormat.MessageFormatterException' Data: {System.Collections.ListDictionaryInternal} HResult: -2146233088 HelpLink: null InnerException: null Message: "'other' option not found in pattern." Source: "Jeffijoe.MessageFormat" StackTrace: " at Jeffijoe.MessageFormat.Formatting.Formatters.PluralFormatter.Pluralize(String locale, ParsedArguments arguments, Double n, Double offset)\r\n at Jeffijoe.MessageFormat.Formatting.Formatters.PluralFormatter.Format(String locale, FormatterRequest request, IDictionary2 args, Object value, IMessageFormatter messageFormatter)\r\n at Jeffijoe.MessageFormat.MessageFormatter.FormatMessage(String pattern, IDictionary2 args)" TargetSite: {System.String Pluralize(System.String, Jeffijoe.MessageFormat.Formatting.ParsedArguments, Double, Double)}

So, that isn't enough to get it to work by itself. I'd like to try to avoid converting the format in the resource file, as that is something I would have to do every time I upgrade the resource file (I don't maintain the files myself). I'd also like to avoid having 2 separate string conversions to make it work.

NightOwl888 avatar Jul 18 '19 15:07 NightOwl888

The other is for when there's no specific match.

If ICU doesn't recommend using choice, then maybe we shouldn't include it, but not sure.

I don't have the bandwidth to do it right now though. :/

jeffijoe avatar Jul 18 '19 19:07 jeffijoe

Would you accept a PR? I found a couple of tests that I could port to at least define the expected behavior:

Unfortunately, it looks like all of the other tests are comparing ICU's choice format against the JDK's ChoiceFormat class to ensure the behavior matches, but I think these 2 will be enough to ensure it works the way I need it to.

NightOwl888 avatar Jul 19 '19 01:07 NightOwl888

Yeah, I’ll accept a PR. I just moved from Denmark to the US and left my Windows PC behind, so I’m not sure whether I can publish a new version on my Mac? When I tried it the last time, the code signing failed.

jeffijoe avatar Jul 19 '19 02:07 jeffijoe

How did you do the last build? I suppose I could build it and send it to you.

Perhaps its time you sign up for a free Azure DevOps account so you can do the deployment build on Windows. The build can be controlled using a .yml file in your repo.

Also, MyGet (another free service) can be used to stage the NuGet package(s) so you can test them before pushing to NuGet.org (which can be done from a button in their control panel).

NightOwl888 avatar Jul 19 '19 02:07 NightOwl888

The last build I did on my Windows machine. There's AppVeyor set up, but not to do code signing and pushing of NuGet packages. Pushing to NuGet is such a pain. ☹️

jeffijoe avatar Jul 19 '19 12:07 jeffijoe

Closing since choice is discouraged over select by the ICU documentation.

jeffijoe avatar Oct 10 '23 21:10 jeffijoe