1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "languages/public/languages.h"
6
7#include "base/string_util.h"
8#include "encodings/compact_lang_det/win/cld_basictypes.h"
9
10
11Language default_language() {return ENGLISH;}
12
13
14// Language names and codes
15
16struct LanguageInfo {
17  const char * language_name_;
18  const char * language_code_639_1_;   // the ISO-639-1 code for the language
19  const char * language_code_639_2_;   // the ISO-639-2 code for the language
20  const char * language_code_other_;   // some nonstandard code for the language
21};
22
23static const LanguageInfo kLanguageInfoTable[] = {
24  { "ENGLISH",             "en", "eng", NULL},
25  { "DANISH",              "da", "dan", NULL},
26  { "DUTCH",               "nl", "dut", NULL},
27  { "FINNISH",             "fi", "fin", NULL},
28  { "FRENCH",              "fr", "fre", NULL},
29  { "GERMAN",              "de", "ger", NULL},
30  { "HEBREW",              "he", "heb", NULL},
31  { "ITALIAN",             "it", "ita", NULL},
32  { "Japanese",            "ja", "jpn", NULL},
33  { "Korean",              "ko", "kor", NULL},
34  { "NORWEGIAN",           "nb", "nor", NULL},
35  { "POLISH",              "pl", "pol", NULL},
36  { "PORTUGUESE",          "pt", "por", NULL},
37  { "RUSSIAN",             "ru", "rus", NULL},
38  { "SPANISH",             "es", "spa", NULL},
39  { "SWEDISH",             "sv", "swe", NULL},
40  { "Chinese",             "zh", "chi", "zh-CN"},
41  { "CZECH",               "cs", "cze", NULL},
42  { "GREEK",               "el", "gre", NULL},
43  { "ICELANDIC",           "is", "ice", NULL},
44  { "LATVIAN",             "lv", "lav", NULL},
45  { "LITHUANIAN",          "lt", "lit", NULL},
46  { "ROMANIAN",            "ro", "rum", NULL},
47  { "HUNGARIAN",           "hu", "hun", NULL},
48  { "ESTONIAN",            "et", "est", NULL},
49  // TODO: Although Teragram has two output names "TG_UNKNOWN_LANGUAGE"
50  // and "Unknown", they are essentially the same. Need to unify them.
51  // "un" and "ut" are invented by us, not from ISO-639.
52  //
53  { "TG_UNKNOWN_LANGUAGE", NULL, NULL, "ut"},
54  { "Unknown",             NULL, NULL, "un"},
55  { "BULGARIAN",           "bg", "bul", NULL},
56  { "CROATIAN",            "hr", "scr", NULL},
57  { "SERBIAN",             "sr", "scc", NULL},
58  { "IRISH",               "ga", "gle", NULL},
59  { "GALICIAN",            "gl", "glg", NULL},
60  // Impossible to tell Tagalog from Filipino at the moment.
61  // Use ISO 639-2 code for Filipino here.
62  { "TAGALOG",             NULL, "fil", NULL},
63  { "TURKISH",             "tr", "tur", NULL},
64  { "UKRAINIAN",           "uk", "ukr", NULL},
65  { "HINDI",               "hi", "hin", NULL},
66  { "MACEDONIAN",          "mk", "mac", NULL},
67  { "BENGALI",             "bn", "ben", NULL},
68  { "INDONESIAN",          "id", "ind", NULL},
69  { "LATIN",               "la", "lat", NULL},
70  { "MALAY",               "ms", "may", NULL},
71  { "MALAYALAM",           "ml", "mal", NULL},
72  { "WELSH",               "cy", "wel", NULL},
73  { "NEPALI",              "ne", "nep", NULL},
74  { "TELUGU",              "te", "tel", NULL},
75  { "ALBANIAN",            "sq", "alb", NULL},
76  { "TAMIL",               "ta", "tam", NULL},
77  { "BELARUSIAN",          "be", "bel", NULL},
78  { "JAVANESE",            "jw", "jav", NULL},
79  { "OCCITAN",             "oc", "oci", NULL},
80  { "URDU",                "ur", "urd", NULL},
81  { "BIHARI",              "bh", "bih", NULL},
82  { "GUJARATI",            "gu", "guj", NULL},
83  { "THAI",                "th", "tha", NULL},
84  { "ARABIC",              "ar", "ara", NULL},
85  { "CATALAN",             "ca", "cat", NULL},
86  { "ESPERANTO",           "eo", "epo", NULL},
87  { "BASQUE",              "eu", "baq", NULL},
88  { "INTERLINGUA",         "ia", "ina", NULL},
89  { "KANNADA",             "kn", "kan", NULL},
90  { "PUNJABI",             "pa", "pan", NULL},
91  { "SCOTS_GAELIC",        "gd", "gla", NULL},
92  { "SWAHILI",             "sw", "swa", NULL},
93  { "SLOVENIAN",           "sl", "slv", NULL},
94  { "MARATHI",             "mr", "mar", NULL},
95  { "MALTESE",             "mt", "mlt", NULL},
96  { "VIETNAMESE",          "vi", "vie", NULL},
97  { "FRISIAN",             "fy", "fry", NULL},
98  { "SLOVAK",              "sk", "slo", NULL},
99  { "ChineseT",
100    NULL,  NULL,  // We intentionally set these 2 fields to NULL to avoid
101                  // confusion between CHINESE_T and CHINESE.
102    "zh-TW"},
103  { "FAROESE",             "fo", "fao", NULL},
104  { "SUNDANESE",           "su", "sun", NULL},
105  { "UZBEK",               "uz", "uzb", NULL},
106  { "AMHARIC",             "am", "amh", NULL},
107  { "AZERBAIJANI",         "az", "aze", NULL},
108  { "GEORGIAN",            "ka", "geo", NULL},
109  { "TIGRINYA",            "ti", "tir", NULL},
110  { "PERSIAN",             "fa", "per", NULL},
111  { "BOSNIAN",             "bs", "bos", NULL},
112  { "SINHALESE",           "si", "sin", NULL},
113  { "NORWEGIAN_N",         "nn", "nno", NULL},
114  { "PORTUGUESE_P",        NULL, NULL, "pt-PT"},
115  { "PORTUGUESE_B",        NULL, NULL, "pt-BR"},
116  { "XHOSA",               "xh", "xho", NULL},
117  { "ZULU",                "zu", "zul", NULL},
118  { "GUARANI",             "gn", "grn", NULL},
119  { "SESOTHO",             "st", "sot", NULL},
120  { "TURKMEN",             "tk", "tuk", NULL},
121  { "KYRGYZ",              "ky", "kir", NULL},
122  { "BRETON",              "br", "bre", NULL},
123  { "TWI",                 "tw", "twi", NULL},
124  { "YIDDISH",             "yi", "yid", NULL},
125  { "SERBO_CROATIAN",      "sh", NULL, NULL},
126  { "SOMALI",              "so", "som", NULL},
127  { "UIGHUR",              "ug", "uig", NULL},
128  { "KURDISH",             "ku", "kur", NULL},
129  { "MONGOLIAN",           "mn", "mon", NULL},
130  { "ARMENIAN",            "hy", "arm", NULL},
131  { "LAOTHIAN",            "lo", "lao", NULL},
132  { "SINDHI",              "sd", "snd", NULL},
133  { "RHAETO_ROMANCE",      "rm", "roh", NULL},
134  { "AFRIKAANS",           "af", "afr", NULL},
135  { "LUXEMBOURGISH",       "lb", "ltz", NULL},
136  { "BURMESE",             "my", "bur", NULL},
137  // KHMER is known as Cambodian for Google user interfaces.
138  { "KHMER",               "km", "khm", NULL},
139  { "TIBETAN",             "bo", "tib", NULL},
140  { "DHIVEHI",             "dv", "div", NULL},
141  { "CHEROKEE",            NULL, "chr", NULL},
142  { "SYRIAC",              NULL, "syr", NULL},
143  { "LIMBU",               NULL, NULL, "sit-NP"},
144  { "ORIYA",               "or", "ori", NULL},
145  { "ASSAMESE",            "as", "asm", NULL},
146  { "CORSICAN",            "co", "cos", NULL},
147  { "INTERLINGUE",         "ie", "ine", NULL},
148  { "KAZAKH",              "kk", "kaz", NULL},
149  { "LINGALA",             "ln", "lin", NULL},
150  { "MOLDAVIAN",           "mo", "mol", NULL},
151  { "PASHTO",              "ps", "pus", NULL},
152  { "QUECHUA",             "qu", "que", NULL},
153  { "SHONA",               "sn", "sna", NULL},
154  { "TAJIK",               "tg", "tgk", NULL},
155  { "TATAR",               "tt", "tat", NULL},
156  { "TONGA",               "to", "tog", NULL},
157  { "YORUBA",              "yo", "yor", NULL},
158  { "CREOLES_AND_PIDGINS_ENGLISH_BASED", NULL, "cpe", NULL},
159  { "CREOLES_AND_PIDGINS_FRENCH_BASED",  NULL, "cpf", NULL},
160  { "CREOLES_AND_PIDGINS_PORTUGUESE_BASED", NULL, "cpp", NULL},
161  { "CREOLES_AND_PIDGINS_OTHER", NULL, "crp", NULL},
162  { "MAORI",               "mi", "mao", NULL},
163  { "WOLOF",               "wo", "wol", NULL},
164  { "ABKHAZIAN",           "ab", "abk", NULL},
165  { "AFAR",                "aa", "aar", NULL},
166  { "AYMARA",              "ay", "aym", NULL},
167  { "BASHKIR",             "ba", "bak", NULL},
168  { "BISLAMA",             "bi", "bis", NULL},
169  { "DZONGKHA",            "dz", "dzo", NULL},
170  { "FIJIAN",              "fj", "fij", NULL},
171  { "GREENLANDIC",         "kl", "kal", NULL},
172  { "HAUSA",               "ha", "hau", NULL},
173  { "HAITIAN_CREOLE",       "ht", NULL, NULL},
174  { "INUPIAK",             "ik", "ipk", NULL},
175  { "INUKTITUT",           "iu", "iku", NULL},
176  { "KASHMIRI",            "ks", "kas", NULL},
177  { "KINYARWANDA",         "rw", "kin", NULL},
178  { "MALAGASY",            "mg", "mlg", NULL},
179  { "NAURU",               "na", "nau", NULL},
180  { "OROMO",               "om", "orm", NULL},
181  { "RUNDI",               "rn", "run", NULL},
182  { "SAMOAN",              "sm", "smo", NULL},
183  { "SANGO",               "sg", "sag", NULL},
184  { "SANSKRIT",            "sa", "san", NULL},
185  { "SISWANT",             "ss", "ssw", NULL},
186  { "TSONGA",              "ts", "tso", NULL},
187  { "TSWANA",              "tn", "tsn", NULL},
188  { "VOLAPUK",             "vo", "vol", NULL},
189  { "ZHUANG",              "za", "zha", NULL},
190  { "KHASI",               NULL, "kha", NULL},
191  { "SCOTS",               NULL, "sco", NULL},
192  { "GANDA",               "lg", "lug", NULL},
193  { "MANX",                "gv", "glv", NULL},
194  { "MONTENEGRIN",         NULL, NULL, "sr-ME"},
195  { "XX",                  NULL, NULL, "XX"},
196};
197
198COMPILE_ASSERT(arraysize(kLanguageInfoTable) == NUM_LANGUAGES + 1,
199               kLanguageInfoTable_has_incorrect_length);
200
201
202// LANGUAGE NAMES
203
204const char* default_language_name() {
205  return kLanguageInfoTable[ENGLISH].language_name_;
206}
207
208static const char* const kInvalidLanguageName = "invalid_language";
209
210const char *invalid_language_name() {
211  return kInvalidLanguageName;
212}
213
214const char* LanguageName(Language lang) {
215  return IsValidLanguage(lang)
216      ? kLanguageInfoTable[lang].language_name_
217      : kInvalidLanguageName;
218}
219
220
221
222// LANGUAGE CODES
223
224
225// The space before invalid_language_code is intentional. It is used
226// to prevent it matching any two letter language code.
227//
228static const char* const kInvalidLanguageCode = " invalid_language_code";
229
230const char *invalid_language_code() {
231  return kInvalidLanguageCode;
232}
233
234const char * LanguageCode(Language lang) {
235  if (! IsValidLanguage(lang))
236    return kInvalidLanguageCode;
237  const LanguageInfo& info = kLanguageInfoTable[lang];
238  if (info.language_code_639_1_) {
239    return info.language_code_639_1_;
240  } else if (info.language_code_639_2_) {
241    return info.language_code_639_2_;
242  } else if (info.language_code_other_) {
243    return info.language_code_other_;
244  } else {
245    return kInvalidLanguageCode;
246  }
247}
248
249const char* default_language_code() {
250  return kLanguageInfoTable[ENGLISH].language_code_639_1_;
251}
252
253const char* LanguageCodeISO639_1(Language lang) {
254  if (! IsValidLanguage(lang))
255    return kInvalidLanguageCode;
256  if (const char* code = kLanguageInfoTable[lang].language_code_639_1_)
257    return code;
258  return kInvalidLanguageCode;
259}
260
261const char* LanguageCodeISO639_2(Language lang) {
262  if (! IsValidLanguage(lang))
263    return kInvalidLanguageCode;
264  if (const char* code = kLanguageInfoTable[lang].language_code_639_2_)
265    return code;
266  return kInvalidLanguageCode;
267}
268
269const char* LanguageCodeWithDialects(Language lang) {
270  if (lang == CHINESE)
271    return "zh-CN";
272  return LanguageCode(lang);
273}
274
275
276
277bool LanguageFromCode(const char* lang_code, Language *language) {
278  *language = UNKNOWN_LANGUAGE;
279  if ( lang_code == NULL ) return false;
280
281  for ( int i = 0 ; i < kNumLanguages ; i++ ) {
282    const LanguageInfo& info = kLanguageInfoTable[i];
283    if ((info.language_code_639_1_ &&
284         !base::strcasecmp(lang_code, info.language_code_639_1_)) ||
285        (info.language_code_639_2_ &&
286         !base::strcasecmp(lang_code, info.language_code_639_2_)) ||
287        (info.language_code_other_ &&
288         !base::strcasecmp(lang_code, info.language_code_other_))) {
289      *language = static_cast<Language>(i);
290      return true;
291    }
292  }
293
294  // For convenience, this function can also parse the non-standard
295  // five-letter language codes "zh-cn" and "zh-tw" which are used by
296  // front-ends such as GWS to distinguish Simplified from Traditional
297  // Chinese.
298  if (!base::strcasecmp(lang_code, "zh-cn") ||
299      !base::strcasecmp(lang_code, "zh_cn")) {
300    *language = CHINESE;
301    return true;
302  }
303  if (!base::strcasecmp(lang_code, "zh-tw") ||
304      !base::strcasecmp(lang_code, "zh_tw")) {
305    *language = CHINESE_T;
306    return true;
307  }
308  if (!base::strcasecmp(lang_code, "sr-me") ||
309      !base::strcasecmp(lang_code, "sr_me")) {
310    *language = MONTENEGRIN;
311    return true;
312  }
313
314  // Process language-code synonyms.
315  if (!base::strcasecmp(lang_code, "he")) {
316    *language = HEBREW;  // Use "iw".
317    return true;
318  }
319  if (!base::strcasecmp(lang_code, "in")) {
320    *language = INDONESIAN;  // Use "id".
321    return true;
322  }
323  if (!base::strcasecmp(lang_code, "ji")) {
324    *language = YIDDISH;  // Use "yi".
325    return true;
326  }
327
328  // Process language-detection synonyms.
329  // These distinct languages cannot be differentiated by our current
330  // language-detection algorithms.
331  if (!base::strcasecmp(lang_code, "fil")) {
332    *language = TAGALOG;
333    return true;
334  }
335
336  return false;
337}
338