RobThree / NGeoNames

Inspired by https://github.com/AReallyGoodName/OfflineReverseGeocode
MIT License
88 stars 22 forks source link

lang to change the name to a different language #4

Closed justlearntutors closed 6 years ago

justlearntutors commented 6 years ago

How can I change the names to a different language?

API example http://ws.geonames.org/search?country=DK&maxRows=100&username=demo&lang=da

RobThree commented 6 years ago

You will need to provide a lot more info; I have no idea what you mean. Sorry.

justlearntutors commented 6 years ago

I want to get city names in Danish, German or another language.

How can I provide language code?

It is possible using this url. http://ws.geonames.org/search?country=DK&maxRows=100&username=demo&lang=da

RobThree commented 6 years ago

The URL you are referring to is the Geonames Web API url. This project doesn't use the Web API but the data dumps from geonames.org. If you scroll all the way down you will see an explanation of all the files geonames provides. Figure out which file you're interested in, download it using NGeonames and then use it accordingly.

I suspect you're interested in the alternatenames but again, not sure.

justlearntutors commented 6 years ago

I found these files.

Are the translated city names here?

http://download.geonames.org/export/dump/alternatenames/

RobThree commented 6 years ago

You understand this is not a support forum but a place to report issues?

Have you read the documentation I pointed you to? Have you actually taken a look at the file(s)? Have you done any research before asking? I can't help you with this; I will gladly fix bugs in the NGeoNames library, explain how to use the code from the NGeoNames library etc. but I can't help you decide if you need this library or not, if the files contain what you need etc. That's all up to you. Also please understand NGeoNames is in no way related to geonames.org other than that the library is used to parse/read the geonames.org dumps.

justlearntutors commented 6 years ago

Have read the documentation and checked the files for Danish translations now.

All translated city names are stored in the files below. http://download.geonames.org/export/dump/alternateNames.zip http://download.geonames.org/export/dump/alternateNamesV2.zip

The files are +200 mb.

NGeoNames is working fine.

var AllCitiesTranslation = GeoFileReader.ReadAlternateNames(@"C:\Users\Philip\Documents\geonames\translations\alternateNames.txt");
var AllCitiesTranslationV2 = GeoFileReader.ReadAlternateNames(@"C:\Users\Philip\Documents\geonames\translations\alternateNamesV2.txt");

int GeoNameId = 5128581;
string TranslatedCityName = "";

if (AllCitiesTranslation.Any(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is"))
{
    TranslatedCityName = AllCitiesTranslation.First(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is").Name;
}

if (AllCitiesTranslationV2.Any(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is"))
{
    TranslatedCityName = AllCitiesTranslation.First(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is").Name;
}
RobThree commented 6 years ago

Ok, this is where I can help you out:

if (AllCitiesTranslation.Any(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is"))
{
    TranslatedCityName = AllCitiesTranslation.First(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is").Name;
}

This will iterate 2 times over the collection(s) which is very inefficient. I'd rather do:

TranslatedCityName = AllCitiesTranslation
    .Where(d => d.GeoNameId == GeoNameId && d.ISOLanguage == "is")
    .FirstOrDefault()?.Name ?? String.Empty;

Also, TranslatedCityName is potentially resolved in the first if-statement and then overwritten in the second if-statement after iterating the V2 collection; that is a lot of wasted CPU cycles if it was already found in the "V1" collection. Is this actual behavior you want or do you want to use some sort of fallback (e.g. if cityname is not found in first collection, check second or vise versa)?

If you want "fallback behavior" then, instead of iterating both(!) collections twice(!) (e.g. 4 'expensive' operations) I'd do something like:

var citiesv1 = GeoFileReader.ReadAlternateNames(@"<...>\alternateNames.txt");
var citiesv2 = GeoFileReader.ReadAlternateNames(@"<...>\alternateNamesV2.txt");
var geoId= 5128581;
var language = "is";

var cityname = citiesv2.ResolveName(geoId, language, citiesv1.ResolveName(geoId, language));

Then add a class to your project and put this in it:

using NGeoNames.Entities;
using System.Collections.Generic;
using System.Linq;

namespace MyNameSpace
{
    static class ExtensionMethods
    {
        public static string ResolveName(this IEnumerable<AlternateName> alternates, int id,
            string language, string defaultValue = null)
        {
            return alternates
                .Where(a => a.Id == id && a.ISOLanguage == language)
                .FirstOrDefault()?.Name ?? defaultValue;
        }
    }
}

This will try to resolve in V2 and then fallback to V1; you can easily change it around to try V1 first and then V2:

// Try V2, fallback to V1
var cityname = citiesv2.ResolveName(geoNameId, language, citiesv1.ResolveName(geoNameId, language));
// Change to try V1, then V2
var cityname = citiesv1.ResolveName(geoNameId, language, citiesv2.ResolveName(geoNameId, language));
justlearntutors commented 6 years ago

I am getting an error for alternateNamesV2.txt.

c# codes var citiesv2 = GeoFileReader.ReadAlternateNames(@"C:\Users\Philip\Documents\geonames\translations\alternateNamesV2.txt");

TranslatedName = AllCitiesTranslationV2.Where(d => d.GeoNameId == CurrentGeoNameId && d.ISOLanguage == "da").FirstOrDefault()?.Name ?? defaultValue;

ParserException: Expected number of fields mismatch; expected: 8, read: 9, line: 1

RobThree commented 6 years ago

That's because the V2 format is new and this library doesn't support it (yet). I only learned this just yet. It should be easy to fix but I won't have time to implement this today. Maybe, maybe (no promises) over the weekend.

RobThree commented 6 years ago

Actually, the V2 file doesn't seem to match the specifications:

The table 'alternate names' :
-----------------------------
alternateNameId   : the id of this alternate name, int
geonameid         : geonameId referring to id in table 'geoname', int
isolanguage       : iso 639 language code 2- or 3-characters; 4-characters 'post' for postal codes and 'iata','icao' and faac for airport codes, fr_1793 for French Revolution names,  abbr for abbreviation, link to a website (mostly to wikipedia), wkdt for the wikidataid, varchar(7)
alternate name    : alternate name or name variant, varchar(400)
isPreferredName   : '1', if this alternate name is an official/preferred name
isShortName       : '1', if this is a short name like 'California' for 'State of California'
isColloquial      : '1', if this alternate name is a colloquial or slang term. Example: 'Big Apple' for 'New York'.
isHistoric        : '1', if this alternate name is historic and was used in the past. Example 'Bombay' for 'Mumbai'.
from          : from period when the name was used
to        : to period when the name was used

There seems to be a field missing; There should be 10 fields, I'm reading 9...

If I were you I'd wait for V2 support. Meanwhile I will try to figure out what's going on with the file / report an issue at ngeonames.