openstreetmap / iD

🆔 The easy-to-use OpenStreetMap editor in JavaScript.
https://www.openstreetmap.org/edit?editor=id
ISC License
3.34k stars 1.2k forks source link

Country should be a combo field #7123

Open 1ec5 opened 4 years ago

1ec5 commented 4 years ago

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.

zorae commented 4 years ago

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

zorae commented 4 years ago

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

1ec5 commented 4 years ago

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 commented 5 months ago

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 commented 5 months ago

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.

Abishek-Jayan commented 2 months ago

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?

1ec5 commented 2 months ago

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.

harshendram commented 3 weeks ago

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