iD icon indicating copy to clipboard operation
iD copied to clipboard

Country should be a combo field

Open 1ec5 opened this issue 6 years ago • 8 comments

The country tag is supposed to be an ISO 3166 alpha-2 code, but not everyone is familiar with the ISO code for their own country (dependent territory, etc.), let alone the country of a consulate or embassy. Meanwhile, tags like country=Turkey and country=United_States_of_America crop up because it looks a lot like a free-form text field.

Mappers would be more likely to enter consistent values if we turn the Country field into a combo field with each choice being a spelled-out country name. As with the multilingual name field (#2457), CLDR would be a natural source for country names localized into every supported language, to avoid additional burden on translators.

Maybe in the future, this work could also come in handy for other tagging schemes that incorporate ISO 3166 codes, like network and cycle_network tags.

1ec5 avatar Dec 15 '19 05:12 1ec5

I’ve spent a lot of time cross-referencing ISO 3166 tables when tagging diplomatic offices. This would be a welcome improvement!

zorae avatar Dec 15 '19 17:12 zorae

Please note that both country=* and target=* may be a semicolon-delimited list, not just a single country code. See wiki

zorae avatar Dec 24 '19 12:12 zorae

This MapRoulette challenge includes hundreds of flagpoles to retag where a mapper had written a full country name in the Country field. That could’ve been due to a lack of awareness of the convention to use ISO codes, the inconvenience of looking up an ISO code, or the taginfo-based suggestions that currently show “Tanzania” as the most common value for some reason.

1ec5 avatar Jul 04 '20 22:07 1ec5

openstreetmap/id-tagging-schema#799 was closed in favor of the CLDR-based approach described above. We already use CLDR for the list of languages in the Multilingual Name field, but at build time, we throw away the rest of the CLDR data, including country names:

https://github.com/openstreetmap/iD/blob/a38d7a1b8d50a3e358f4e0f0a5ae5a42b3d7cf58/scripts/language_names.js#L69

1ec5 avatar Apr 04 '24 17:04 1ec5

On second thought, we already require browser versions that support Intl.DisplayNames.prototype.of(), so we can just use that method to map each country code to a localized, human-readable string. This would also work for language names, allowing us to remove the dependency on CLDR.

1ec5 avatar Apr 04 '24 17:04 1ec5

Hey is this issue being worked on by anyone? From what I see, the change needs to be done in the combo.js file. May I take a crack at it?

Abishek-Jayan avatar Jul 09 '24 07:07 Abishek-Jayan

No one has posted a pull request for this enhancement yet, so feel free to give it a try.

For what it’s worth, combo.js is deep in the UI code. Most of this field code doesn’t know about the quirks of individual keys or fields. Instead, that’s normally the responsibility of the separate id-tagging-schema repository. Since there are so many potential options to list for this field, we would want to generate them dynamically at runtime instead of hard-coding them in id-tagging-schema, but maybe not directly in the UI code, because other modules like the validator might eventually need the same data.

You might want to look at modules/presets/index.js, where iD loads and processes id-tagging-schema’s data. That would be a more convenient place to add a bunch of options to a particular field, since you wouldn’t have to think about UI at all.

1ec5 avatar Jul 10 '24 00:07 1ec5

Here's a JavaScript function that takes either a full country name or an ISO code and converts it into the corresponding ISO code. This function uses a predefined mapping of country names to ISO codes:

const countryToISO = {
    "Afghanistan": "AF",
    "Albania": "AL",
    "Algeria": "DZ",
    "United States of America": "US",
    "India": "IN",
    "Turkey": "TR",
    // Add more countries as needed
};

function getISOCode(input) {
    // Convert input to uppercase for case-insensitive comparison
    const upperInput = input.toUpperCase();

    // Check if the input is already an ISO code
    if (Object.values(countryToISO).includes(upperInput)) {
        return upperInput;
    }

    // Find the ISO code for the given country name
    for (const [country, iso] of Object.entries(countryToISO)) {
        if (country.toUpperCase() === upperInput) {
            return iso;
        }
    }

    // If not found, return null or handle the error as needed
    return null;
}

// Example usage
console.log(getISOCode("India")); // Output: IN
console.log(getISOCode("IN"));    // Output: IN
console.log(getISOCode("Turkey")); // Output: TR
console.log(getISOCode("TR"));    // Output: TR

This function works as follows:

  1. It first checks if the input is already an ISO code.
  2. If not, it searches for the corresponding ISO code using the country name.
  3. If the input is neither a valid ISO code nor a recognized country name, it returns null.

we can use i18n-iso-countries library too. I hope my approach is correct ,free for discussions

harshendram avatar Aug 23 '24 21:08 harshendram