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