JSONEncoder: How to sort keys using "localizedStandardCompare"? (just like how Xcode 16 serialize a xcstrings file)

Hello,

I'd like to ask a very fundamental question about JSONEncoder: how to sort keys in a specific order when encoding a dictionary to JSON text?

I know there is an option called JSONEncoder.OutputFormatting.sortedKeys, but it sorts the keys only in lexicographic order.

I want to sort the keys using a different comparator, such as String.localizedStandardCompare(_:), which achieves the "Finder-like" order.

The reason why I ask this question is because I have a localization tool that works with String Catalog (xcstrings file, which is a JSON), but every time my tool serializes an xcstrings file, it always messes up the keys in lexicographic order (I used JSONEncoder + .sortedKeys). Meanwhile, Xcode 16 always serializes the string keys into the "Finder-like" order. As a result, my tool always generates a huge diff when manipulating the xcstrings even when making only a small modification to it.

So I am wondering how Xcode 16 implements the String Catalog tool to serialize the JSON in "Finder-like" order. It would be great if JSONEncoder could do that too. Or, maybe I can use another serialization method to implement this behavior?

Answered by DTS Engineer in 804329022
how to sort keys in a specific order when encoding a dictionary to JSON text?

You can’t. The JSON standard is very clear that dictionaries are not ordered. The ability of JSONEncoder to sort the keys is an affordance for folks who want to maintain key stability, for creating nice diffs and so on. However, it has no way to override that sort order (r. 132654941).

Only Xcode 16 serializes the String Catalog files into the "Finder-like" order. In Xcode 15, the String Catalog files are in lexicographic order. So, this is a new in Xcode 16.

I think you should file a bug about that. I can see why Xcode might have made this change, but it’s messing up your tool and I can imagine it messing up other tools as well. Please post your bug number, just for the record.

As to what you can do about it right now, there isn’t a way to override this with JSONEncoder. Your only real option is to write or acquire your own library for JSON rendering.

I also think it’d be reasonable to file an enhancement request against JSONEncoder for more control over the sort order. I’m not sure that’ll get any traction — there’s a strong impetus to maintain the unsorted nature of dictionaries — but you have a pretty reasonable use case.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

PS: Only Xcode 16 serializes the String Catalog files into the "Finder-like" order. In Xcode 15, the String Catalog files are in lexicographic order. So, this is a new in Xcode 16.

how to sort keys in a specific order when encoding a dictionary to JSON text?

You can’t. The JSON standard is very clear that dictionaries are not ordered. The ability of JSONEncoder to sort the keys is an affordance for folks who want to maintain key stability, for creating nice diffs and so on. However, it has no way to override that sort order (r. 132654941).

Only Xcode 16 serializes the String Catalog files into the "Finder-like" order. In Xcode 15, the String Catalog files are in lexicographic order. So, this is a new in Xcode 16.

I think you should file a bug about that. I can see why Xcode might have made this change, but it’s messing up your tool and I can imagine it messing up other tools as well. Please post your bug number, just for the record.

As to what you can do about it right now, there isn’t a way to override this with JSONEncoder. Your only real option is to write or acquire your own library for JSON rendering.

I also think it’d be reasonable to file an enhancement request against JSONEncoder for more control over the sort order. I’m not sure that’ll get any traction — there’s a strong impetus to maintain the unsorted nature of dictionaries — but you have a pretty reasonable use case.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

Xcode's sort order for String Catalogs is expected to be stable between Xcode 15 and 16.

However, Foundation did make a one-time change to sort order for JSONEncoder.sortedKeys in macOS Sequoia, so this is likely what is causing the behavior change for your tool.

@DTS Engineer @Developer Tools Engineer Thank you for your fast response and detailed information! ❤️

After further investigation, I found the implementation of JSONSerialization seems to be incorrect. When using .sortedKeys options with JSONSerialization, the keys are always sorted in the "Finder-like" order instead of lexicographic order. This is inconsistent with the documentation. But I'm not sure what is the expected behavior.

I can reproduce this issue with Xcode 16.0 on the latest macOS 15.0 and iOS 18.0. I've submitted a feedback FB15177571.

JSONEncoder: How to sort keys using "localizedStandardCompare"? (just like how Xcode 16 serialize a xcstrings file)
 
 
Q