summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2021-11-22 15:56:53 +0100
committerIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2021-12-09 03:45:08 +0100
commit4f53c703e40bea3203259c212c54dc4816c08b09 (patch)
tree178ce98f0707d0e6b509cc603f0f92580ecd5775
parent0fbeac01156c57dc6e48087b7a8dea4644294f6a (diff)
QLocale: Extend support for language codes
This commit extends functionality for QLocale::codeToLanguage() and QLocale::languageToCode() by adding an additional argument that allows selection of the ISO 639 code-set to consider for those operations. The following ISO 639 codes are supported: * Part 1 * Part 2 bibliographic * Part 2 terminological * Part 3 As a result of this change the codeToLanguage() overload without the additional argument now returns a Language value if it matches any know code. Previously a valid language was returned only if the function argument matched the first code defined for that language from the above list. [ChangeLog][QtCore][QLocale] Added overloads for codeToLanguage() and languageToCode() that support specifying which ISO 639 codes to consider. Fixes: QTBUG-98129 Change-Id: I4da8a89e2e68a673cf63a621359cded609873fa2 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
-rw-r--r--src/corelib/text/qlocale.cpp136
-rw-r--r--src/corelib/text/qlocale.h25
-rw-r--r--src/corelib/text/qlocale.qdoc19
-rw-r--r--src/corelib/text/qlocale_data_p.h687
-rw-r--r--src/corelib/text/qlocale_mac.mm8
-rw-r--r--src/corelib/text/qlocale_p.h15
-rw-r--r--tests/auto/corelib/text/qlocale/tst_qlocale.cpp38
-rw-r--r--util/locale_database/iso639_3.py105
-rwxr-xr-xutil/locale_database/qlocalexml2cpp.py53
9 files changed, 724 insertions, 362 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index 45794cc703..660271230a 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -102,22 +102,58 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qlocale_data_p.h"
QT_END_INCLUDE_NAMESPACE
-QLocale::Language QLocalePrivate::codeToLanguage(QStringView code) noexcept
+QLocale::Language QLocalePrivate::codeToLanguage(QStringView code,
+ QLocale::LanguageCodeTypes codeTypes) noexcept
{
const auto len = code.size();
if (len != 2 && len != 3)
return QLocale::AnyLanguage;
- char16_t uc1 = code[0].toLower().unicode();
- char16_t uc2 = code[1].toLower().unicode();
- char16_t uc3 = len > 2 ? code[2].toLower().unicode() : 0;
- const unsigned char *c = language_code_list;
- for (; *c != 0; c += 3) {
- if (uc1 == c[0] && uc2 == c[1] && uc3 == c[2])
- return QLocale::Language((c - language_code_list)/3);
+ const char16_t uc1 = code[0].toLower().unicode();
+ const char16_t uc2 = code[1].toLower().unicode();
+ const char16_t uc3 = len > 2 ? code[2].toLower().unicode() : 0;
+
+ // All language codes are ASCII.
+ if (uc1 > 0x7F || uc2 > 0x7F || uc3 > 0x7F)
+ return QLocale::AnyLanguage;
+
+ const AlphaCode codeBuf = { { char(uc1), char(uc2), char(uc3) } };
+
+ auto searchCode = [codeBuf](auto f) {
+ return std::find_if(languageCodeList.begin(), languageCodeList.end(),
+ [=](const LanguageCodeEntry &i) { return f(i) == codeBuf; });
+ };
+
+ if (codeTypes.testFlag(QLocale::ISO639Part1) && uc3 == 0) {
+ auto i = searchCode([](const LanguageCodeEntry &i) { return i.part1; });
+ if (i != languageCodeList.end())
+ return QLocale::Language(std::distance(languageCodeList.begin(), i));
}
- if (uc3 == 0) {
+ if (uc3 != 0) {
+ if (codeTypes.testFlag(QLocale::ISO639Part2B)) {
+ auto i = searchCode([](const LanguageCodeEntry &i) { return i.part2B; });
+ if (i != languageCodeList.end())
+ return QLocale::Language(std::distance(languageCodeList.begin(), i));
+ }
+
+ // Optimization: Part 2T code if present is always the same as Part 3 code.
+ // This is asserted in iso639_3.LanguageCodeData.
+ if (codeTypes.testFlag(QLocale::ISO639Part2T)
+ && !codeTypes.testFlag(QLocale::ISO639Part3)) {
+ auto i = searchCode([](const LanguageCodeEntry &i) { return i.part2T; });
+ if (i != languageCodeList.end())
+ return QLocale::Language(std::distance(languageCodeList.begin(), i));
+ }
+
+ if (codeTypes.testFlag(QLocale::ISO639Part3)) {
+ auto i = searchCode([](const LanguageCodeEntry &i) { return i.part3; });
+ if (i != languageCodeList.end())
+ return QLocale::Language(std::distance(languageCodeList.begin(), i));
+ }
+ }
+
+ if (codeTypes.testFlag(QLocale::LegacyLanguageCode) && uc3 == 0) {
// legacy codes
if (uc1 == 'n' && uc2 == 'o') // no -> nb
return QLocale::NorwegianBokmal;
@@ -177,15 +213,29 @@ QLocale::Territory QLocalePrivate::codeToTerritory(QStringView code) noexcept
return QLocale::AnyTerritory;
}
-QLatin1String QLocalePrivate::languageToCode(QLocale::Language language)
+QLatin1String QLocalePrivate::languageToCode(QLocale::Language language,
+ QLocale::LanguageCodeTypes codeTypes)
{
if (language == QLocale::AnyLanguage || language > QLocale::LastLanguage)
return QLatin1String();
if (language == QLocale::C)
return QLatin1String("C");
- const unsigned char *c = language_code_list + 3 * language;
- return QLatin1String(reinterpret_cast<const char*>(c), c[2] == 0 ? 2 : 3);
+ const LanguageCodeEntry &i = languageCodeList[language];
+
+ if (codeTypes.testFlag(QLocale::ISO639Part1) && i.part1.isValid())
+ return QLatin1String(i.part1.code, 2);
+
+ if (codeTypes.testFlag(QLocale::ISO639Part2B) && i.part2B.isValid())
+ return QLatin1String(i.part2B.code, 3);
+
+ if (codeTypes.testFlag(QLocale::ISO639Part2T) && i.part2T.isValid())
+ return QLatin1String(i.part2T.code, 3);
+
+ if (codeTypes.testFlag(QLocale::ISO639Part3))
+ return QLatin1String(i.part3.code, 3);
+
+ return QLatin1String();
}
QLatin1String QLocalePrivate::scriptToCode(QLocale::Script script)
@@ -370,20 +420,32 @@ QByteArray QLocaleId::name(char separator) const
if (language_id == QLocale::C)
return QByteArrayLiteral("C");
- const unsigned char *lang = language_code_list + 3 * language_id;
+ const LanguageCodeEntry &language = languageCodeList[language_id];
+ const char *lang;
+ qsizetype langLen;
+
+ if (language.part1.isValid()) {
+ lang = language.part1.code;
+ langLen = 2;
+ } else {
+ lang = language.part2B.isValid() ? language.part2B.code : language.part3.code;
+ langLen = 3;
+ }
+
const unsigned char *script =
(script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : nullptr);
const unsigned char *country =
(territory_id != QLocale::AnyTerritory
? territory_code_list + 3 * territory_id : nullptr);
- char len = (lang[2] != 0 ? 3 : 2) + (script ? 4 + 1 : 0)
- + (country ? (country[2] != 0 ? 3 : 2) + 1 : 0);
+ qsizetype len = langLen + (script ? 4 + 1 : 0) + (country ? (country[2] != 0 ? 3 : 2) + 1 : 0);
QByteArray name(len, Qt::Uninitialized);
char *uc = name.data();
+
*uc++ = lang[0];
*uc++ = lang[1];
- if (lang[2] != 0)
+ if (langLen > 2)
*uc++ = lang[2];
+
if (script) {
*uc++ = separator;
*uc++ = script[0];
@@ -1348,30 +1410,66 @@ QString QLocale::bcp47Name() const
Returns the two- or three-letter language code for \a language, as defined
in the ISO 639 standards.
+ If specified, \a codeTypes selects which set of codes to consider. The first
+ code from the set that is defined for \a language is returned. Otherwise,
+ all ISO-639 codes are considered. The codes are considered in the following
+ order: \c ISO639Part1, \c ISO639Part2B, \c ISO639Part2T, \c ISO639Part3.
+ \c LegacyLanguageCode is ignored by this function.
+
\note For \c{QLocale::C} the function returns \c{"C"}.
For \c QLocale::AnyLanguage an empty string is returned.
+ If the language has no code in any selected code set, an empty string
+ is returned.
- \since 6.1
+ \since 6.3
\sa codeToLanguage(), language(), name(), bcp47Name(), territoryToCode(), scriptToCode()
*/
+QString QLocale::languageToCode(Language language, LanguageCodeTypes codeTypes)
+{
+ return QLocalePrivate::languageToCode(language, codeTypes);
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+/*!
+ \overload
+ \since 6.1
+*/
QString QLocale::languageToCode(Language language)
{
return QLocalePrivate::languageToCode(language);
}
+#endif
/*!
Returns the QLocale::Language enum corresponding to the two- or three-letter
\a languageCode, as defined in the ISO 639 standards.
- If the code is invalid or not known QLocale::AnyLanguage is returned.
+ If specified, \a codeTypes selects which set of codes to consider for
+ conversion. By default all codes known to Qt are considered. The codes are
+ matched in the following order: \c ISO639Part1, \c ISO639Part2B,
+ \c ISO639Part2T, \c ISO639Part3, \c LegacyLanguageCode.
- \since 6.1
+ If the code is invalid or not known \c QLocale::AnyLanguage is returned.
+
+ \since 6.3
\sa languageToCode(), codeToTerritory(), codeToScript()
*/
+QLocale::Language QLocale::codeToLanguage(QStringView languageCode,
+ LanguageCodeTypes codeTypes) noexcept
+{
+ return QLocalePrivate::codeToLanguage(languageCode, codeTypes);
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+/*!
+ \overload
+ \since 6.1
+*/
QLocale::Language QLocale::codeToLanguage(QStringView languageCode) noexcept
{
return QLocalePrivate::codeToLanguage(languageCode);
}
+#endif
/*!
\since 6.2
diff --git a/src/corelib/text/qlocale.h b/src/corelib/text/qlocale.h
index 82852524eb..0a583b0881 100644
--- a/src/corelib/text/qlocale.h
+++ b/src/corelib/text/qlocale.h
@@ -1088,8 +1088,32 @@ public:
QStringList uiLanguages() const;
+ enum LanguageCodeType {
+ ISO639Part1 = 1 << 0,
+ ISO639Part2B = 1 << 1,
+ ISO639Part2T = 1 << 2,
+ ISO639Part3 = 1 << 3,
+ LegacyLanguageCode = 1 << 15,
+
+ ISO639Part2 = ISO639Part2B | ISO639Part2T,
+ ISO639Alpha2 = ISO639Part1,
+ ISO639Alpha3 = ISO639Part2 | ISO639Part3,
+ ISO639 = ISO639Alpha2 | ISO639Alpha3,
+
+ AnyLanguageCode = -1
+ };
+ Q_DECLARE_FLAGS(LanguageCodeTypes, LanguageCodeType)
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
static QString languageToCode(Language language);
+ static QString languageToCode(Language language, LanguageCodeTypes codeTypes);
static Language codeToLanguage(QStringView languageCode) noexcept;
+ static Language codeToLanguage(QStringView languageCode, LanguageCodeTypes codeTypes) noexcept;
+#else
+ static QString languageToCode(Language language, LanguageCodeTypes codeTypes = AnyLanguageCode);
+ static Language codeToLanguage(QStringView languageCode,
+ LanguageCodeTypes codeTypes = AnyLanguageCode) noexcept;
+#endif
static QString territoryToCode(Territory territory);
static Territory codeToTerritory(QStringView territoryCode) noexcept;
#if QT_DEPRECATED_SINCE(6, 6)
@@ -1146,6 +1170,7 @@ private:
};
Q_DECLARE_SHARED(QLocale)
Q_DECLARE_OPERATORS_FOR_FLAGS(QLocale::NumberOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QLocale::LanguageCodeTypes)
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QLocale &);
diff --git a/src/corelib/text/qlocale.qdoc b/src/corelib/text/qlocale.qdoc
index dc9c4e632f..9ea24d1433 100644
--- a/src/corelib/text/qlocale.qdoc
+++ b/src/corelib/text/qlocale.qdoc
@@ -1033,6 +1033,25 @@
\since 4.4
*/
+/*!
+ \enum QLocale::LanguageCodeType
+
+ This enum defines language code types that can be used to restrict set
+ of language codes considered by \c codeToLanguage and \c languageToCode.
+
+ \value ISO639Part1 ISO 639 Part 1 Alpha 2 code.
+ \value ISO639Part2B ISO 639 Part 2 bibliographic Alpha 3 code.
+ \value ISO639Part2T ISO 639 Part 2 terminological Alpha 3 code.
+ \value ISO639Part3 ISO 639 Part 3 Alpha 3 code.
+ \value LegacyLanguageCode Codes that are not part of the above set, but that
+ were supported by Qt in the past. This value can only be used by
+ codeToLanguage(). It is ignored when passed to languageToCode().
+ \value ISO639Part2 Any ISO 639 Part 2 code.
+ \value ISO639Alpha2 Any ISO-639 2-letter code.
+ \value ISO639Alpha3 Any ISO-639 3-letter code.
+ \value ISO639 Any ISO 639 code.
+ \value AnyLanguageCode Specifies that any code can be used.
+*/
/*!
\fn bool QLocale::operator==(const QLocale &lhs, const QLocale &rhs)
diff --git a/src/corelib/text/qlocale_data_p.h b/src/corelib/text/qlocale_data_p.h
index 4bd4d256b4..b0ed889762 100644
--- a/src/corelib/text/qlocale_data_p.h
+++ b/src/corelib/text/qlocale_data_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
+#include <array>
+#include <QtCore/qendian.h>
#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -74,10 +76,29 @@ static const TerritoryLanguage ImperialMeasurementSystems[] = {
static const int ImperialMeasurementSystemsCount =
sizeof(ImperialMeasurementSystems)/sizeof(ImperialMeasurementSystems[0]);
+/*
+ Storage for alpha codes with length of up to 4 allowing efficient comparison.
+*/
+struct alignas(uint32_t) AlphaCode {
+ char code[4];
+
+ bool isValid() const noexcept { return asU32() != 0; }
+ bool operator==(AlphaCode other) const noexcept { return asU32() == other.asU32(); }
+private:
+ uint32_t asU32() const noexcept { return qFromUnaligned<uint32_t>(code); }
+};
+
+struct LanguageCodeEntry {
+ AlphaCode part1;
+ AlphaCode part2B;
+ AlphaCode part2T;
+ AlphaCode part3;
+};
+
// GENERATED PART STARTS HERE
/*
- This part of the file was generated on 2021-11-09 from the
+ This part of the file was generated on 2021-12-03 from the
Common Locale Data Repository v40
http://www.unicode.org/cldr/
@@ -5337,338 +5358,338 @@ static const quint16 territory_name_index[] = {
2824, // Zimbabwe
};
-static const unsigned char language_code_list[] =
-" \0" // AnyLanguage
-" \0" // C
-"ab\0" // Abkhazian
-"aa\0" // Afar
-"af\0" // Afrikaans
-"agq" // Aghem
-"ak\0" // Akan
-"akk" // Akkadian
-"bss" // Akoose
-"sq\0" // Albanian
-"ase" // American Sign Language
-"am\0" // Amharic
-"egy" // Ancient Egyptian
-"grc" // Ancient Greek
-"ar\0" // Arabic
-"an\0" // Aragonese
-"arc" // Aramaic
-"hy\0" // Armenian
-"as\0" // Assamese
-"ast" // Asturian
-"asa" // Asu
-"cch" // Atsam
-"av\0" // Avaric
-"ae\0" // Avestan
-"ay\0" // Aymara
-"az\0" // Azerbaijani
-"ksf" // Bafia
-"ban" // Balinese
-"bm\0" // Bambara
-"bax" // Bamun
-"bn\0" // Bangla
-"bas" // Basaa
-"ba\0" // Bashkir
-"eu\0" // Basque
-"bbc" // Batak Toba
-"be\0" // Belarusian
-"bem" // Bemba
-"bez" // Bena
-"bho" // Bhojpuri
-"bi\0" // Bislama
-"byn" // Blin
-"brx" // Bodo
-"bs\0" // Bosnian
-"br\0" // Breton
-"bug" // Buginese
-"bg\0" // Bulgarian
-"my\0" // Burmese
-"yue" // Cantonese
-"ca\0" // Catalan
-"ceb" // Cebuano
-"tzm" // Central Atlas Tamazight
-"ckb" // Central Kurdish
-"ccp" // Chakma
-"ch\0" // Chamorro
-"ce\0" // Chechen
-"chr" // Cherokee
-"cic" // Chickasaw
-"cgg" // Chiga
-"zh\0" // Chinese
-"cu\0" // Church
-"cv\0" // Chuvash
-"ksh" // Colognian
-"cop" // Coptic
-"kw\0" // Cornish
-"co\0" // Corsican
-"cr\0" // Cree
-"hr\0" // Croatian
-"cs\0" // Czech
-"da\0" // Danish
-"dv\0" // Divehi
-"doi" // Dogri
-"dua" // Duala
-"nl\0" // Dutch
-"dz\0" // Dzongkha
-"ebu" // Embu
-"en\0" // English
-"myv" // Erzya
-"eo\0" // Esperanto
-"et\0" // Estonian
-"ee\0" // Ewe
-"ewo" // Ewondo
-"fo\0" // Faroese
-"fj\0" // Fijian
-"fil" // Filipino
-"fi\0" // Finnish
-"fr\0" // French
-"fur" // Friulian
-"ff\0" // Fulah
-"gd\0" // Gaelic
-"gaa" // Ga
-"gl\0" // Galician
-"lg\0" // Ganda
-"gez" // Geez
-"ka\0" // Georgian
-"de\0" // German
-"got" // Gothic
-"el\0" // Greek
-"gn\0" // Guarani
-"gu\0" // Gujarati
-"guz" // Gusii
-"ht\0" // Haitian
-"ha\0" // Hausa
-"haw" // Hawaiian
-"he\0" // Hebrew
-"hz\0" // Herero
-"hi\0" // Hindi
-"ho\0" // Hiri Motu
-"hu\0" // Hungarian
-"is\0" // Icelandic
-"io\0" // Ido
-"ig\0" // Igbo
-"smn" // Inari Sami
-"id\0" // Indonesian
-"inh" // Ingush
-"ia\0" // Interlingua
-"ie\0" // Interlingue
-"iu\0" // Inuktitut
-"ik\0" // Inupiaq
-"ga\0" // Irish
-"it\0" // Italian
-"ja\0" // Japanese
-"jv\0" // Javanese
-"kaj" // Jju
-"dyo" // Jola Fonyi
-"kea" // Kabuverdianu
-"kab" // Kabyle
-"kkj" // Kako
-"kl\0" // Kalaallisut
-"kln" // Kalenjin
-"kam" // Kamba
-"kn\0" // Kannada
-"kr\0" // Kanuri
-"ks\0" // Kashmiri
-"kk\0" // Kazakh
-"ken" // Kenyang
-"km\0" // Khmer
-"quc" // Kiche
-"ki\0" // Kikuyu
-"rw\0" // Kinyarwanda
-"kv\0" // Komi
-"kg\0" // Kongo
-"kok" // Konkani
-"ko\0" // Korean
-"kfo" // Koro
-"ses" // Koyraboro Senni
-"khq" // Koyra Chiini
-"kpe" // Kpelle
-"kj\0" // Kuanyama
-"ku\0" // Kurdish
-"nmg" // Kwasio
-"ky\0" // Kyrgyz
-"lkt" // Lakota
-"lag" // Langi
-"lo\0" // Lao
-"la\0" // Latin
-"lv\0" // Latvian
-"lez" // Lezghian
-"li\0" // Limburgish
-"ln\0" // Lingala
-"lzh" // Literary Chinese
-"lt\0" // Lithuanian
-"jbo" // Lojban
-"dsb" // Lower Sorbian
-"nds" // Low German
-"lu\0" // Luba Katanga
-"smj" // Lule Sami
-"luo" // Luo
-"lb\0" // Luxembourgish
-"luy" // Luyia
-"mk\0" // Macedonian
-"jmc" // Machame
-"mai" // Maithili
-"mgh" // Makhuwa Meetto
-"kde" // Makonde
-"mg\0" // Malagasy
-"ml\0" // Malayalam
-"ms\0" // Malay
-"mt\0" // Maltese
-"man" // Mandingo
-"mni" // Manipuri
-"gv\0" // Manx
-"mi\0" // Maori
-"arn" // Mapuche
-"mr\0" // Marathi
-"mh\0" // Marshallese
-"mas" // Masai
-"mzn" // Mazanderani
-"men" // Mende
-"mer" // Meru
-"mgo" // Meta
-"moh" // Mohawk
-"mn\0" // Mongolian
-"mfe" // Morisyen
-"mua" // Mundang
-"mus" // Muscogee
-"naq" // Nama
-"na\0" // Nauru
-"nv\0" // Navajo
-"ng\0" // Ndonga
-"ne\0" // Nepali
-"new" // Newari
-"nnh" // Ngiemboon
-"jgo" // Ngomba
-"pcm" // Nigerian Pidgin
-"nqo" // Nko
-"lrc" // Northern Luri
-"se\0" // Northern Sami
-"nso" // Northern Sotho
-"nd\0" // North Ndebele
-"nb\0" // Norwegian Bokmal
-"nn\0" // Norwegian Nynorsk
-"nus" // Nuer
-"ny\0" // Nyanja
-"nyn" // Nyankole
-"oc\0" // Occitan
-"or\0" // Odia
-"oj\0" // Ojibwa
-"sga" // Old Irish
-"non" // Old Norse
-"peo" // Old Persian
-"om\0" // Oromo
-"osa" // Osage
-"os\0" // Ossetic
-"pal" // Pahlavi
-"pau" // Palauan
-"pi\0" // Pali
-"pap" // Papiamento
-"ps\0" // Pashto
-"fa\0" // Persian
-"phn" // Phoenician
-"pl\0" // Polish
-"pt\0" // Portuguese
-"prg" // Prussian
-"pa\0" // Punjabi
-"qu\0" // Quechua
-"ro\0" // Romanian
-"rm\0" // Romansh
-"rof" // Rombo
-"rn\0" // Rundi
-"ru\0" // Russian
-"rwk" // Rwa
-"ssy" // Saho
-"sah" // Sakha
-"saq" // Samburu
-"sm\0" // Samoan
-"sg\0" // Sango
-"sbp" // Sangu
-"sa\0" // Sanskrit
-"sat" // Santali
-"sc\0" // Sardinian
-"saz" // Saurashtra
-"seh" // Sena
-"sr\0" // Serbian
-"ksb" // Shambala
-"sn\0" // Shona
-"ii\0" // Sichuan Yi
-"scn" // Sicilian
-"sid" // Sidamo
-"szl" // Silesian
-"sd\0" // Sindhi
-"si\0" // Sinhala
-"sms" // Skolt Sami
-"sk\0" // Slovak
-"sl\0" // Slovenian
-"xog" // Soga
-"so\0" // Somali
-"sdh" // Southern Kurdish
-"sma" // Southern Sami
-"st\0" // Southern Sotho
-"nr\0" // South Ndebele
-"es\0" // Spanish
-"zgh" // Standard Moroccan Tamazight
-"su\0" // Sundanese
-"sw\0" // Swahili
-"ss\0" // Swati
-"sv\0" // Swedish
-"gsw" // Swiss German
-"syr" // Syriac
-"shi" // Tachelhit
-"ty\0" // Tahitian
-"blt" // Tai Dam
-"dav" // Taita
-"tg\0" // Tajik
-"ta\0" // Tamil
-"trv" // Taroko
-"twq" // Tasawaq
-"tt\0" // Tatar
-"te\0" // Telugu
-"teo" // Teso
-"th\0" // Thai
-"bo\0" // Tibetan
-"tig" // Tigre
-"ti\0" // Tigrinya
-"tkl" // Tokelau
-"tpi" // Tok Pisin
-"to\0" // Tongan
-"ts\0" // Tsonga
-"tn\0" // Tswana
-"tr\0" // Turkish
-"tk\0" // Turkmen
-"tvl" // Tuvalu
-"kcg" // Tyap
-"uga" // Ugaritic
-"uk\0" // Ukrainian
-"hsb" // Upper Sorbian
-"ur\0" // Urdu
-"ug\0" // Uyghur
-"uz\0" // Uzbek
-"vai" // Vai
-"ve\0" // Venda
-"vi\0" // Vietnamese
-"vo\0" // Volapuk
-"vun" // Vunjo
-"wa\0" // Walloon
-"wae" // Walser
-"wbp" // Warlpiri
-"cy\0" // Welsh
-"bgn" // Western Balochi
-"fy\0" // Western Frisian
-"wal" // Wolaytta
-"wo\0" // Wolof
-"xh\0" // Xhosa
-"yav" // Yangben
-"yi\0" // Yiddish
-"yo\0" // Yoruba
-"dje" // Zarma
-"za\0" // Zhuang
-"zu\0" // Zulu
-"kgp" // Kaingang
-"yrl" // Nheengatu
-;
+constexpr std::array<LanguageCodeEntry, 330> languageCodeList {
+ LanguageCodeEntry {{}, {{'u', 'n', 'd'}}, {{'u', 'n', 'd'}}, {{'u', 'n', 'd'}}}, // AnyLanguage
+ LanguageCodeEntry {{}, {{'u', 'n', 'd'}}, {{'u', 'n', 'd'}}, {{'u', 'n', 'd'}}}, // C
+ LanguageCodeEntry {{{'a', 'b'}}, {{'a', 'b', 'k'}}, {{'a', 'b', 'k'}}, {{'a', 'b', 'k'}}}, // Abkhazian
+ LanguageCodeEntry {{{'a', 'a'}}, {{'a', 'a', 'r'}}, {{'a', 'a', 'r'}}, {{'a', 'a', 'r'}}}, // Afar
+ LanguageCodeEntry {{{'a', 'f'}}, {{'a', 'f', 'r'}}, {{'a', 'f', 'r'}}, {{'a', 'f', 'r'}}}, // Afrikaans
+ LanguageCodeEntry {{}, {}, {}, {{'a', 'g', 'q'}}}, // Aghem
+ LanguageCodeEntry {{{'a', 'k'}}, {{'a', 'k', 'a'}}, {{'a', 'k', 'a'}}, {{'a', 'k', 'a'}}}, // Akan
+ LanguageCodeEntry {{}, {{'a', 'k', 'k'}}, {{'a', 'k', 'k'}}, {{'a', 'k', 'k'}}}, // Akkadian
+ LanguageCodeEntry {{}, {}, {}, {{'b', 's', 's'}}}, // Akoose
+ LanguageCodeEntry {{{'s', 'q'}}, {{'a', 'l', 'b'}}, {{'s', 'q', 'i'}}, {{'s', 'q', 'i'}}}, // Albanian
+ LanguageCodeEntry {{}, {}, {}, {{'a', 's', 'e'}}}, // American Sign Language
+ LanguageCodeEntry {{{'a', 'm'}}, {{'a', 'm', 'h'}}, {{'a', 'm', 'h'}}, {{'a', 'm', 'h'}}}, // Amharic
+ LanguageCodeEntry {{}, {{'e', 'g', 'y'}}, {{'e', 'g', 'y'}}, {{'e', 'g', 'y'}}}, // Ancient Egyptian
+ LanguageCodeEntry {{}, {{'g', 'r', 'c'}}, {{'g', 'r', 'c'}}, {{'g', 'r', 'c'}}}, // Ancient Greek
+ LanguageCodeEntry {{{'a', 'r'}}, {{'a', 'r', 'a'}}, {{'a', 'r', 'a'}}, {{'a', 'r', 'a'}}}, // Arabic
+ LanguageCodeEntry {{{'a', 'n'}}, {{'a', 'r', 'g'}}, {{'a', 'r', 'g'}}, {{'a', 'r', 'g'}}}, // Aragonese
+ LanguageCodeEntry {{}, {{'a', 'r', 'c'}}, {{'a', 'r', 'c'}}, {{'a', 'r', 'c'}}}, // Aramaic
+ LanguageCodeEntry {{{'h', 'y'}}, {{'a', 'r', 'm'}}, {{'h', 'y', 'e'}}, {{'h', 'y', 'e'}}}, // Armenian
+ LanguageCodeEntry {{{'a', 's'}}, {{'a', 's', 'm'}}, {{'a', 's', 'm'}}, {{'a', 's', 'm'}}}, // Assamese
+ LanguageCodeEntry {{}, {{'a', 's', 't'}}, {{'a', 's', 't'}}, {{'a', 's', 't'}}}, // Asturian
+ LanguageCodeEntry {{}, {}, {}, {{'a', 's', 'a'}}}, // Asu
+ LanguageCodeEntry {{}, {}, {}, {{'c', 'c', 'h'}}}, // Atsam
+ LanguageCodeEntry {{{'a', 'v'}}, {{'a', 'v', 'a'}}, {{'a', 'v', 'a'}}, {{'a', 'v', 'a'}}}, // Avaric
+ LanguageCodeEntry {{{'a', 'e'}}, {{'a', 'v', 'e'}}, {{'a', 'v', 'e'}}, {{'a', 'v', 'e'}}}, // Avestan
+ LanguageCodeEntry {{{'a', 'y'}}, {{'a', 'y', 'm'}}, {{'a', 'y', 'm'}}, {{'a', 'y', 'm'}}}, // Aymara
+ LanguageCodeEntry {{{'a', 'z'}}, {{'a', 'z', 'e'}}, {{'a', 'z', 'e'}}, {{'a', 'z', 'e'}}}, // Azerbaijani
+ LanguageCodeEntry {{}, {}, {}, {{'k', 's', 'f'}}}, // Bafia
+ LanguageCodeEntry {{}, {{'b', 'a', 'n'}}, {{'b', 'a', 'n'}}, {{'b', 'a', 'n'}}}, // Balinese
+ LanguageCodeEntry {{{'b', 'm'}}, {{'b', 'a', 'm'}}, {{'b', 'a', 'm'}}, {{'b', 'a', 'm'}}}, // Bambara
+ LanguageCodeEntry {{}, {}, {}, {{'b', 'a', 'x'}}}, // Bamun
+ LanguageCodeEntry {{{'b', 'n'}}, {{'b', 'e', 'n'}}, {{'b', 'e', 'n'}}, {{'b', 'e', 'n'}}}, // Bangla
+ LanguageCodeEntry {{}, {{'b', 'a', 's'}}, {{'b', 'a', 's'}}, {{'b', 'a', 's'}}}, // Basaa
+ LanguageCodeEntry {{{'b', 'a'}}, {{'b', 'a', 'k'}}, {{'b', 'a', 'k'}}, {{'b', 'a', 'k'}}}, // Bashkir
+ LanguageCodeEntry {{{'e', 'u'}}, {{'b', 'a', 'q'}}, {{'e', 'u', 's'}}, {{'e', 'u', 's'}}}, // Basque
+ LanguageCodeEntry {{}, {}, {}, {{'b', 'b', 'c'}}}, // Batak Toba
+ LanguageCodeEntry {{{'b', 'e'}}, {{'b', 'e', 'l'}}, {{'b', 'e', 'l'}}, {{'b', 'e', 'l'}}}, // Belarusian
+ LanguageCodeEntry {{}, {{'b', 'e', 'm'}}, {{'b', 'e', 'm'}}, {{'b', 'e', 'm'}}}, // Bemba
+ LanguageCodeEntry {{}, {}, {}, {{'b', 'e', 'z'}}}, // Bena
+ LanguageCodeEntry {{}, {{'b', 'h', 'o'}}, {{'b', 'h', 'o'}}, {{'b', 'h', 'o'}}}, // Bhojpuri
+ LanguageCodeEntry {{{'b', 'i'}}, {{'b', 'i', 's'}}, {{'b', 'i', 's'}}, {{'b', 'i', 's'}}}, // Bislama
+ LanguageCodeEntry {{}, {{'b', 'y', 'n'}}, {{'b', 'y', 'n'}}, {{'b', 'y', 'n'}}}, // Blin
+ LanguageCodeEntry {{}, {}, {}, {{'b', 'r', 'x'}}}, // Bodo
+ LanguageCodeEntry {{{'b', 's'}}, {{'b', 'o', 's'}}, {{'b', 'o', 's'}}, {{'b', 'o', 's'}}}, // Bosnian
+ LanguageCodeEntry {{{'b', 'r'}}, {{'b', 'r', 'e'}}, {{'b', 'r', 'e'}}, {{'b', 'r', 'e'}}}, // Breton
+ LanguageCodeEntry {{}, {{'b', 'u', 'g'}}, {{'b', 'u', 'g'}}, {{'b', 'u', 'g'}}}, // Buginese
+ LanguageCodeEntry {{{'b', 'g'}}, {{'b', 'u', 'l'}}, {{'b', 'u', 'l'}}, {{'b', 'u', 'l'}}}, // Bulgarian
+ LanguageCodeEntry {{{'m', 'y'}}, {{'b', 'u', 'r'}}, {{'m', 'y', 'a'}}, {{'m', 'y', 'a'}}}, // Burmese
+ LanguageCodeEntry {{}, {}, {}, {{'y', 'u', 'e'}}}, // Cantonese
+ LanguageCodeEntry {{{'c', 'a'}}, {{'c', 'a', 't'}}, {{'c', 'a', 't'}}, {{'c', 'a', 't'}}}, // Catalan
+ LanguageCodeEntry {{}, {{'c', 'e', 'b'}}, {{'c', 'e', 'b'}}, {{'c', 'e', 'b'}}}, // Cebuano
+ LanguageCodeEntry {{}, {}, {}, {{'t', 'z', 'm'}}}, // Central Atlas Tamazight
+ LanguageCodeEntry {{}, {}, {}, {{'c', 'k', 'b'}}}, // Central Kurdish
+ LanguageCodeEntry {{}, {}, {}, {{'c', 'c', 'p'}}}, // Chakma
+ LanguageCodeEntry {{{'c', 'h'}}, {{'c', 'h', 'a'}}, {{'c', 'h', 'a'}}, {{'c', 'h', 'a'}}}, // Chamorro
+ LanguageCodeEntry {{{'c', 'e'}}, {{'c', 'h', 'e'}}, {{'c', 'h', 'e'}}, {{'c', 'h', 'e'}}}, // Chechen
+ LanguageCodeEntry {{}, {{'c', 'h', 'r'}}, {{'c', 'h', 'r'}}, {{'c', 'h', 'r'}}}, // Cherokee
+ LanguageCodeEntry {{}, {}, {}, {{'c', 'i', 'c'}}}, // Chickasaw
+ LanguageCodeEntry {{}, {}, {}, {{'c', 'g', 'g'}}}, // Chiga
+ LanguageCodeEntry {{{'z', 'h'}}, {{'c', 'h', 'i'}}, {{'z', 'h', 'o'}}, {{'z', 'h', 'o'}}}, // Chinese
+ LanguageCodeEntry {{{'c', 'u'}}, {{'c', 'h', 'u'}}, {{'c', 'h', 'u'}}, {{'c', 'h', 'u'}}}, // Church
+ LanguageCodeEntry {{{'c', 'v'}}, {{'c', 'h', 'v'}}, {{'c', 'h', 'v'}}, {{'c', 'h', 'v'}}}, // Chuvash
+ LanguageCodeEntry {{}, {}, {}, {{'k', 's', 'h'}}}, // Colognian
+ LanguageCodeEntry {{}, {{'c', 'o', 'p'}}, {{'c', 'o', 'p'}}, {{'c', 'o', 'p'}}}, // Coptic
+ LanguageCodeEntry {{{'k', 'w'}}, {{'c', 'o', 'r'}}, {{'c', 'o', 'r'}}, {{'c', 'o', 'r'}}}, // Cornish
+ LanguageCodeEntry {{{'c', 'o'}}, {{'c', 'o', 's'}}, {{'c', 'o', 's'}}, {{'c', 'o', 's'}}}, // Corsican
+ LanguageCodeEntry {{{'c', 'r'}}, {{'c', 'r', 'e'}}, {{'c', 'r', 'e'}}, {{'c', 'r', 'e'}}}, // Cree
+ LanguageCodeEntry {{{'h', 'r'}}, {{'h', 'r', 'v'}}, {{'h', 'r', 'v'}}, {{'h', 'r', 'v'}}}, // Croatian
+ LanguageCodeEntry {{{'c', 's'}}, {{'c', 'z', 'e'}}, {{'c', 'e', 's'}}, {{'c', 'e', 's'}}}, // Czech
+ LanguageCodeEntry {{{'d', 'a'}}, {{'d', 'a', 'n'}}, {{'d', 'a', 'n'}}, {{'d', 'a', 'n'}}}, // Danish
+ LanguageCodeEntry {{{'d', 'v'}}, {{'d', 'i', 'v'}}, {{'d', 'i', 'v'}}, {{'d', 'i', 'v'}}}, // Divehi
+ LanguageCodeEntry {{}, {{'d', 'o', 'i'}}, {{'d', 'o', 'i'}}, {{'d', 'o', 'i'}}}, // Dogri
+ LanguageCodeEntry {{}, {{'d', 'u', 'a'}}, {{'d', 'u', 'a'}}, {{'d', 'u', 'a'}}}, // Duala
+ LanguageCodeEntry {{{'n', 'l'}}, {{'d', 'u', 't'}}, {{'n', 'l', 'd'}}, {{'n', 'l', 'd'}}}, // Dutch
+ LanguageCodeEntry {{{'d', 'z'}}, {{'d', 'z', 'o'}}, {{'d', 'z', 'o'}}, {{'d', 'z', 'o'}}}, // Dzongkha
+ LanguageCodeEntry {{}, {}, {}, {{'e', 'b', 'u'}}}, // Embu
+ LanguageCodeEntry {{{'e', 'n'}}, {{'e', 'n', 'g'}}, {{'e', 'n', 'g'}}, {{'e', 'n', 'g'}}}, // English
+ LanguageCodeEntry {{}, {{'m', 'y', 'v'}}, {{'m', 'y', 'v'}}, {{'m', 'y', 'v'}}}, // Erzya
+ LanguageCodeEntry {{{'e', 'o'}}, {{'e', 'p', 'o'}}, {{'e', 'p', 'o'}}, {{'e', 'p', 'o'}}}, // Esperanto
+ LanguageCodeEntry {{{'e', 't'}}, {{'e', 's', 't'}}, {{'e', 's', 't'}}, {{'e', 's', 't'}}}, // Estonian
+ LanguageCodeEntry {{{'e', 'e'}}, {{'e', 'w', 'e'}}, {{'e', 'w', 'e'}}, {{'e', 'w', 'e'}}}, // Ewe
+ LanguageCodeEntry {{}, {{'e', 'w', 'o'}}, {{'e', 'w', 'o'}}, {{'e', 'w', 'o'}}}, // Ewondo
+ LanguageCodeEntry {{{'f', 'o'}}, {{'f', 'a', 'o'}}, {{'f', 'a', 'o'}}, {{'f', 'a', 'o'}}}, // Faroese
+ LanguageCodeEntry {{{'f', 'j'}}, {{'f', 'i', 'j'}}, {{'f', 'i', 'j'}}, {{'f', 'i', 'j'}}}, // Fijian
+ LanguageCodeEntry {{}, {{'f', 'i', 'l'}}, {{'f', 'i', 'l'}}, {{'f', 'i', 'l'}}}, // Filipino
+ LanguageCodeEntry {{{'f', 'i'}}, {{'f', 'i', 'n'}}, {{'f', 'i', 'n'}}, {{'f', 'i', 'n'}}}, // Finnish
+ LanguageCodeEntry {{{'f', 'r'}}, {{'f', 'r', 'e'}}, {{'f', 'r', 'a'}}, {{'f', 'r', 'a'}}}, // French
+ LanguageCodeEntry {{}, {{'f', 'u', 'r'}}, {{'f', 'u', 'r'}}, {{'f', 'u', 'r'}}}, // Friulian
+ LanguageCodeEntry {{{'f', 'f'}}, {{'f', 'u', 'l'}}, {{'f', 'u', 'l'}}, {{'f', 'u', 'l'}}}, // Fulah
+ LanguageCodeEntry {{{'g', 'd'}}, {{'g', 'l', 'a'}}, {{'g', 'l', 'a'}}, {{'g', 'l', 'a'}}}, // Gaelic
+ LanguageCodeEntry {{}, {{'g', 'a', 'a'}}, {{'g', 'a', 'a'}}, {{'g', 'a', 'a'}}}, // Ga
+ LanguageCodeEntry {{{'g', 'l'}}, {{'g', 'l', 'g'}}, {{'g', 'l', 'g'}}, {{'g', 'l', 'g'}}}, // Galician
+ LanguageCodeEntry {{{'l', 'g'}}, {{'l', 'u', 'g'}}, {{'l', 'u', 'g'}}, {{'l', 'u', 'g'}}}, // Ganda
+ LanguageCodeEntry {{}, {{'g', 'e', 'z'}}, {{'g', 'e', 'z'}}, {{'g', 'e', 'z'}}}, // Geez
+ LanguageCodeEntry {{{'k', 'a'}}, {{'g', 'e', 'o'}}, {{'k', 'a', 't'}}, {{'k', 'a', 't'}}}, // Georgian
+ LanguageCodeEntry {{{'d', 'e'}}, {{'g', 'e', 'r'}}, {{'d', 'e', 'u'}}, {{'d', 'e', 'u'}}}, // German
+ LanguageCodeEntry {{}, {{'g', 'o', 't'}}, {{'g', 'o', 't'}}, {{'g', 'o', 't'}}}, // Gothic
+ LanguageCodeEntry {{{'e', 'l'}}, {{'g', 'r', 'e'}}, {{'e', 'l', 'l'}}, {{'e', 'l', 'l'}}}, // Greek
+ LanguageCodeEntry {{{'g', 'n'}}, {{'g', 'r', 'n'}}, {{'g', 'r', 'n'}}, {{'g', 'r', 'n'}}}, // Guarani
+ LanguageCodeEntry {{{'g', 'u'}}, {{'g', 'u', 'j'}}, {{'g', 'u', 'j'}}, {{'g', 'u', 'j'}}}, // Gujarati
+ LanguageCodeEntry {{}, {}, {}, {{'g', 'u', 'z'}}}, // Gusii
+ LanguageCodeEntry {{{'h', 't'}}, {{'h', 'a', 't'}}, {{'h', 'a', 't'}}, {{'h', 'a', 't'}}}, // Haitian
+ LanguageCodeEntry {{{'h', 'a'}}, {{'h', 'a', 'u'}}, {{'h', 'a', 'u'}}, {{'h', 'a', 'u'}}}, // Hausa
+ LanguageCodeEntry {{}, {{'h', 'a', 'w'}}, {{'h', 'a', 'w'}}, {{'h', 'a', 'w'}}}, // Hawaiian
+ LanguageCodeEntry {{{'h', 'e'}}, {{'h', 'e', 'b'}}, {{'h', 'e', 'b'}}, {{'h', 'e', 'b'}}}, // Hebrew
+ LanguageCodeEntry {{{'h', 'z'}}, {{'h', 'e', 'r'}}, {{'h', 'e', 'r'}}, {{'h', 'e', 'r'}}}, // Herero
+ LanguageCodeEntry {{{'h', 'i'}}, {{'h', 'i', 'n'}}, {{'h', 'i', 'n'}}, {{'h', 'i', 'n'}}}, // Hindi
+ LanguageCodeEntry {{{'h', 'o'}}, {{'h', 'm', 'o'}}, {{'h', 'm', 'o'}}, {{'h', 'm', 'o'}}}, // Hiri Motu
+ LanguageCodeEntry {{{'h', 'u'}}, {{'h', 'u', 'n'}}, {{'h', 'u', 'n'}}, {{'h', 'u', 'n'}}}, // Hungarian
+ LanguageCodeEntry {{{'i', 's'}}, {{'i', 'c', 'e'}}, {{'i', 's', 'l'}}, {{'i', 's', 'l'}}}, // Icelandic
+ LanguageCodeEntry {{{'i', 'o'}}, {{'i', 'd', 'o'}}, {{'i', 'd', 'o'}}, {{'i', 'd', 'o'}}}, // Ido
+ LanguageCodeEntry {{{'i', 'g'}}, {{'i', 'b', 'o'}}, {{'i', 'b', 'o'}}, {{'i', 'b', 'o'}}}, // Igbo
+ LanguageCodeEntry {{}, {{'s', 'm', 'n'}}, {{'s', 'm', 'n'}}, {{'s', 'm', 'n'}}}, // Inari Sami
+ LanguageCodeEntry {{{'i', 'd'}}, {{'i', 'n', 'd'}}, {{'i', 'n', 'd'}}, {{'i', 'n', 'd'}}}, // Indonesian
+ LanguageCodeEntry {{}, {{'i', 'n', 'h'}}, {{'i', 'n', 'h'}}, {{'i', 'n', 'h'}}}, // Ingush
+ LanguageCodeEntry {{{'i', 'a'}}, {{'i', 'n', 'a'}}, {{'i', 'n', 'a'}}, {{'i', 'n', 'a'}}}, // Interlingua
+ LanguageCodeEntry {{{'i', 'e'}}, {{'i', 'l', 'e'}}, {{'i', 'l', 'e'}}, {{'i', 'l', 'e'}}}, // Interlingue
+ LanguageCodeEntry {{{'i', 'u'}}, {{'i', 'k', 'u'}}, {{'i', 'k', 'u'}}, {{'i', 'k', 'u'}}}, // Inuktitut
+ LanguageCodeEntry {{{'i', 'k'}}, {{'i', 'p', 'k'}}, {{'i', 'p', 'k'}}, {{'i', 'p', 'k'}}}, // Inupiaq
+ LanguageCodeEntry {{{'g', 'a'}}, {{'g', 'l', 'e'}}, {{'g', 'l', 'e'}}, {{'g', 'l', 'e'}}}, // Irish
+ LanguageCodeEntry {{{'i', 't'}}, {{'i', 't', 'a'}}, {{'i', 't', 'a'}}, {{'i', 't', 'a'}}}, // Italian
+ LanguageCodeEntry {{{'j', 'a'}}, {{'j', 'p', 'n'}}, {{'j', 'p', 'n'}}, {{'j', 'p', 'n'}}}, // Japanese
+ LanguageCodeEntry {{{'j', 'v'}}, {{'j', 'a', 'v'}}, {{'j', 'a', 'v'}}, {{'j', 'a', 'v'}}}, // Javanese
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'a', 'j'}}}, // Jju
+ LanguageCodeEntry {{}, {}, {}, {{'d', 'y', 'o'}}}, // Jola Fonyi
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'e', 'a'}}}, // Kabuverdianu
+ LanguageCodeEntry {{}, {{'k', 'a', 'b'}}, {{'k', 'a', 'b'}}, {{'k', 'a', 'b'}}}, // Kabyle
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'k', 'j'}}}, // Kako
+ LanguageCodeEntry {{{'k', 'l'}}, {{'k', 'a', 'l'}}, {{'k', 'a', 'l'}}, {{'k', 'a', 'l'}}}, // Kalaallisut
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'l', 'n'}}}, // Kalenjin
+ LanguageCodeEntry {{}, {{'k', 'a', 'm'}}, {{'k', 'a', 'm'}}, {{'k', 'a', 'm'}}}, // Kamba
+ LanguageCodeEntry {{{'k', 'n'}}, {{'k', 'a', 'n'}}, {{'k', 'a', 'n'}}, {{'k', 'a', 'n'}}}, // Kannada
+ LanguageCodeEntry {{{'k', 'r'}}, {{'k', 'a', 'u'}}, {{'k', 'a', 'u'}}, {{'k', 'a', 'u'}}}, // Kanuri
+ LanguageCodeEntry {{{'k', 's'}}, {{'k', 'a', 's'}}, {{'k', 'a', 's'}}, {{'k', 'a', 's'}}}, // Kashmiri
+ LanguageCodeEntry {{{'k', 'k'}}, {{'k', 'a', 'z'}}, {{'k', 'a', 'z'}}, {{'k', 'a', 'z'}}}, // Kazakh
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'e', 'n'}}}, // Kenyang
+ LanguageCodeEntry {{{'k', 'm'}}, {{'k', 'h', 'm'}}, {{'k', 'h', 'm'}}, {{'k', 'h', 'm'}}}, // Khmer
+ LanguageCodeEntry {{}, {}, {}, {{'q', 'u', 'c'}}}, // Kiche
+ LanguageCodeEntry {{{'k', 'i'}}, {{'k', 'i', 'k'}}, {{'k', 'i', 'k'}}, {{'k', 'i', 'k'}}}, // Kikuyu
+ LanguageCodeEntry {{{'r', 'w'}}, {{'k', 'i', 'n'}}, {{'k', 'i', 'n'}}, {{'k', 'i', 'n'}}}, // Kinyarwanda
+ LanguageCodeEntry {{{'k', 'v'}}, {{'k', 'o', 'm'}}, {{'k', 'o', 'm'}}, {{'k', 'o', 'm'}}}, // Komi
+ LanguageCodeEntry {{{'k', 'g'}}, {{'k', 'o', 'n'}}, {{'k', 'o', 'n'}}, {{'k', 'o', 'n'}}}, // Kongo
+ LanguageCodeEntry {{}, {{'k', 'o', 'k'}}, {{'k', 'o', 'k'}}, {{'k', 'o', 'k'}}}, // Konkani
+ LanguageCodeEntry {{{'k', 'o'}}, {{'k', 'o', 'r'}}, {{'k', 'o', 'r'}}, {{'k', 'o', 'r'}}}, // Korean
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'f', 'o'}}}, // Koro
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'e', 's'}}}, // Koyraboro Senni
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'h', 'q'}}}, // Koyra Chiini
+ LanguageCodeEntry {{}, {{'k', 'p', 'e'}}, {{'k', 'p', 'e'}}, {{'k', 'p', 'e'}}}, // Kpelle
+ LanguageCodeEntry {{{'k', 'j'}}, {{'k', 'u', 'a'}}, {{'k', 'u', 'a'}}, {{'k', 'u', 'a'}}}, // Kuanyama
+ LanguageCodeEntry {{{'k', 'u'}}, {{'k', 'u', 'r'}}, {{'k', 'u', 'r'}}, {{'k', 'u', 'r'}}}, // Kurdish
+ LanguageCodeEntry {{}, {}, {}, {{'n', 'm', 'g'}}}, // Kwasio
+ LanguageCodeEntry {{{'k', 'y'}}, {{'k', 'i', 'r'}}, {{'k', 'i', 'r'}}, {{'k', 'i', 'r'}}}, // Kyrgyz
+ LanguageCodeEntry {{}, {}, {}, {{'l', 'k', 't'}}}, // Lakota
+ LanguageCodeEntry {{}, {}, {}, {{'l', 'a', 'g'}}}, // Langi
+ LanguageCodeEntry {{{'l', 'o'}}, {{'l', 'a', 'o'}}, {{'l', 'a', 'o'}}, {{'l', 'a', 'o'}}}, // Lao
+ LanguageCodeEntry {{{'l', 'a'}}, {{'l', 'a', 't'}}, {{'l', 'a', 't'}}, {{'l', 'a', 't'}}}, // Latin
+ LanguageCodeEntry {{{'l', 'v'}}, {{'l', 'a', 'v'}}, {{'l', 'a', 'v'}}, {{'l', 'a', 'v'}}}, // Latvian
+ LanguageCodeEntry {{}, {{'l', 'e', 'z'}}, {{'l', 'e', 'z'}}, {{'l', 'e', 'z'}}}, // Lezghian
+ LanguageCodeEntry {{{'l', 'i'}}, {{'l', 'i', 'm'}}, {{'l', 'i', 'm'}}, {{'l', 'i', 'm'}}}, // Limburgish
+ LanguageCodeEntry {{{'l', 'n'}}, {{'l', 'i', 'n'}}, {{'l', 'i', 'n'}}, {{'l', 'i', 'n'}}}, // Lingala
+ LanguageCodeEntry {{}, {}, {}, {{'l', 'z', 'h'}}}, // Literary Chinese
+ LanguageCodeEntry {{{'l', 't'}}, {{'l', 'i', 't'}}, {{'l', 'i', 't'}}, {{'l', 'i', 't'}}}, // Lithuanian
+ LanguageCodeEntry {{}, {{'j', 'b', 'o'}}, {{'j', 'b', 'o'}}, {{'j', 'b', 'o'}}}, // Lojban
+ LanguageCodeEntry {{}, {{'d', 's', 'b'}}, {{'d', 's', 'b'}}, {{'d', 's', 'b'}}}, // Lower Sorbian
+ LanguageCodeEntry {{}, {{'n', 'd', 's'}}, {{'n', 'd', 's'}}, {{'n', 'd', 's'}}}, // Low German
+ LanguageCodeEntry {{{'l', 'u'}}, {{'l', 'u', 'b'}}, {{'l', 'u', 'b'}}, {{'l', 'u', 'b'}}}, // Luba Katanga
+ LanguageCodeEntry {{}, {{'s', 'm', 'j'}}, {{'s', 'm', 'j'}}, {{'s', 'm', 'j'}}}, // Lule Sami
+ LanguageCodeEntry {{}, {{'l', 'u', 'o'}}, {{'l', 'u', 'o'}}, {{'l', 'u', 'o'}}}, // Luo
+ LanguageCodeEntry {{{'l', 'b'}}, {{'l', 't', 'z'}}, {{'l', 't', 'z'}}, {{'l', 't', 'z'}}}, // Luxembourgish
+ LanguageCodeEntry {{}, {}, {}, {{'l', 'u', 'y'}}}, // Luyia
+ LanguageCodeEntry {{{'m', 'k'}}, {{'m', 'a', 'c'}}, {{'m', 'k', 'd'}}, {{'m', 'k', 'd'}}}, // Macedonian
+ LanguageCodeEntry {{}, {}, {}, {{'j', 'm', 'c'}}}, // Machame
+ LanguageCodeEntry {{}, {{'m', 'a', 'i'}}, {{'m', 'a', 'i'}}, {{'m', 'a', 'i'}}}, // Maithili
+ LanguageCodeEntry {{}, {}, {}, {{'m', 'g', 'h'}}}, // Makhuwa Meetto
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'd', 'e'}}}, // Makonde
+ LanguageCodeEntry {{{'m', 'g'}}, {{'m', 'l', 'g'}}, {{'m', 'l', 'g'}}, {{'m', 'l', 'g'}}}, // Malagasy
+ LanguageCodeEntry {{{'m', 'l'}}, {{'m', 'a', 'l'}}, {{'m', 'a', 'l'}}, {{'m', 'a', 'l'}}}, // Malayalam
+ LanguageCodeEntry {{{'m', 's'}}, {{'m', 'a', 'y'}}, {{'m', 's', 'a'}}, {{'m', 's', 'a'}}}, // Malay
+ LanguageCodeEntry {{{'m', 't'}}, {{'m', 'l', 't'}}, {{'m', 'l', 't'}}, {{'m', 'l', 't'}}}, // Maltese
+ LanguageCodeEntry {{}, {{'m', 'a', 'n'}}, {{'m', 'a', 'n'}}, {{'m', 'a', 'n'}}}, // Mandingo
+ LanguageCodeEntry {{}, {{'m', 'n', 'i'}}, {{'m', 'n', 'i'}}, {{'m', 'n', 'i'}}}, // Manipuri
+ LanguageCodeEntry {{{'g', 'v'}}, {{'g', 'l', 'v'}}, {{'g', 'l', 'v'}}, {{'g', 'l', 'v'}}}, // Manx
+ LanguageCodeEntry {{{'m', 'i'}}, {{'m', 'a', 'o'}}, {{'m', 'r', 'i'}}, {{'m', 'r', 'i'}}}, // Maori
+ LanguageCodeEntry {{}, {{'a', 'r', 'n'}}, {{'a', 'r', 'n'}}, {{'a', 'r', 'n'}}}, // Mapuche
+ LanguageCodeEntry {{{'m', 'r'}}, {{'m', 'a', 'r'}}, {{'m', 'a', 'r'}}, {{'m', 'a', 'r'}}}, // Marathi
+ LanguageCodeEntry {{{'m', 'h'}}, {{'m', 'a', 'h'}}, {{'m', 'a', 'h'}}, {{'m', 'a', 'h'}}}, // Marshallese
+ LanguageCodeEntry {{}, {{'m', 'a', 's'}}, {{'m', 'a', 's'}}, {{'m', 'a', 's'}}}, // Masai
+ LanguageCodeEntry {{}, {}, {}, {{'m', 'z', 'n'}}}, // Mazanderani
+ LanguageCodeEntry {{}, {{'m', 'e', 'n'}}, {{'m', 'e', 'n'}}, {{'m', 'e', 'n'}}}, // Mende
+ LanguageCodeEntry {{}, {}, {}, {{'m', 'e', 'r'}}}, // Meru
+ LanguageCodeEntry {{}, {}, {}, {{'m', 'g', 'o'}}}, // Meta
+ LanguageCodeEntry {{}, {{'m', 'o', 'h'}}, {{'m', 'o', 'h'}}, {{'m', 'o', 'h'}}}, // Mohawk
+ LanguageCodeEntry {{{'m', 'n'}}, {{'m', 'o', 'n'}}, {{'m', 'o', 'n'}}, {{'m', 'o', 'n'}}}, // Mongolian
+ LanguageCodeEntry {{}, {}, {}, {{'m', 'f', 'e'}}}, // Morisyen
+ LanguageCodeEntry {{}, {}, {}, {{'m', 'u', 'a'}}}, // Mundang
+ LanguageCodeEntry {{}, {{'m', 'u', 's'}}, {{'m', 'u', 's'}}, {{'m', 'u', 's'}}}, // Muscogee
+ LanguageCodeEntry {{}, {}, {}, {{'n', 'a', 'q'}}}, // Nama
+ LanguageCodeEntry {{{'n', 'a'}}, {{'n', 'a', 'u'}}, {{'n', 'a', 'u'}}, {{'n', 'a', 'u'}}}, // Nauru
+ LanguageCodeEntry {{{'n', 'v'}}, {{'n', 'a', 'v'}}, {{'n', 'a', 'v'}}, {{'n', 'a', 'v'}}}, // Navajo
+ LanguageCodeEntry {{{'n', 'g'}}, {{'n', 'd', 'o'}}, {{'n', 'd', 'o'}}, {{'n', 'd', 'o'}}}, // Ndonga
+ LanguageCodeEntry {{{'n', 'e'}}, {{'n', 'e', 'p'}}, {{'n', 'e', 'p'}}, {{'n', 'e', 'p'}}}, // Nepali
+ LanguageCodeEntry {{}, {{'n', 'e', 'w'}}, {{'n', 'e', 'w'}}, {{'n', 'e', 'w'}}}, // Newari
+ LanguageCodeEntry {{}, {}, {}, {{'n', 'n', 'h'}}}, // Ngiemboon
+ LanguageCodeEntry {{}, {}, {}, {{'j', 'g', 'o'}}}, // Ngomba
+ LanguageCodeEntry {{}, {}, {}, {{'p', 'c', 'm'}}}, // Nigerian Pidgin
+ LanguageCodeEntry {{}, {{'n', 'q', 'o'}}, {{'n', 'q', 'o'}}, {{'n', 'q', 'o'}}}, // Nko
+ LanguageCodeEntry {{}, {}, {}, {{'l', 'r', 'c'}}}, // Northern Luri
+ LanguageCodeEntry {{{'s', 'e'}}, {{'s', 'm', 'e'}}, {{'s', 'm', 'e'}}, {{'s', 'm', 'e'}}}, // Northern Sami
+ LanguageCodeEntry {{}, {{'n', 's', 'o'}}, {{'n', 's', 'o'}}, {{'n', 's', 'o'}}}, // Northern Sotho
+ LanguageCodeEntry {{{'n', 'd'}}, {{'n', 'd', 'e'}}, {{'n', 'd', 'e'}}, {{'n', 'd', 'e'}}}, // North Ndebele
+ LanguageCodeEntry {{{'n', 'b'}}, {{'n', 'o', 'b'}}, {{'n', 'o', 'b'}}, {{'n', 'o', 'b'}}}, // Norwegian Bokmal
+ LanguageCodeEntry {{{'n', 'n'}}, {{'n', 'n', 'o'}}, {{'n', 'n', 'o'}}, {{'n', 'n', 'o'}}}, // Norwegian Nynorsk
+ LanguageCodeEntry {{}, {}, {}, {{'n', 'u', 's'}}}, // Nuer
+ LanguageCodeEntry {{{'n', 'y'}}, {{'n', 'y', 'a'}}, {{'n', 'y', 'a'}}, {{'n', 'y', 'a'}}}, // Nyanja
+ LanguageCodeEntry {{}, {{'n', 'y', 'n'}}, {{'n', 'y', 'n'}}, {{'n', 'y', 'n'}}}, // Nyankole
+ LanguageCodeEntry {{{'o', 'c'}}, {{'o', 'c', 'i'}}, {{'o', 'c', 'i'}}, {{'o', 'c', 'i'}}}, // Occitan
+ LanguageCodeEntry {{{'o', 'r'}}, {{'o', 'r', 'i'}}, {{'o', 'r', 'i'}}, {{'o', 'r', 'i'}}}, // Odia
+ LanguageCodeEntry {{{'o', 'j'}}, {{'o', 'j', 'i'}}, {{'o', 'j', 'i'}}, {{'o', 'j', 'i'}}}, // Ojibwa
+ LanguageCodeEntry {{}, {{'s', 'g', 'a'}}, {{'s', 'g', 'a'}}, {{'s', 'g', 'a'}}}, // Old Irish
+ LanguageCodeEntry {{}, {{'n', 'o', 'n'}}, {{'n', 'o', 'n'}}, {{'n', 'o', 'n'}}}, // Old Norse
+ LanguageCodeEntry {{}, {{'p', 'e', 'o'}}, {{'p', 'e', 'o'}}, {{'p', 'e', 'o'}}}, // Old Persian
+ LanguageCodeEntry {{{'o', 'm'}}, {{'o', 'r', 'm'}}, {{'o', 'r', 'm'}}, {{'o', 'r', 'm'}}}, // Oromo
+ LanguageCodeEntry {{}, {{'o', 's', 'a'}}, {{'o', 's', 'a'}}, {{'o', 's', 'a'}}}, // Osage
+ LanguageCodeEntry {{{'o', 's'}}, {{'o', 's', 's'}}, {{'o', 's', 's'}}, {{'o', 's', 's'}}}, // Ossetic
+ LanguageCodeEntry {{}, {{'p', 'a', 'l'}}, {{'p', 'a', 'l'}}, {{'p', 'a', 'l'}}}, // Pahlavi
+ LanguageCodeEntry {{}, {{'p', 'a', 'u'}}, {{'p', 'a', 'u'}}, {{'p', 'a', 'u'}}}, // Palauan
+ LanguageCodeEntry {{{'p', 'i'}}, {{'p', 'l', 'i'}}, {{'p', 'l', 'i'}}, {{'p', 'l', 'i'}}}, // Pali
+ LanguageCodeEntry {{}, {{'p', 'a', 'p'}}, {{'p', 'a', 'p'}}, {{'p', 'a', 'p'}}}, // Papiamento
+ LanguageCodeEntry {{{'p', 's'}}, {{'p', 'u', 's'}}, {{'p', 'u', 's'}}, {{'p', 'u', 's'}}}, // Pashto
+ LanguageCodeEntry {{{'f', 'a'}}, {{'p', 'e', 'r'}}, {{'f', 'a', 's'}}, {{'f', 'a', 's'}}}, // Persian
+ LanguageCodeEntry {{}, {{'p', 'h', 'n'}}, {{'p', 'h', 'n'}}, {{'p', 'h', 'n'}}}, // Phoenician
+ LanguageCodeEntry {{{'p', 'l'}}, {{'p', 'o', 'l'}}, {{'p', 'o', 'l'}}, {{'p', 'o', 'l'}}}, // Polish
+ LanguageCodeEntry {{{'p', 't'}}, {{'p', 'o', 'r'}}, {{'p', 'o', 'r'}}, {{'p', 'o', 'r'}}}, // Portuguese
+ LanguageCodeEntry {{}, {}, {}, {{'p', 'r', 'g'}}}, // Prussian
+ LanguageCodeEntry {{{'p', 'a'}}, {{'p', 'a', 'n'}}, {{'p', 'a', 'n'}}, {{'p', 'a', 'n'}}}, // Punjabi
+ LanguageCodeEntry {{{'q', 'u'}}, {{'q', 'u', 'e'}}, {{'q', 'u', 'e'}}, {{'q', 'u', 'e'}}}, // Quechua
+ LanguageCodeEntry {{{'r', 'o'}}, {{'r', 'u', 'm'}}, {{'r', 'o', 'n'}}, {{'r', 'o', 'n'}}}, // Romanian
+ LanguageCodeEntry {{{'r', 'm'}}, {{'r', 'o', 'h'}}, {{'r', 'o', 'h'}}, {{'r', 'o', 'h'}}}, // Romansh
+ LanguageCodeEntry {{}, {}, {}, {{'r', 'o', 'f'}}}, // Rombo
+ LanguageCodeEntry {{{'r', 'n'}}, {{'r', 'u', 'n'}}, {{'r', 'u', 'n'}}, {{'r', 'u', 'n'}}}, // Rundi
+ LanguageCodeEntry {{{'r', 'u'}}, {{'r', 'u', 's'}}, {{'r', 'u', 's'}}, {{'r', 'u', 's'}}}, // Russian
+ LanguageCodeEntry {{}, {}, {}, {{'r', 'w', 'k'}}}, // Rwa
+ LanguageCodeEntry {{}, {}, {}, {{'s', 's', 'y'}}}, // Saho
+ LanguageCodeEntry {{}, {{'s', 'a', 'h'}}, {{'s', 'a', 'h'}}, {{'s', 'a', 'h'}}}, // Sakha
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'a', 'q'}}}, // Samburu
+ LanguageCodeEntry {{{'s', 'm'}}, {{'s', 'm', 'o'}}, {{'s', 'm', 'o'}}, {{'s', 'm', 'o'}}}, // Samoan
+ LanguageCodeEntry {{{'s', 'g'}}, {{'s', 'a', 'g'}}, {{'s', 'a', 'g'}}, {{'s', 'a', 'g'}}}, // Sango
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'b', 'p'}}}, // Sangu
+ LanguageCodeEntry {{{'s', 'a'}}, {{'s', 'a', 'n'}}, {{'s', 'a', 'n'}}, {{'s', 'a', 'n'}}}, // Sanskrit
+ LanguageCodeEntry {{}, {{'s', 'a', 't'}}, {{'s', 'a', 't'}}, {{'s', 'a', 't'}}}, // Santali
+ LanguageCodeEntry {{{'s', 'c'}}, {{'s', 'r', 'd'}}, {{'s', 'r', 'd'}}, {{'s', 'r', 'd'}}}, // Sardinian
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'a', 'z'}}}, // Saurashtra
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'e', 'h'}}}, // Sena
+ LanguageCodeEntry {{{'s', 'r'}}, {{'s', 'r', 'p'}}, {{'s', 'r', 'p'}}, {{'s', 'r', 'p'}}}, // Serbian
+ LanguageCodeEntry {{}, {}, {}, {{'k', 's', 'b'}}}, // Shambala
+ LanguageCodeEntry {{{'s', 'n'}}, {{'s', 'n', 'a'}}, {{'s', 'n', 'a'}}, {{'s', 'n', 'a'}}}, // Shona
+ LanguageCodeEntry {{{'i', 'i'}}, {{'i', 'i', 'i'}}, {{'i', 'i', 'i'}}, {{'i', 'i', 'i'}}}, // Sichuan Yi
+ LanguageCodeEntry {{}, {{'s', 'c', 'n'}}, {{'s', 'c', 'n'}}, {{'s', 'c', 'n'}}}, // Sicilian
+ LanguageCodeEntry {{}, {{'s', 'i', 'd'}}, {{'s', 'i', 'd'}}, {{'s', 'i', 'd'}}}, // Sidamo
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'z', 'l'}}}, // Silesian
+ LanguageCodeEntry {{{'s', 'd'}}, {{'s', 'n', 'd'}}, {{'s', 'n', 'd'}}, {{'s', 'n', 'd'}}}, // Sindhi
+ LanguageCodeEntry {{{'s', 'i'}}, {{'s', 'i', 'n'}}, {{'s', 'i', 'n'}}, {{'s', 'i', 'n'}}}, // Sinhala
+ LanguageCodeEntry {{}, {{'s', 'm', 's'}}, {{'s', 'm', 's'}}, {{'s', 'm', 's'}}}, // Skolt Sami
+ LanguageCodeEntry {{{'s', 'k'}}, {{'s', 'l', 'o'}}, {{'s', 'l', 'k'}}, {{'s', 'l', 'k'}}}, // Slovak
+ LanguageCodeEntry {{{'s', 'l'}}, {{'s', 'l', 'v'}}, {{'s', 'l', 'v'}}, {{'s', 'l', 'v'}}}, // Slovenian
+ LanguageCodeEntry {{}, {}, {}, {{'x', 'o', 'g'}}}, // Soga
+ LanguageCodeEntry {{{'s', 'o'}}, {{'s', 'o', 'm'}}, {{'s', 'o', 'm'}}, {{'s', 'o', 'm'}}}, // Somali
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'd', 'h'}}}, // Southern Kurdish
+ LanguageCodeEntry {{}, {{'s', 'm', 'a'}}, {{'s', 'm', 'a'}}, {{'s', 'm', 'a'}}}, // Southern Sami
+ LanguageCodeEntry {{{'s', 't'}}, {{'s', 'o', 't'}}, {{'s', 'o', 't'}}, {{'s', 'o', 't'}}}, // Southern Sotho
+ LanguageCodeEntry {{{'n', 'r'}}, {{'n', 'b', 'l'}}, {{'n', 'b', 'l'}}, {{'n', 'b', 'l'}}}, // South Ndebele
+ LanguageCodeEntry {{{'e', 's'}}, {{'s', 'p', 'a'}}, {{'s', 'p', 'a'}}, {{'s', 'p', 'a'}}}, // Spanish
+ LanguageCodeEntry {{}, {{'z', 'g', 'h'}}, {{'z', 'g', 'h'}}, {{'z', 'g', 'h'}}}, // Standard Moroccan Tamazight
+ LanguageCodeEntry {{{'s', 'u'}}, {{'s', 'u', 'n'}}, {{'s', 'u', 'n'}}, {{'s', 'u', 'n'}}}, // Sundanese
+ LanguageCodeEntry {{{'s', 'w'}}, {{'s', 'w', 'a'}}, {{'s', 'w', 'a'}}, {{'s', 'w', 'a'}}}, // Swahili
+ LanguageCodeEntry {{{'s', 's'}}, {{'s', 's', 'w'}}, {{'s', 's', 'w'}}, {{'s', 's', 'w'}}}, // Swati
+ LanguageCodeEntry {{{'s', 'v'}}, {{'s', 'w', 'e'}}, {{'s', 'w', 'e'}}, {{'s', 'w', 'e'}}}, // Swedish
+ LanguageCodeEntry {{}, {{'g', 's', 'w'}}, {{'g', 's', 'w'}}, {{'g', 's', 'w'}}}, // Swiss German
+ LanguageCodeEntry {{}, {{'s', 'y', 'r'}}, {{'s', 'y', 'r'}}, {{'s', 'y', 'r'}}}, // Syriac
+ LanguageCodeEntry {{}, {}, {}, {{'s', 'h', 'i'}}}, // Tachelhit
+ LanguageCodeEntry {{{'t', 'y'}}, {{'t', 'a', 'h'}}, {{'t', 'a', 'h'}}, {{'t', 'a', 'h'}}}, // Tahitian
+ LanguageCodeEntry {{}, {}, {}, {{'b', 'l', 't'}}}, // Tai Dam
+ LanguageCodeEntry {{}, {}, {}, {{'d', 'a', 'v'}}}, // Taita
+ LanguageCodeEntry {{{'t', 'g'}}, {{'t', 'g', 'k'}}, {{'t', 'g', 'k'}}, {{'t', 'g', 'k'}}}, // Tajik
+ LanguageCodeEntry {{{'t', 'a'}}, {{'t', 'a', 'm'}}, {{'t', 'a', 'm'}}, {{'t', 'a', 'm'}}}, // Tamil
+ LanguageCodeEntry {{}, {}, {}, {{'t', 'r', 'v'}}}, // Taroko
+ LanguageCodeEntry {{}, {}, {}, {{'t', 'w', 'q'}}}, // Tasawaq
+ LanguageCodeEntry {{{'t', 't'}}, {{'t', 'a', 't'}}, {{'t', 'a', 't'}}, {{'t', 'a', 't'}}}, // Tatar
+ LanguageCodeEntry {{{'t', 'e'}}, {{'t', 'e', 'l'}}, {{'t', 'e', 'l'}}, {{'t', 'e', 'l'}}}, // Telugu
+ LanguageCodeEntry {{}, {}, {}, {{'t', 'e', 'o'}}}, // Teso
+ LanguageCodeEntry {{{'t', 'h'}}, {{'t', 'h', 'a'}}, {{'t', 'h', 'a'}}, {{'t', 'h', 'a'}}}, // Thai
+ LanguageCodeEntry {{{'b', 'o'}}, {{'t', 'i', 'b'}}, {{'b', 'o', 'd'}}, {{'b', 'o', 'd'}}}, // Tibetan
+ LanguageCodeEntry {{}, {{'t', 'i', 'g'}}, {{'t', 'i', 'g'}}, {{'t', 'i', 'g'}}}, // Tigre
+ LanguageCodeEntry {{{'t', 'i'}}, {{'t', 'i', 'r'}}, {{'t', 'i', 'r'}}, {{'t', 'i', 'r'}}}, // Tigrinya
+ LanguageCodeEntry {{}, {{'t', 'k', 'l'}}, {{'t', 'k', 'l'}}, {{'t', 'k', 'l'}}}, // Tokelau
+ LanguageCodeEntry {{}, {{'t', 'p', 'i'}}, {{'t', 'p', 'i'}}, {{'t', 'p', 'i'}}}, // Tok Pisin
+ LanguageCodeEntry {{{'t', 'o'}}, {{'t', 'o', 'n'}}, {{'t', 'o', 'n'}}, {{'t', 'o', 'n'}}}, // Tongan
+ LanguageCodeEntry {{{'t', 's'}}, {{'t', 's', 'o'}}, {{'t', 's', 'o'}}, {{'t', 's', 'o'}}}, // Tsonga
+ LanguageCodeEntry {{{'t', 'n'}}, {{'t', 's', 'n'}}, {{'t', 's', 'n'}}, {{'t', 's', 'n'}}}, // Tswana
+ LanguageCodeEntry {{{'t', 'r'}}, {{'t', 'u', 'r'}}, {{'t', 'u', 'r'}}, {{'t', 'u', 'r'}}}, // Turkish
+ LanguageCodeEntry {{{'t', 'k'}}, {{'t', 'u', 'k'}}, {{'t', 'u', 'k'}}, {{'t', 'u', 'k'}}}, // Turkmen
+ LanguageCodeEntry {{}, {{'t', 'v', 'l'}}, {{'t', 'v', 'l'}}, {{'t', 'v', 'l'}}}, // Tuvalu
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'c', 'g'}}}, // Tyap
+ LanguageCodeEntry {{}, {{'u', 'g', 'a'}}, {{'u', 'g', 'a'}}, {{'u', 'g', 'a'}}}, // Ugaritic
+ LanguageCodeEntry {{{'u', 'k'}}, {{'u', 'k', 'r'}}, {{'u', 'k', 'r'}}, {{'u', 'k', 'r'}}}, // Ukrainian
+ LanguageCodeEntry {{}, {{'h', 's', 'b'}}, {{'h', 's', 'b'}}, {{'h', 's', 'b'}}}, // Upper Sorbian
+ LanguageCodeEntry {{{'u', 'r'}}, {{'u', 'r', 'd'}}, {{'u', 'r', 'd'}}, {{'u', 'r', 'd'}}}, // Urdu
+ LanguageCodeEntry {{{'u', 'g'}}, {{'u', 'i', 'g'}}, {{'u', 'i', 'g'}}, {{'u', 'i', 'g'}}}, // Uyghur
+ LanguageCodeEntry {{{'u', 'z'}}, {{'u', 'z', 'b'}}, {{'u', 'z', 'b'}}, {{'u', 'z', 'b'}}}, // Uzbek
+ LanguageCodeEntry {{}, {{'v', 'a', 'i'}}, {{'v', 'a', 'i'}}, {{'v', 'a', 'i'}}}, // Vai
+ LanguageCodeEntry {{{'v', 'e'}}, {{'v', 'e', 'n'}}, {{'v', 'e', 'n'}}, {{'v', 'e', 'n'}}}, // Venda
+ LanguageCodeEntry {{{'v', 'i'}}, {{'v', 'i', 'e'}}, {{'v', 'i', 'e'}}, {{'v', 'i', 'e'}}}, // Vietnamese
+ LanguageCodeEntry {{{'v', 'o'}}, {{'v', 'o', 'l'}}, {{'v', 'o', 'l'}}, {{'v', 'o', 'l'}}}, // Volapuk
+ LanguageCodeEntry {{}, {}, {}, {{'v', 'u', 'n'}}}, // Vunjo
+ LanguageCodeEntry {{{'w', 'a'}}, {{'w', 'l', 'n'}}, {{'w', 'l', 'n'}}, {{'w', 'l', 'n'}}}, // Walloon
+ LanguageCodeEntry {{}, {}, {}, {{'w', 'a', 'e'}}}, // Walser
+ LanguageCodeEntry {{}, {}, {}, {{'w', 'b', 'p'}}}, // Warlpiri
+ LanguageCodeEntry {{{'c', 'y'}}, {{'w', 'e', 'l'}}, {{'c', 'y', 'm'}}, {{'c', 'y', 'm'}}}, // Welsh
+ LanguageCodeEntry {{}, {}, {}, {{'b', 'g', 'n'}}}, // Western Balochi
+ LanguageCodeEntry {{{'f', 'y'}}, {{'f', 'r', 'y'}}, {{'f', 'r', 'y'}}, {{'f', 'r', 'y'}}}, // Western Frisian
+ LanguageCodeEntry {{}, {{'w', 'a', 'l'}}, {{'w', 'a', 'l'}}, {{'w', 'a', 'l'}}}, // Wolaytta
+ LanguageCodeEntry {{{'w', 'o'}}, {{'w', 'o', 'l'}}, {{'w', 'o', 'l'}}, {{'w', 'o', 'l'}}}, // Wolof
+ LanguageCodeEntry {{{'x', 'h'}}, {{'x', 'h', 'o'}}, {{'x', 'h', 'o'}}, {{'x', 'h', 'o'}}}, // Xhosa
+ LanguageCodeEntry {{}, {}, {}, {{'y', 'a', 'v'}}}, // Yangben
+ LanguageCodeEntry {{{'y', 'i'}}, {{'y', 'i', 'd'}}, {{'y', 'i', 'd'}}, {{'y', 'i', 'd'}}}, // Yiddish
+ LanguageCodeEntry {{{'y', 'o'}}, {{'y', 'o', 'r'}}, {{'y', 'o', 'r'}}, {{'y', 'o', 'r'}}}, // Yoruba
+ LanguageCodeEntry {{}, {}, {}, {{'d', 'j', 'e'}}}, // Zarma
+ LanguageCodeEntry {{{'z', 'a'}}, {{'z', 'h', 'a'}}, {{'z', 'h', 'a'}}, {{'z', 'h', 'a'}}}, // Zhuang
+ LanguageCodeEntry {{{'z', 'u'}}, {{'z', 'u', 'l'}}, {{'z', 'u', 'l'}}, {{'z', 'u', 'l'}}}, // Zulu
+ LanguageCodeEntry {{}, {}, {}, {{'k', 'g', 'p'}}}, // Kaingang
+ LanguageCodeEntry {{}, {}, {}, {{'y', 'r', 'l'}}}, // Nheengatu
+};
static const unsigned char script_code_list[] =
"Zzzz" // AnyScript
diff --git a/src/corelib/text/qlocale_mac.mm b/src/corelib/text/qlocale_mac.mm
index ef9d1d24a3..7d75db31d0 100644
--- a/src/corelib/text/qlocale_mac.mm
+++ b/src/corelib/text/qlocale_mac.mm
@@ -548,12 +548,18 @@ static QVariant getLocaleValue(CFStringRef key)
return QVariant();
}
+static QLocale::Language codeToLanguage(QStringView s)
+{
+ return QLocalePrivate::codeToLanguage(s);
+}
+
QVariant QSystemLocale::query(QueryType type, QVariant in) const
{
QMacAutoReleasePool pool;
+
switch(type) {
case LanguageId:
- return getLocaleValue<QLocalePrivate::codeToLanguage>(kCFLocaleLanguageCode);
+ return getLocaleValue<codeToLanguage>(kCFLocaleLanguageCode);
case TerritoryId:
return getLocaleValue<QLocalePrivate::codeToTerritory>(kCFLocaleCountryCode);
case ScriptId:
diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h
index 60bc78db04..5326831bb6 100644
--- a/src/corelib/text/qlocale_p.h
+++ b/src/corelib/text/qlocale_p.h
@@ -418,18 +418,25 @@ public:
[[nodiscard]] QByteArray bcp47Name(char separator = '-') const;
- [[nodiscard]] inline QLatin1String languageCode() const
- { return languageToCode(QLocale::Language(m_data->m_language_id)); }
+ [[nodiscard]] inline QLatin1String
+ languageCode(QLocale::LanguageCodeTypes codeTypes = QLocale::AnyLanguageCode) const
+ {
+ return languageToCode(QLocale::Language(m_data->m_language_id), codeTypes);
+ }
[[nodiscard]] inline QLatin1String scriptCode() const
{ return scriptToCode(QLocale::Script(m_data->m_script_id)); }
[[nodiscard]] inline QLatin1String territoryCode() const
{ return territoryToCode(QLocale::Territory(m_data->m_territory_id)); }
[[nodiscard]] static const QLocalePrivate *get(const QLocale &l) { return l.d; }
- [[nodiscard]] static QLatin1String languageToCode(QLocale::Language language);
+ [[nodiscard]] static QLatin1String
+ languageToCode(QLocale::Language language,
+ QLocale::LanguageCodeTypes codeTypes = QLocale::AnyLanguageCode);
[[nodiscard]] static QLatin1String scriptToCode(QLocale::Script script);
[[nodiscard]] static QLatin1String territoryToCode(QLocale::Territory territory);
- [[nodiscard]] static QLocale::Language codeToLanguage(QStringView code) noexcept;
+ [[nodiscard]] static QLocale::Language
+ codeToLanguage(QStringView code,
+ QLocale::LanguageCodeTypes codeTypes = QLocale::AnyLanguageCode) noexcept;
[[nodiscard]] static QLocale::Script codeToScript(QStringView code) noexcept;
[[nodiscard]] static QLocale::Territory codeToTerritory(QStringView code) noexcept;
diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
index 2a752e486f..52224701f6 100644
--- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
@@ -3501,6 +3501,23 @@ void tst_QLocale::lcsToCode()
QCOMPARE(QLocale::languageToCode(QLocale::AnyLanguage), QString());
QCOMPARE(QLocale::languageToCode(QLocale::C), QString("C"));
QCOMPARE(QLocale::languageToCode(QLocale::English), QString("en"));
+ QCOMPARE(QLocale::languageToCode(QLocale::Albanian), u"sq"_qs);
+ QCOMPARE(QLocale::languageToCode(QLocale::Albanian, QLocale::ISO639Part1), u"sq"_qs);
+ QCOMPARE(QLocale::languageToCode(QLocale::Albanian, QLocale::ISO639Part2B), u"alb"_qs);
+ QCOMPARE(QLocale::languageToCode(QLocale::Albanian, QLocale::ISO639Part2T), u"sqi"_qs);
+ QCOMPARE(QLocale::languageToCode(QLocale::Albanian, QLocale::ISO639Part3), u"sqi"_qs);
+
+ QCOMPARE(QLocale::languageToCode(QLocale::Taita), u"dav"_qs);
+ QCOMPARE(QLocale::languageToCode(QLocale::Taita,
+ QLocale::ISO639Part1 | QLocale::ISO639Part2B
+ | QLocale::ISO639Part2T),
+ QString());
+ QCOMPARE(QLocale::languageToCode(QLocale::Taita, QLocale::ISO639Part3), u"dav"_qs);
+ QCOMPARE(QLocale::languageToCode(QLocale::English, QLocale::LanguageCodeTypes {}), QString());
+
+ // Legacy codes can only be used to convert them to Language values, not other way around.
+ QCOMPARE(QLocale::languageToCode(QLocale::NorwegianBokmal, QLocale::LegacyLanguageCode),
+ QString());
QCOMPARE(QLocale::territoryToCode(QLocale::AnyTerritory), QString());
QCOMPARE(QLocale::territoryToCode(QLocale::UnitedStates), QString("US"));
@@ -3518,9 +3535,28 @@ void tst_QLocale::codeToLcs()
QCOMPARE(QLocale::codeToLanguage(QString("e")), QLocale::AnyLanguage);
QCOMPARE(QLocale::codeToLanguage(QString("en")), QLocale::English);
QCOMPARE(QLocale::codeToLanguage(QString("EN")), QLocale::English);
- QCOMPARE(QLocale::codeToLanguage(QString("eng")), QLocale::AnyLanguage);
+ QCOMPARE(QLocale::codeToLanguage(QString("eng")), QLocale::English);
QCOMPARE(QLocale::codeToLanguage(QString("ha")), QLocale::Hausa);
+ QCOMPARE(QLocale::codeToLanguage(QString("ha"), QLocale::ISO639Alpha3), QLocale::AnyLanguage);
QCOMPARE(QLocale::codeToLanguage(QString("haw")), QLocale::Hawaiian);
+ QCOMPARE(QLocale::codeToLanguage(QString("haw"), QLocale::ISO639Alpha2), QLocale::AnyLanguage);
+
+ QCOMPARE(QLocale::codeToLanguage(u"sq"), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"alb"), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"sqi"), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"sq", QLocale::ISO639Part1), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"sq", QLocale::ISO639Part3), QLocale::AnyLanguage);
+ QCOMPARE(QLocale::codeToLanguage(u"alb", QLocale::ISO639Part2B), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"alb", QLocale::ISO639Part2T | QLocale::ISO639Part3),
+ QLocale::AnyLanguage);
+ QCOMPARE(QLocale::codeToLanguage(u"sqi", QLocale::ISO639Part2T), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"sqi", QLocale::ISO639Part3), QLocale::Albanian);
+ QCOMPARE(QLocale::codeToLanguage(u"sqi", QLocale::ISO639Part1 | QLocale::ISO639Part2B),
+ QLocale::AnyLanguage);
+
+ // Legacy code
+ QCOMPARE(QLocale::codeToLanguage(u"no"), QLocale::NorwegianBokmal);
+ QCOMPARE(QLocale::codeToLanguage(u"no", QLocale::ISO639Part1), QLocale::AnyLanguage);
QCOMPARE(QLocale::codeToTerritory(QString()), QLocale::AnyTerritory);
QCOMPARE(QLocale::codeToTerritory(QString("ZZ")), QLocale::AnyTerritory);
diff --git a/util/locale_database/iso639_3.py b/util/locale_database/iso639_3.py
new file mode 100644
index 0000000000..b150855ba9
--- /dev/null
+++ b/util/locale_database/iso639_3.py
@@ -0,0 +1,105 @@
+#############################################################################
+##
+## Copyright (C) 2021 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the locale database tools of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+from dataclasses import dataclass
+from typing import Dict, Optional
+
+
+@dataclass
+class LanguageCodeEntry:
+ part3Code: str
+ part2BCode: Optional[str]
+ part2TCode: Optional[str]
+ part1Code: Optional[str]
+
+ def id(self) -> str:
+ if self.part1Code:
+ return self.part1Code
+ if self.part2BCode:
+ return self.part2BCode
+ return self.part3Code
+
+ def __repr__(self) -> str:
+ parts = [f'{self.__class__.__name__}({self.id()!r}, part3Code={self.part3Code!r}']
+ if self.part2BCode is not None and self.part2BCode != self.part3Code:
+ parts.append(f', part2BCode={self.part2BCode!r}')
+ if self.part2TCode != self.part2BCode:
+ parts.append(f', part2TCode={self.part2TCode!r}')
+ if self.part1Code is not None:
+ parts.append(f', part1Code={self.part1Code!r}')
+ parts.append(')')
+ return ''.join(parts)
+
+
+class LanguageCodeData:
+ """
+ Representation of ISO639-2 language code data.
+ """
+ def __init__(self, fileName: str):
+ """
+ Construct the object populating the data from the given file.
+ """
+ self.__codeMap: Dict[str, LanguageCodeEntry] = {}
+
+ with open(fileName, 'r', encoding='utf-8') as stream:
+ stream.readline() # skip the header
+ for line in stream.readlines():
+ part3Code, part2BCode, part2TCode, part1Code, _ = line.split('\t', 4)
+
+ # sanity checks
+ assert all(p.isascii() for p in (part3Code, part2BCode, part2TCode, part1Code)), \
+ f'Non-ascii characters in code names: {part3Code!r} {part2BCode!r} '\
+ f'{part2TCode!r} {part1Code!r}'
+
+ assert len(part3Code) == 3, f'Invalid Part 3 code length for {part3Code!r}'
+ assert not part1Code or len(part1Code) == 2, \
+ f'Invalid Part 1 code length for {part3Code!r}: {part1Code!r}'
+ assert not part2BCode or len(part2BCode) == 3, \
+ f'Invalid Part 2B code length for {part3Code!r}: {part2BCode!r}'
+ assert not part2TCode or len(part2TCode) == 3, \
+ f'Invalid Part 2T code length for {part3Code!r}: {part2TCode!r}'
+
+ assert (part2BCode == '') == (part2TCode == ''), \
+ f'Only one Part 2 code is specified for {part3Code!r}: ' \
+ f'{part2BCode!r} vs {part2TCode!r}'
+ assert not part2TCode or part2TCode == part3Code, \
+ f'Part 3 code {part3Code!r} does not match Part 2T code {part2TCode!r}'
+
+ entry = LanguageCodeEntry(part3Code, part2BCode or None,
+ part2TCode or None, part1Code or None)
+
+ self.__codeMap[entry.id()] = entry
+
+ def query(self, code: str) -> Optional[LanguageCodeEntry]:
+ """
+ Lookup the entry with the given code and return it.
+
+ The entries can be looked up by using either the Alpha2 code or the bibliographical
+ Alpha3 code.
+ """
+ return self.__codeMap.get(code)
diff --git a/util/locale_database/qlocalexml2cpp.py b/util/locale_database/qlocalexml2cpp.py
index 7ac7945cf8..a7592f7a0c 100755
--- a/util/locale_database/qlocalexml2cpp.py
+++ b/util/locale_database/qlocalexml2cpp.py
@@ -30,15 +30,22 @@
See ``cldr2qlocalexml.py`` for how to generate the QLocaleXML data itself.
Pass the output file from that as first parameter to this script; pass
-the root of the qtbase check-out as second parameter.
+the ISO 639-3 data file as second parameter; pass the root of the qtbase
+check-out as third parameter.
+
+The ISO 639-3 data file can be downloaded from the SIL website:
+
+ https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3.tab
"""
import datetime
import argparse
from pathlib import Path
+from typing import Optional
from qlocalexml import QLocaleXmlReader
from localetools import unicode2hex, wrap_list, Error, Transcriber, SourceFileEditor
+from iso639_3 import LanguageCodeData
class LocaleKeySorter:
"""Sort-ordering representation of a locale key.
@@ -389,8 +396,42 @@ class LocaleDataWriter (LocaleSourceEditor):
# TODO: unify these next three into the previous three; kept
# separate for now to verify we're not changing data.
- def languageCodes(self, languages):
- self.__writeCodeList(self.writer.write, languages, 'language', 3)
+ def languageCodes(self, languages, code_data: LanguageCodeData):
+ out = self.writer.write
+
+ out(f'constexpr std::array<LanguageCodeEntry, {len(languages)}> languageCodeList {{\n')
+
+ def q(val: Optional[str], size: int) -> str:
+ """Quote the value and adjust the result for tabular view."""
+ chars = []
+ if val is not None:
+ for c in val:
+ chars.append(f"'{c}'")
+ s = ', '.join(chars)
+ s = f'{{{s}}}'
+ else:
+ s = ''
+ if size == 0:
+ return f'{{{s}}}'
+ else:
+ return f'{{{s}}},'.ljust(size * 5 + 4)
+
+ for key, value in languages.items():
+ code = value[1]
+ if key < 2:
+ result = code_data.query('und')
+ else:
+ result = code_data.query(code)
+ assert code == result.id()
+ assert result is not None
+
+ codeString = q(result.part1Code, 2)
+ codeString += q(result.part2BCode, 3)
+ codeString += q(result.part2TCode, 3)
+ codeString += q(result.part3Code, 0)
+ out(f' LanguageCodeEntry {{{codeString}}}, // {value[0]}\n')
+
+ out('};\n\n')
def scriptCodes(self, scripts):
self.__writeCodeList(self.writer.write, scripts, 'script', 4)
@@ -519,6 +560,8 @@ def main(out, err):
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('input_file', help='input XML file name',
metavar='input-file.xml')
+ parser.add_argument('iso_path', help='path to the ISO 639-3 data file',
+ metavar='iso-639-3.tab')
parser.add_argument('qtbase_path', help='path to the root of the qtbase source tree')
parser.add_argument('--calendars', help='select calendars to emit data for',
nargs='+', metavar='CALENDAR',
@@ -538,6 +581,8 @@ def main(out, err):
locale_map = dict(reader.loadLocaleMap(calendars, err.write))
locale_keys = sorted(locale_map.keys(), key=LocaleKeySorter(reader.defaultMap()))
+ code_data = LanguageCodeData(args.iso_path)
+
try:
with LocaleDataWriter(qtsrcdir.joinpath('src/corelib/text/qlocale_data_p.h'),
qtsrcdir, reader.cldrVersion) as writer:
@@ -549,7 +594,7 @@ def main(out, err):
writer.scriptNames(reader.scripts)
writer.territoryNames(reader.territories)
# TODO: merge the next three into the previous three
- writer.languageCodes(reader.languages)
+ writer.languageCodes(reader.languages, code_data)
writer.scriptCodes(reader.scripts)
writer.territoryCodes(reader.territories)
except Exception as e: