Home | History | Annotate | Download | only in geocoding
      1 // Copyright (C) 2012 The Libphonenumber Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 //
     15 // Author: Patrick Mezard
     16 
     17 #include "phonenumbers/geocoding/mapping_file_provider.h"
     18 
     19 #include <algorithm>
     20 #include <cstddef>
     21 #include <cstring>
     22 #include <sstream>
     23 #include <string>
     24 
     25 #include "phonenumbers/geocoding/geocoding_data.h"
     26 
     27 namespace i18n {
     28 namespace phonenumbers {
     29 
     30 using std::string;
     31 
     32 namespace {
     33 
     34 struct NormalizedLocale {
     35   const char* locale;
     36   const char* normalized_locale;
     37 };
     38 
     39 const NormalizedLocale kNormalizedLocales[] = {
     40   {"zh_TW", "zh_Hant"},
     41   {"zh_HK", "zh_Hant"},
     42   {"zh_MO", "zh_Hant"},
     43 };
     44 
     45 const char* GetNormalizedLocale(const string& full_locale) {
     46   const int size = sizeof(kNormalizedLocales) / sizeof(*kNormalizedLocales);
     47   for (int i = 0; i != size; ++i) {
     48     if (full_locale.compare(kNormalizedLocales[i].locale) == 0) {
     49       return kNormalizedLocales[i].normalized_locale;
     50     }
     51   }
     52   return NULL;
     53 }
     54 
     55 void AppendLocalePart(const string& part, string* full_locale) {
     56   if (!part.empty()) {
     57     full_locale->append("_");
     58     full_locale->append(part);
     59   }
     60 }
     61 
     62 void ConstructFullLocale(const string& language, const string& script, const
     63                          string& region, string* full_locale) {
     64   full_locale->assign(language);
     65   AppendLocalePart(script, full_locale);
     66   AppendLocalePart(region, full_locale);
     67 }
     68 
     69 // Returns true if s1 comes strictly before s2 in lexicographic order.
     70 bool IsLowerThan(const char* s1, const char* s2) {
     71   return strcmp(s1, s2) < 0;
     72 }
     73 
     74 // Returns true if languages contains language.
     75 bool HasLanguage(const CountryLanguages* languages, const string& language) {
     76   const char** const start = languages->available_languages;
     77   const char** const end = start + languages->available_languages_size;
     78   const char** const it =
     79       std::lower_bound(start, end, language.c_str(), IsLowerThan);
     80   return it != end && strcmp(language.c_str(), *it) == 0;
     81 }
     82 
     83 }  // namespace
     84 
     85 MappingFileProvider::MappingFileProvider(
     86     const int* country_calling_codes, int country_calling_codes_size,
     87     country_languages_getter get_country_languages)
     88   : country_calling_codes_(country_calling_codes),
     89     country_calling_codes_size_(country_calling_codes_size),
     90     get_country_languages_(get_country_languages) {
     91 }
     92 
     93 const string& MappingFileProvider::GetFileName(int country_calling_code,
     94                                                const string& language,
     95                                                const string& script,
     96                                                const string& region,
     97                                                string* filename) const {
     98   filename->clear();
     99   if (language.empty()) {
    100     return *filename;
    101   }
    102   const int* const country_calling_codes_end = country_calling_codes_ +
    103       country_calling_codes_size_;
    104   const int* const it =
    105       std::lower_bound(country_calling_codes_,
    106                        country_calling_codes_end,
    107                        country_calling_code);
    108   if (it == country_calling_codes_end || *it != country_calling_code) {
    109     return *filename;
    110   }
    111   const CountryLanguages* const langs =
    112       get_country_languages_(it - country_calling_codes_);
    113   if (langs->available_languages_size > 0) {
    114     string language_code;
    115     FindBestMatchingLanguageCode(langs, language, script, region,
    116                                  &language_code);
    117   if (!language_code.empty()) {
    118     std::stringstream filename_buf;
    119     filename_buf << country_calling_code << "_" << language_code;
    120     *filename = filename_buf.str();
    121     }
    122   }
    123   return *filename;
    124 }
    125 
    126 void MappingFileProvider::FindBestMatchingLanguageCode(
    127   const CountryLanguages* languages, const string& language,
    128   const string& script, const string& region, string* best_match) const {
    129   string full_locale;
    130   ConstructFullLocale(language, script, region, &full_locale);
    131   const char* const normalized_locale = GetNormalizedLocale(full_locale);
    132   if (normalized_locale != NULL) {
    133     string normalized_locale_str(normalized_locale);
    134     if (HasLanguage(languages, normalized_locale_str)) {
    135       best_match->swap(normalized_locale_str);
    136       return;
    137     }
    138   }
    139 
    140   if (HasLanguage(languages, full_locale)) {
    141     best_match->swap(full_locale);
    142     return;
    143   }
    144 
    145   if (script.empty() != region.empty()) {
    146     if (HasLanguage(languages, language)) {
    147       *best_match = language;
    148       return;
    149     }
    150   } else if (!script.empty() && !region.empty()) {
    151     string lang_with_script(language);
    152     lang_with_script.append("_");
    153     lang_with_script.append(script);
    154     if (HasLanguage(languages, lang_with_script)) {
    155       best_match->swap(lang_with_script);
    156       return;
    157     }
    158   }
    159 
    160   string lang_with_region(language);
    161   lang_with_region.append("_");
    162   lang_with_region.append(region);
    163   if (HasLanguage(languages, lang_with_region)) {
    164     best_match->swap(lang_with_region);
    165     return;
    166   }
    167   if (HasLanguage(languages, language)) {
    168     *best_match = language;
    169     return;
    170   }
    171   best_match->clear();
    172 }
    173 
    174 }  // namespace phonenumbers
    175 }  // namespace i18n
    176