Shaka Packager SDK
language_utils.cc
1 // Copyright 2015 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/media/base/language_utils.h>
8 
9 #include <iterator>
10 
11 #include <absl/log/check.h>
12 #include <absl/log/log.h>
13 
14 namespace {
15 
16 // A map from 3-letter language codes (ISO 639-2) to 2-letter language codes
17 // (ISO 639-1) for all languages which have both in the registry.
18 typedef struct {
19  const char iso_639_2[4]; // 3 letters + nul
20  const char iso_639_1[3]; // 2 letters + nul
21 } LanguageMapPairType;
22 const LanguageMapPairType kLanguageMap[] = {
23  { "aar", "aa" }, { "abk", "ab" }, { "afr", "af" }, { "aka", "ak" },
24  { "alb", "sq" }, { "amh", "am" }, { "ara", "ar" }, { "arg", "an" },
25  { "arm", "hy" }, { "asm", "as" }, { "ava", "av" }, { "ave", "ae" },
26  { "aym", "ay" }, { "aze", "az" }, { "bak", "ba" }, { "bam", "bm" },
27  { "baq", "eu" }, { "bel", "be" }, { "ben", "bn" }, { "bih", "bh" },
28  { "bis", "bi" }, { "bod", "bo" }, { "bos", "bs" }, { "bre", "br" },
29  { "bul", "bg" }, { "bur", "my" }, { "cat", "ca" }, { "ces", "cs" },
30  { "cha", "ch" }, { "che", "ce" }, { "chi", "zh" }, { "chu", "cu" },
31  { "chv", "cv" }, { "cor", "kw" }, { "cos", "co" }, { "cre", "cr" },
32  { "cym", "cy" }, { "cze", "cs" }, { "dan", "da" }, { "deu", "de" },
33  { "div", "dv" }, { "dut", "nl" }, { "dzo", "dz" }, { "ell", "el" },
34  { "eng", "en" }, { "epo", "eo" }, { "est", "et" }, { "eus", "eu" },
35  { "ewe", "ee" }, { "fao", "fo" }, { "fas", "fa" }, { "fij", "fj" },
36  { "fin", "fi" }, { "fra", "fr" }, { "fre", "fr" }, { "fry", "fy" },
37  { "ful", "ff" }, { "geo", "ka" }, { "ger", "de" }, { "gla", "gd" },
38  { "gle", "ga" }, { "glg", "gl" }, { "glv", "gv" }, { "gre", "el" },
39  { "grn", "gn" }, { "guj", "gu" }, { "hat", "ht" }, { "hau", "ha" },
40  { "heb", "he" }, { "her", "hz" }, { "hin", "hi" }, { "hmo", "ho" },
41  { "hrv", "hr" }, { "hun", "hu" }, { "hye", "hy" }, { "ibo", "ig" },
42  { "ice", "is" }, { "ido", "io" }, { "iii", "ii" }, { "iku", "iu" },
43  { "ile", "ie" }, { "ina", "ia" }, { "ind", "id" }, { "ipk", "ik" },
44  { "isl", "is" }, { "ita", "it" }, { "jav", "jv" }, { "jpn", "ja" },
45  { "kal", "kl" }, { "kan", "kn" }, { "kas", "ks" }, { "kat", "ka" },
46  { "kau", "kr" }, { "kaz", "kk" }, { "khm", "km" }, { "kik", "ki" },
47  { "kin", "rw" }, { "kir", "ky" }, { "kom", "kv" }, { "kon", "kg" },
48  { "kor", "ko" }, { "kua", "kj" }, { "kur", "ku" }, { "lao", "lo" },
49  { "lat", "la" }, { "lav", "lv" }, { "lim", "li" }, { "lin", "ln" },
50  { "lit", "lt" }, { "ltz", "lb" }, { "lub", "lu" }, { "lug", "lg" },
51  { "mac", "mk" }, { "mah", "mh" }, { "mal", "ml" }, { "mao", "mi" },
52  { "mar", "mr" }, { "may", "ms" }, { "mkd", "mk" }, { "mlg", "mg" },
53  { "mlt", "mt" }, { "mon", "mn" }, { "mri", "mi" }, { "msa", "ms" },
54  { "mya", "my" }, { "nau", "na" }, { "nav", "nv" }, { "nbl", "nr" },
55  { "nde", "nd" }, { "ndo", "ng" }, { "nep", "ne" }, { "nld", "nl" },
56  { "nno", "nn" }, { "nob", "nb" }, { "nor", "no" }, { "nya", "ny" },
57  { "oci", "oc" }, { "oji", "oj" }, { "ori", "or" }, { "orm", "om" },
58  { "oss", "os" }, { "pan", "pa" }, { "per", "fa" }, { "pli", "pi" },
59  { "pol", "pl" }, { "por", "pt" }, { "pus", "ps" }, { "que", "qu" },
60  { "roh", "rm" }, { "ron", "ro" }, { "rum", "ro" }, { "run", "rn" },
61  { "rus", "ru" }, { "sag", "sg" }, { "san", "sa" }, { "sin", "si" },
62  { "slk", "sk" }, { "slo", "sk" }, { "slv", "sl" }, { "sme", "se" },
63  { "smo", "sm" }, { "sna", "sn" }, { "snd", "sd" }, { "som", "so" },
64  { "sot", "st" }, { "spa", "es" }, { "sqi", "sq" }, { "srd", "sc" },
65  { "srp", "sr" }, { "ssw", "ss" }, { "sun", "su" }, { "swa", "sw" },
66  { "swe", "sv" }, { "tah", "ty" }, { "tam", "ta" }, { "tat", "tt" },
67  { "tel", "te" }, { "tgk", "tg" }, { "tgl", "tl" }, { "tha", "th" },
68  { "tib", "bo" }, { "tir", "ti" }, { "ton", "to" }, { "tsn", "tn" },
69  { "tso", "ts" }, { "tuk", "tk" }, { "tur", "tr" }, { "twi", "tw" },
70  { "uig", "ug" }, { "ukr", "uk" }, { "urd", "ur" }, { "uzb", "uz" },
71  { "ven", "ve" }, { "vie", "vi" }, { "vol", "vo" }, { "wel", "cy" },
72  { "wln", "wa" }, { "wol", "wo" }, { "xho", "xh" }, { "yid", "yi" },
73  { "yor", "yo" }, { "zha", "za" }, { "zho", "zh" }, { "zul", "zu" },
74 };
75 
76 void SplitLanguageTag(const std::string& tag,
77  std::string* main_language, std::string* subtag) {
78  // Split the main language from its subtag (if any).
79  *main_language = tag;
80  subtag->clear();
81  size_t dash = main_language->find('-');
82  if (dash != std::string::npos) {
83  *subtag = main_language->substr(dash);
84  main_language->erase(dash);
85  }
86 }
87 
88 } // namespace
89 
90 namespace shaka {
91 
92 std::string LanguageToShortestForm(const std::string& language) {
93  // Do not try to mangle blank strings.
94  if (language.size() == 0) {
95  return language;
96  }
97 
98  std::string main_language;
99  std::string subtag;
100  SplitLanguageTag(language, &main_language, &subtag);
101 
102  if (main_language.size() == 2) {
103  // Presumably already a valid ISO-639-1 code, and therefore conforms to
104  // BCP-47's requirement to use the shortest possible code.
105  return main_language + subtag;
106  }
107 
108  for (size_t i = 0; i < std::size(kLanguageMap); ++i) {
109  if (main_language == kLanguageMap[i].iso_639_2) {
110  return kLanguageMap[i].iso_639_1 + subtag;
111  }
112  }
113 
114  // This could happen legitimately for languages which have no 2-letter code,
115  // but that would imply that the input language code is a 3-letter code.
116  DCHECK_EQ(3u, main_language.size()) << main_language;
117  return main_language + subtag;
118 }
119 
120 std::string LanguageToISO_639_2(const std::string& language) {
121  std::string main_language;
122  std::string subtag;
123  SplitLanguageTag(language, &main_language, &subtag);
124 
125  if (main_language.size() == 3) {
126  // Presumably already a valid ISO-639-2 code.
127  return main_language + subtag;
128  }
129 
130  for (size_t i = 0; i < std::size(kLanguageMap); ++i) {
131  if (main_language == kLanguageMap[i].iso_639_1) {
132  return kLanguageMap[i].iso_639_2 + subtag;
133  }
134  }
135 
136  LOG(WARNING) << "No equivalent 3-letter language code for " << main_language;
137  // This is probably a mistake on the part of the user and should be treated
138  // as invalid input.
139  return "und";
140 }
141 
142 } // namespace shaka
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66
std::string LanguageToISO_639_2(const std::string &language)
std::string LanguageToShortestForm(const std::string &language)