Updated: Comment #2
Problem/Motivation
If you create a view of nodes ordered by the country part of an addressfield, you get some unexpected results...
- Nodes in the United Arab Emerates come before nodes in Argentina
- Nodes in Austria come before nodes in Australia
- Nodes in Switzerland come between nodes in Canada and nodes in Chili
- etc.
(this example uses ascending order: descending order is still incorrect but opposite)
Presumably, in English, United Arab Emerates would come before United States but after Ukraine; etc. Note that different languages have different names for countries and would expect them in an entirely different order (e.g.: "United States" == "États-Unis" (in French) == "美国" in Simplified Chinese).
This is because, internally, Addressfield module stores the "country" of addresses as the 2-character ISO 3166-1 code. While this method has many advantages, notably internationalization, ISO 3166-1's codes don't follow English's (or presumably, any language's) preferred sorting order.
The country names shown in the widget selection list (on the node-edit page) and in views (when Display the localized country name instead of the two character country code is selected) comes from a call to country_get_list()
, which returns the ISO 3366-1 codes keyed to the translated names.
Proposed resolution
Finding a good solution is difficult due to the fact that country names need to be translatable, sorting works differently in different languages, and that the country names are in PHP, not the database.
Still, here are some methods I've thought of that might achieve the desired outcome:
- Convert the codes to names in PHP, after getting results back from the database, then
asort()
the names. This method ensures the names are in the locale's language and preferred sort order but is relatively inefficient and could cause view caching problems. - Add a table to the database containing an index on the country codes and one column for the country's name for each of the currently-enabled languages. This method offloads sorting to the database (which is significantly more efficient) and caching will work as-expected, but managing a table with an arbitrary number of columns, and getting data into the table could be difficult (because you can add and delete languages while viewing the site in another language). Also, if your database, table or column has the wrong locale, it might sort it wrong anyway.
Feedback, or better suggestions, would be appreciated.
Remaining tasks
- Figure out the best way to resolve it.
User interface changes
Hopefully only that lists of countries will be sorted correctly.
API changes
Hopefully none.
Comments
Comment #1
mparker17Updated the issue summary with lots more detail.
Comment #2
mparker17Comment #3
Lukas von BlarerI guess that sorting the view in the pre_render hook or similar is going to be difficult especially if you have limited search results. This will limit the result set to the wrong rows. Therefore you would need to fetch all and set the limit in php. This can be too expensive easily.
Creating a separate table only to sort entities in views seems to be a overkill as well. But if we dont find another solution... The countries module does that. Maybe there could be an integration between these two modules?
A third possible solution that just came to my mind: Is there a way to do a string replacement in the query that lets us replace the codes dynamically with the names? Would this perform sufficently?
Comment #4
xmacinfoI did a views query alter to change the sort order to a ORDER BY FIELD where I define the manual order of each two-letter country code.
That works fine for a any number of countries.
If the site is multilingual, you would need to have a different ORDER BY FIELD for each language.
To automate things, I imagine I could use addressfield token to get the full name of the countries and return the proper two-letter codes to ORDER BY FIELD.
Nevertheless, I still feel that Addressfield should do this automatically.
Comment #5
Lukas von BlarerWhy don't you post your solution?
Comment #6
mparker17@Lukas von Blarer, sorry, I don't have a solution for this. :S I posted the feature request in the hope that someone in the community will have some ideas about how to solve the problem.
Once we have a plan of action, I'd be happy to help write the patch, though!
Comment #7
xmacinfo@Lukas von Blarer: Yes, I will post my solution later. It is on another computer which I do not have access right now.
Comment #8
xmacinfoHere we go.
Comment #9
Lukas von BlarerThanks! I will look into this. Is this a possible solution to make into the module? We would have to list all translated countries and sort them by their name. But that could be cached by language.
Comment #10
modstore CreditAttribution: modstore commentedI needed to show a view of country names and it was sorting by country code. This was my solution, will only work though if there's only the one page:
Comment #11
kiliweb CreditAttribution: kiliweb commentedThanks xmacinfo, #8 works perfectly !
-
http://kiliweb.fr
Comment #12
bojanz CreditAttribution: bojanz commentedDrupal doesn't support per-locale sorting (the intl extension does, but it's PHP 5.3+ and not enabled by default). It might be something to add to http://github.com/commerceguys/intl, but it's definitely not something we can solve for Drupal 7. You will need to continue using hacks.
Comment #14
bofrost CreditAttribution: bofrost at Drupaldise commentedHey guys, if someone else is looking for some solutions for this (still existing) problem, here comes my way.
I've done it with hook_views_pre_render like this:
This works also with translations or in my case with entity translation fields.
Comment #15
awebmanager CreditAttribution: awebmanager as a volunteer commentedI have to say it really is ridiculous that this is still an issue. It is NOT unreasonable to want to sort a list of nodes by their country field, in alphabetical order by the country's name. To have to hack the module or create your own module is a really inconvenient solution. It seems the only other way from the replies here is to install a whole other module (https://www.drupal.org/project/countries) and add a new "country" field into the content type, so the editor has to select a country separately from adding an address, which makes no sense from a UX point of view. Having done that I now have to edit many nodes to add a country already set in the address field just so I can create a view to list the nodes by country name. Really not good.