10#include <config_folders.h>
11#include <config_liblangtag.h>
16#include <rtl/ustrbuf.hxx>
17#include <rtl/bootstrap.hxx>
19#include <osl/file.hxx>
20#include <rtl/locale.h>
26#include <unordered_set>
30#if LIBLANGTAG_INLINE_FIX
33#include <liblangtag/langtag.h>
36#include <osl/detail/android-bootstrap.h>
40#include <osl/detail/emscripten-bootstrap.h>
51 myLtError() :
p(nullptr) {}
52 ~myLtError() {
if (p) lt_error_unref( p); }
58std::recursive_mutex& theMutex()
60 static std::recursive_mutex SINGLETON;
72 for (
auto const& elemDefined : aDefined)
78 for (
auto const& fallback : aFallbacks)
80 tmpSet.insert(fallback);
90struct compareIgnoreAsciiCaseLess
92 bool operator()( std::u16string_view r1, std::u16string_view r2 )
const
97typedef ::std::map< OUString, LanguageTag::ImplPtr, compareIgnoreAsciiCaseLess > MapBcp47;
98typedef ::std::map< LanguageType, LanguageTag::ImplPtr > MapLangID;
99MapBcp47& theMapBcp47()
101 static MapBcp47 SINGLETON;
104MapLangID& theMapLangID()
106 static MapLangID SINGLETON;
120 std::unique_lock aGuard( theMutex());
121 if (!nOnTheFlyLanguage)
134 SAL_WARN(
"i18nlangtag",
"getNextOnTheFlyLanguage: none left! ("
142#if OSL_DEBUG_LEVEL > 0
143 static size_t nOnTheFlies = 0;
145 SAL_INFO(
"i18nlangtag",
"getNextOnTheFlyLanguage: number " << nOnTheFlies);
147 return nOnTheFlyLanguage;
167class LiblangtagDataRef
171 ~LiblangtagDataRef();
181 void setupDataPath();
183 static void teardown();
186LiblangtagDataRef& theDataRef()
188 static LiblangtagDataRef SINGLETON;
193LiblangtagDataRef::LiblangtagDataRef()
199LiblangtagDataRef::~LiblangtagDataRef()
205void LiblangtagDataRef::setup()
207 SAL_INFO(
"i18nlangtag",
"LiblangtagDataRef::setup: initializing database");
208 if (maDataPath.isEmpty())
214void LiblangtagDataRef::teardown()
216 SAL_INFO(
"i18nlangtag",
"LiblangtagDataRef::teardown: finalizing database");
220void LiblangtagDataRef::setupDataPath()
222#if defined(ANDROID) || defined(EMSCRIPTEN)
223 maDataPath = OString(lo_get_app_data_dir()) +
"/share/liblangtag";
226 OUString
aURL(
"$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
"/liblangtag");
227 rtl::Bootstrap::expandMacros(aURL);
231 OUString
aData =
aURL +
"/language-subtag-registry.xml";
232 osl::DirectoryItem aDirItem;
233 if (osl::DirectoryItem::get( aData, aDirItem) == osl::DirectoryItem::E_None)
236 if (osl::FileBase::getSystemPathFromFileURL( aURL, aPath) == osl::FileBase::E_None)
240 if (maDataPath.isEmpty())
243 lt_db_set_datadir( maDataPath.getStr());
254 rLocale.Variant.clear();
390 OUString& rVariants );
394 static OUString
convertToBcp47(
const css::lang::Locale& rLocale );
403 mpImplLangtag( nullptr),
406 meIsValid( DECISION_DONTKNOW),
407 meIsIsoLocale( DECISION_DONTKNOW),
408 meIsIsoODF( DECISION_DONTKNOW),
409 meIsLiblangtagNeeded( DECISION_DONTKNOW),
414 mbCachedLanguage( false),
415 mbCachedScript( false),
416 mbCachedCountry( false),
417 mbCachedVariants( false),
418 mbCachedGlibcString( false)
427 maCachedLanguage( rLanguageTagImpl.maCachedLanguage),
428 maCachedScript( rLanguageTagImpl.maCachedScript),
429 maCachedCountry( rLanguageTagImpl.maCachedCountry),
430 maCachedVariants( rLanguageTagImpl.maCachedVariants),
431 maCachedGlibcString( rLanguageTagImpl.maCachedGlibcString),
432 mpImplLangtag( rLanguageTagImpl.mpImplLangtag ?
433 lt_tag_copy( rLanguageTagImpl.mpImplLangtag) : nullptr),
435 meScriptType( rLanguageTagImpl.meScriptType),
436 meIsValid( rLanguageTagImpl.meIsValid),
437 meIsIsoLocale( rLanguageTagImpl.meIsIsoLocale),
438 meIsIsoODF( rLanguageTagImpl.meIsIsoODF),
439 meIsLiblangtagNeeded( rLanguageTagImpl.meIsLiblangtagNeeded),
444 mbCachedLanguage( rLanguageTagImpl.mbCachedLanguage),
445 mbCachedScript( rLanguageTagImpl.mbCachedScript),
446 mbCachedCountry( rLanguageTagImpl.mbCachedCountry),
447 mbCachedVariants( rLanguageTagImpl.mbCachedVariants),
448 mbCachedGlibcString( rLanguageTagImpl.mbCachedGlibcString)
457 if (&rLanguageTagImpl ==
this)
470 lt_tag_unref(oldTag);
549 std::u16string_view rScript,
const OUString& rCountry )
564 maBcp47 = rLanguage +
"-" + rCountry;
572 if (rCountry.isEmpty())
573 maBcp47 = rLanguage +
"-" + rScript;
575 maBcp47 = rLanguage +
"-" + rScript +
"-" + rCountry;
614 SAL_WARN(
"i18nlangtag",
"LanguageTagImpl::registerOnTheFly: no Bcp47 string, no registering");
618 std::unique_lock aGuard( theMutex());
620 MapBcp47& rMapBcp47 = theMapBcp47();
621 MapBcp47::const_iterator it( rMapBcp47.find(
maBcp47));
622 bool bOtherImpl =
false;
623 if (it != rMapBcp47.end())
625 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerOnTheFly: found impl for '" <<
maBcp47 <<
"'");
626 pImpl = (*it).second;
627 if (pImpl.get() !=
this)
634 SAL_WARN(
"i18nlangtag",
"LanguageTag::registerOnTheFly: using other impl for this '" <<
maBcp47 <<
"'");
641 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerOnTheFly: new impl for '" <<
maBcp47 <<
"'");
642 pImpl = std::make_shared<LanguageTagImpl>( *
this);
643 rMapBcp47.insert( ::std::make_pair(
maBcp47, pImpl));
646 if (!bOtherImpl || !pImpl->mbInitializedLangID)
656 const MapLangID& rMapLangID = theMapLangID();
657 MapLangID::const_iterator itID( rMapLangID.find( nRegisterID));
658 if (itID != rMapLangID.end())
660 if ((*itID).second->maBcp47 !=
maBcp47)
662 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerOnTheFly: not using suggested 0x"
663 << ::std::hex << nRegisterID <<
" for '" <<
maBcp47 <<
"' have '"
664 << (*itID).second->maBcp47 <<
"'");
669 SAL_WARN(
"i18nlangtag",
"LanguageTag::registerOnTheFly: suggested 0x"
670 << ::std::hex << nRegisterID <<
" for '" <<
maBcp47 <<
"' already registered");
679 pImpl->mnLangID = nRegisterID;
680 pImpl->mbInitializedLangID =
true;
681 if (pImpl.get() !=
this)
688 ::std::pair< MapLangID::const_iterator, bool > res(
689 theMapLangID().insert( ::std::make_pair( pImpl->mnLangID, pImpl)));
692 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerOnTheFly: cross-inserted 0x"
693 << ::std::hex << pImpl->mnLangID <<
" for '" <<
maBcp47 <<
"'");
697 SAL_WARN(
"i18nlangtag",
"LanguageTag::registerOnTheFly: not cross-inserted 0x"
698 << ::std::hex << pImpl->mnLangID <<
" for '" <<
maBcp47 <<
"' have '"
699 << (*res.first).second->maBcp47 <<
"'");
708 const MapLangID& rMapLangID = theMapLangID();
709 MapLangID::const_iterator itID( rMapLangID.find( nRegisterID));
710 if (itID != rMapLangID.end())
711 return (*itID).second->getScriptType();
723 "LanguageTag::setConfiguredSystemLanguage: refusing to set unresolved system locale 0x" <<
724 ::std::hex << nLang);
727 SAL_INFO(
"i18nlangtag",
"LanguageTag::setConfiguredSystemLanguage: setting to 0x" << ::std::hex << nLang);
731 theSystemLocale().reset();
761#if OSL_DEBUG_LEVEL > 0
762 static size_t nCalls = 0;
764 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << nCalls <<
" calls");
771 pImpl = theSystemLocale();
774#if OSL_DEBUG_LEVEL > 0
775 static size_t nCallsSystem = 0;
777 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << nCallsSystem <<
" system calls");
798 theDontKnow = std::make_shared<LanguageTagImpl>( *
this);
800#if OSL_DEBUG_LEVEL > 0
801 static size_t nCallsDontKnow = 0;
803 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << nCallsDontKnow <<
" DontKnow calls");
810 pImpl = theSystemLocale();
811 if (pImpl && pImpl->mnLangID ==
mnLangID)
813#if OSL_DEBUG_LEVEL > 0
814 static size_t nCallsSystemEqual = 0;
816 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << nCallsSystemEqual
817 <<
" system equal LangID calls");
841 pImpl = theSystemLocale();
842 if (pImpl && pImpl->maBcp47 ==
maBcp47)
844#if OSL_DEBUG_LEVEL > 0
845 static size_t nCallsSystemEqual = 0;
847 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << nCallsSystemEqual <<
" system equal BCP47 calls");
853#if OSL_DEBUG_LEVEL > 0
854 static size_t nCallsNonSystem = 0;
856 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << nCallsNonSystem <<
" non-system calls");
859 std::unique_lock aGuard( theMutex());
861#if OSL_DEBUG_LEVEL > 0
862 static long nRunning = 0;
866 SAL_WARN_IF( nRunning > 1,
"i18nlangtag",
"LanguageTag::registerImpl: re-entered for '"
868 struct Runner { Runner() { ++nRunning; } ~Runner() { --nRunning; } } aRunner;
874 MapLangID& rMap = theMapLangID();
875 MapLangID::const_iterator it( rMap.find(
mnLangID));
876 if (it != rMap.end())
878 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: found impl for 0x" << ::std::hex <<
mnLangID);
879 pImpl = (*it).second;
883 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: new impl for 0x" << ::std::hex <<
mnLangID);
884 pImpl = std::make_shared<LanguageTagImpl>( *
this);
885 rMap.insert( ::std::make_pair(
mnLangID, pImpl));
887 if (!pImpl->mbInitializedLocale)
888 pImpl->convertLangToLocale();
891 if (nLang == pImpl->mnLangID)
893 if (!pImpl->mbInitializedBcp47)
894 pImpl->convertLocaleToBcp47();
895 ::std::pair< MapBcp47::const_iterator, bool > res(
896 theMapBcp47().insert( ::std::make_pair( pImpl->maBcp47, pImpl)));
899 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: cross-inserted '" << pImpl->maBcp47 <<
"' for 0x" << ::std::hex <<
mnLangID);
903 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: not cross-inserted '" << pImpl->maBcp47 <<
"' for 0x" << ::std::hex <<
mnLangID <<
" have 0x"
904 << ::std::hex << (*res.first).second->mnLangID);
909 if (!pImpl->mbInitializedBcp47)
910 pImpl->convertLocaleToBcp47();
911 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: not cross-inserted '" << pImpl->maBcp47 <<
"' for 0x" << ::std::hex <<
mnLangID <<
" round-trip to 0x" << ::std::hex << nLang);
917 MapBcp47& rMap = theMapBcp47();
918 MapBcp47::const_iterator it( rMap.find(
maBcp47));
919 if (it != rMap.end())
921 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: found impl for '" <<
maBcp47 <<
"'");
922 pImpl = (*it).second;
926 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: new impl for '" <<
maBcp47 <<
"'");
927 pImpl = std::make_shared<LanguageTagImpl>( *
this);
928 ::std::pair< MapBcp47::iterator, bool > insOrig( rMap.insert( ::std::make_pair(
maBcp47, pImpl)));
931 if (pImpl->synCanonicalize())
933 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: canonicalized to '" << pImpl->maBcp47 <<
"'");
934 ::std::pair< MapBcp47::const_iterator, bool > insCanon(
935 rMap.insert( ::std::make_pair( pImpl->maBcp47, pImpl)));
936 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: " << (insCanon.second ?
"" :
"not ")
937 <<
"inserted '" << pImpl->maBcp47 <<
"'");
946 if (!insCanon.second && (*insCanon.first).second != pImpl)
948 (*insOrig.first).second = pImpl = (*insCanon.first).second;
949 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: share impl with 0x"
950 << ::std::hex << pImpl->mnLangID);
953 if (!pImpl->mbInitializedLangID)
956 if (!pImpl->mbInitializedLocale)
957 pImpl->convertBcp47ToLocale();
958 if (!pImpl->mbInitializedLangID)
959 pImpl->convertLocaleToLang(
true);
972 bInsert = (aBcp47 == pImpl->maBcp47);
978 ::std::pair< MapLangID::const_iterator, bool > res(
979 theMapLangID().insert( ::std::make_pair( pImpl->mnLangID, pImpl)));
982 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: cross-inserted 0x"
983 << ::std::hex << pImpl->mnLangID <<
" for '" <<
maBcp47 <<
"'");
987 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: not cross-inserted 0x"
988 << ::std::hex << pImpl->mnLangID <<
" for '" <<
maBcp47 <<
"' have '"
989 << (*res.first).second->maBcp47 <<
"'");
994 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: not cross-inserted 0x"
995 << ::std::hex << pImpl->mnLangID <<
" for '" <<
maBcp47 <<
"' round-trip to '"
1003 SAL_WARN(
"i18nlangtag",
"LanguageTag::registerImpl: can't register for 0x" << ::std::hex <<
mnLangID );
1004 pImpl = std::make_shared<LanguageTagImpl>( *
this);
1011 theSystemLocale() = pImpl;
1012 SAL_INFO(
"i18nlangtag",
"LanguageTag::registerImpl: added system locale 0x"
1013 << ::std::hex << pImpl->mnLangID <<
" '" << pImpl->maBcp47 <<
"'");
1093 explicit dumper( lt_tag_t** pp ) : mpp( *pp ?
NULL : pp) {}
1094 ~dumper() {
if (mpp && *mpp) lt_tag_dump( *mpp); }
1099 bool bChanged =
false;
1111 bool bTemporaryLocale =
false;
1112 bool bTemporaryLangID =
false;
1126 OUString aLanguage, aScript, aCountry, aRegion, aVariants;
1133 OUStringBuffer
aBuf( aLanguage.getLength() + 1 + aScript.getLength() +
1134 1 + aCountry.getLength() + 1 + aRegion.getLength() + 1 + aVariants.getLength());
1135 aBuf.append( aLanguage);
1136 if (!aScript.isEmpty())
1137 aBuf.append(
"-" + aScript);
1138 if (!aCountry.isEmpty())
1139 aBuf.append(
"-" + aCountry);
1140 if (!aRegion.isEmpty())
1141 aBuf.append(
"-" + aRegion);
1142 if (!aVariants.isEmpty())
1143 aBuf.append(
"-" + aVariants);
1144 OUString
aStr(
aBuf.makeStringAndClear());
1189 bTemporaryLangID =
true;
1196 if (rKnowns.find(
maBcp47) != rKnowns.end())
1201 if (!aNew.Language.isEmpty() &&
1202 (aNew.Language !=
maLocale.Language ||
1203 aNew.Country !=
maLocale.Country ||
1213 if (bTemporaryLocale)
1218 if (bTemporaryLangID)
1231 SAL_INFO(
"i18nlangtag",
"LanguageTagImpl::canonicalize: using liblangtag for '" <<
maBcp47 <<
"'");
1235 theDataRef().init();
1245 SAL_WARN(
"i18nlangtag",
"LanguageTagImpl::canonicalize: could not parse '" <<
maBcp47 <<
"'");
1250 SAL_WARN_IF(!pTag,
"i18nlangtag",
"LanguageTagImpl::canonicalize: could not canonicalize '" <<
maBcp47 <<
"'");
1253 OUString aNew(OUString::createFromAscii(pTag));
1264 SAL_WARN(
"i18nlangtag",
"LanguageTagImpl::canonicalize: could not reparse '"
1279 SAL_INFO(
"i18nlangtag",
"LanguageTagImpl::canonicalize: could not parse '" <<
maBcp47 <<
"'");
1288 bool bChanged =
false;
1310 "LanguageTag::syncFromImpl: re-registering, '" << pImpl->
maBcp47 <<
"' vs '" <<
maBcp47 <<
1311 " and 0x" << ::std::hex << pImpl->
mnLangID <<
" vs 0x" << ::std::hex <<
mnLangID);
1385 bool bRemapped =
false;
1408 bRemapped = (
maBcp47 != aOrgBcp47);
1423 if (aLoc.Language !=
"en" ||
getLanguage() ==
"en")
1434 SAL_WARN(
"i18nlangtag",
"LanguageTagImpl::convertLocaleToLang: with bAllowOnTheFlyID invalid '"
1545 RTL_TEXTENCODING_UTF8);
1551 theDataRef::get().init();
1552 mpImplLangtag = lt_tag_convert_from_locale(
aStr.getStr(), &aError.p);
1553 maBcp47 = OStringToOUString( lt_tag_get_string( mpImplLangtag), RTL_TEXTENCODING_UTF8);
1559 SAL_WARN(
"i18nlangtag",
"LanguageTag(rtl_Locale) - unknown: " <<
aStr);
1584 static const OUString theEmptyBcp47 =
u"";
1587 return theEmptyBcp47;
1607 const lt_lang_t* pLangT = lt_tag_get_language(
mpImplLangtag);
1609 "LanguageTag::getLanguageFromLangtag: pLangT==NULL for '" <<
maBcp47 <<
"'");
1612 const char* pLang = lt_lang_get_tag( pLangT);
1614 "LanguageTag::getLanguageFromLangtag: pLang==NULL for '" <<
maBcp47 <<
"'");
1616 aLanguage = OUString::createFromAscii( pLang);
1635 const lt_script_t* pScriptT = lt_tag_get_script(
mpImplLangtag);
1639 const char* pScript = lt_script_get_tag( pScriptT);
1640 SAL_WARN_IF( !pScript,
"i18nlangtag",
"LanguageTag::getScriptFromLangtag: pScript==NULL");
1642 aScript = OUString::createFromAscii( pScript);
1661 const lt_region_t* pRegionT = lt_tag_get_region(
mpImplLangtag);
1669 "i18nlangtag",
"LanguageTag::getRegionFromLangtag: pRegionT==NULL for '" <<
maBcp47 <<
"'");
1672 const char* pRegion = lt_region_get_tag( pRegionT);
1674 "LanguageTag::getRegionFromLangtag: pRegion==NULL for'" <<
maBcp47 <<
"'");
1676 aRegion = OUString::createFromAscii( pRegion);
1689 OUStringBuffer aVariants;
1695 const lt_list_t* pVariantsT = lt_tag_get_variants(
mpImplLangtag);
1696 for (
const lt_list_t*
pE = pVariantsT;
pE;
pE = lt_list_next(
pE))
1698 const lt_variant_t* pVariantT =
static_cast<const lt_variant_t*
>(lt_list_value(
pE));
1701 const char*
p = lt_variant_get_tag( pVariantT);
1704 if (!aVariants.isEmpty())
1705 aVariants.append(
"-");
1706 aVariants.appendAscii(
p);
1716 return aVariants.makeStringAndClear();
1723 static lang::Locale theEmptyLocale;
1726 return theEmptyLocale;
1790 return 'a' <= c && c <=
'z';
1795 return 'A' <= c && c <=
'Z';
1805 bool b2chars = rLanguage.getLength() == 2;
1806 if ((b2chars || rLanguage.getLength() == 3) &&
1807 isLowerAscii( rLanguage[0]) && isLowerAscii( rLanguage[1]) &&
1808 (b2chars || isLowerAscii( rLanguage[2])))
1810 SAL_WARN_IF( ((rLanguage.getLength() == 2 || rLanguage.getLength() == 3) &&
1811 (isUpperAscii( rLanguage[0]) || isUpperAscii( rLanguage[1]))) ||
1812 (rLanguage.getLength() == 3 && isUpperAscii( rLanguage[2])),
"i18nlangtag",
1813 "LanguageTag::isIsoLanguage: rejecting upper case " << rLanguage);
1822 if (rRegion.isEmpty() ||
1823 (rRegion.getLength() == 2 && isUpperAscii( rRegion[0]) && isUpperAscii( rRegion[1])))
1825 SAL_WARN_IF( rRegion.getLength() == 2 && (isLowerAscii( rRegion[0]) || isLowerAscii( rRegion[1])),
1826 "i18nlangtag",
"LanguageTag::isIsoCountry: rejecting lower case " << rRegion);
1835 if (rScript.isEmpty() ||
1836 (rScript.getLength() == 4 &&
1837 isUpperAscii( rScript[0]) && isLowerAscii( rScript[1]) &&
1838 isLowerAscii( rScript[2]) && isLowerAscii( rScript[3])))
1841 (isLowerAscii( rScript[0]) || isUpperAscii( rScript[1]) ||
1842 isUpperAscii( rScript[2]) || isUpperAscii( rScript[3])),
1843 "i18nlangtag",
"LanguageTag::isIsoScript: rejecting case mismatch " << rScript);
1896 if (!aScript.isEmpty())
1898 aLanguageScript +=
"-" + aScript;
1900 return aLanguageScript;
1967 char* pLang = lt_tag_convert_to_locale(
mpImplLangtag,
nullptr);
1984 if (aCountry.isEmpty())
1987 aRet =
getLanguage() +
"_" + aCountry + rEncoding;
1992 sal_Int32 nAt = aRet.indexOf(
'@');
1994 aRet = OUString::Concat(aRet.subView(0, nAt)) + rEncoding + aRet.subView(nAt);
2044 OUString aLanguage, aScript, aCountry, aRegion, aVariants;
2123 "LanguageTag::isValidBcp47: canonicalize() didn't set meIsValid");
2141 const lang::Locale& rLocale1 =
getLocale();
2143 if ( rLocale1.Language != aLocale2.Language ||
2144 rLocale1.Country != aLocale2.Country ||
2145 rLocale1.Variant != aLocale2.Variant)
2147 if (rLocale1.Language !=
"en" && aLocale2.Language ==
"en" && aLocale2.Country ==
"US")
2152 for (
auto const& fallback : aFallbacks)
2156 if (aLocale2.Language !=
"en" || aLocale2.Country !=
"US")
2160 SAL_INFO(
"i18nlangtag",
"LanguageTag::makeFallback - for (" <<
2161 rLocale1.Language <<
"," << rLocale1.Country <<
"," << rLocale1.Variant <<
") to (" <<
2162 aLocale2.Language <<
"," << aLocale2.Country <<
"," << aLocale2.Variant <<
")");
2178 ::std::vector< OUString > aVec;
2183 if (!aCountry.isEmpty())
2185 if (bIncludeFullBcp47)
2186 aVec.emplace_back(aLanguage +
"-" + aCountry);
2187 if (aLanguage ==
"zh")
2193 if (aCountry ==
"HK" || aCountry ==
"MO")
2194 aVec.emplace_back(aLanguage +
"-TW");
2195 else if (aCountry !=
"CN")
2196 aVec.emplace_back(aLanguage +
"-CN");
2197 aVec.push_back( aLanguage);
2199 else if (aLanguage ==
"sh")
2204 aVec.emplace_back(
"sr-Latn-" + aCountry);
2205 aVec.emplace_back(
"sr-Latn");
2206 aVec.emplace_back(
"sh");
2207 aVec.emplace_back(
"sr-" + aCountry);
2208 aVec.emplace_back(
"sr");
2210 else if (aLanguage ==
"ca" && aCountry ==
"XV")
2213 aVec.insert( aVec.end(), aRep.begin(), aRep.end());
2216 else if (aLanguage ==
"ku")
2218 if (aCountry ==
"TR" || aCountry ==
"SY")
2220 aVec.emplace_back(
"kmr-Latn-" + aCountry);
2221 aVec.emplace_back(
"kmr-" + aCountry);
2222 aVec.emplace_back(
"kmr-Latn");
2223 aVec.emplace_back(
"kmr");
2224 aVec.push_back( aLanguage);
2226 else if (aCountry ==
"IQ" || aCountry ==
"IR")
2228 aVec.emplace_back(
"ckb-" + aCountry);
2229 aVec.emplace_back(
"ckb");
2232 else if (aLanguage ==
"kmr" && (aCountry ==
"TR" || aCountry ==
"SY"))
2234 aVec.emplace_back(
"ku-Latn-" + aCountry);
2235 aVec.emplace_back(
"ku-" + aCountry);
2236 aVec.push_back( aLanguage);
2237 aVec.emplace_back(
"ku");
2239 else if (aLanguage ==
"ckb" && (aCountry ==
"IQ" || aCountry ==
"IR"))
2241 aVec.emplace_back(
"ku-Arab-" + aCountry);
2242 aVec.emplace_back(
"ku-" + aCountry);
2243 aVec.push_back( aLanguage);
2247 aVec.push_back( aLanguage);
2251 if (bIncludeFullBcp47)
2252 aVec.push_back( aLanguage);
2253 if (aLanguage ==
"sh")
2255 aVec.emplace_back(
"sr-Latn");
2256 aVec.emplace_back(
"sr");
2258 else if (aLanguage ==
"pli")
2261 aVec.emplace_back(
"pi-Latn");
2262 aVec.emplace_back(
"pi");
2269 if (bIncludeFullBcp47)
2276 aVec.emplace_back(
"en-GB-oxendict");
2277 else if (
maBcp47 ==
"en-GB-oxendict")
2278 aVec.emplace_back(
"en-GB-oed");
2285 bool bHaveLanguageScriptVariant =
false;
2286 if (!aCountry.isEmpty())
2288 if (!aVariants.isEmpty())
2290 aTmp = aLanguage +
"-" + aScript +
"-" + aCountry +
"-" + aVariants;
2292 aVec.push_back( aTmp);
2295 aTmp = aLanguage +
"-" + aScript +
"-" + aVariants;
2297 aVec.push_back( aTmp);
2298 bHaveLanguageScriptVariant =
true;
2300 aTmp = aLanguage +
"-" + aScript +
"-" + aCountry;
2302 aVec.push_back( aTmp);
2303 if (aLanguage ==
"sr" && aScript ==
"Latn")
2306 if (aCountry ==
"CS")
2308 aVec.emplace_back(
"sr-Latn-YU");
2309 aVec.emplace_back(
"sh-CS");
2310 aVec.emplace_back(
"sh-YU");
2313 aVec.emplace_back(
"sh-" + aCountry);
2315 else if (aLanguage ==
"pi" && aScript ==
"Latn")
2316 aVec.emplace_back(
"pli");
2317 else if (aLanguage ==
"krm" && aScript ==
"Latn" && (aCountry ==
"TR" || aCountry ==
"SY"))
2318 aVec.emplace_back(
"ku-" + aCountry);
2320 if (!aVariants.isEmpty() && !bHaveLanguageScriptVariant)
2322 aTmp = aLanguage +
"-" + aScript +
"-" + aVariants;
2324 aVec.push_back( aTmp);
2326 aTmp = aLanguage +
"-" + aScript;
2328 aVec.push_back( aTmp);
2332 if (aLanguage ==
"sr" && aScript ==
"Latn")
2333 aVec.emplace_back(
"sh");
2334 else if (aLanguage ==
"ku" && aScript ==
"Arab")
2335 aVec.emplace_back(
"ckb");
2337 else if (aLanguage ==
"krm" && aScript ==
"Latn" && aCountry.isEmpty())
2338 aVec.emplace_back(
"ku");
2340 bool bHaveLanguageVariant =
false;
2341 if (!aCountry.isEmpty())
2343 if (!aVariants.isEmpty())
2345 aTmp = aLanguage +
"-" + aCountry +
"-" + aVariants;
2347 aVec.push_back( aTmp);
2348 if (
maBcp47 ==
"ca-ES-valencia")
2349 aVec.emplace_back(
"ca-XV");
2355 if (aVariants.getLength() >= 5 ||
2356 (aVariants.getLength() == 4 &&
'0' <= aVariants[0] && aVariants[0] <=
'9'))
2358 aTmp = aLanguage +
"-" + aVariants;
2360 aVec.push_back( aTmp);
2361 bHaveLanguageVariant =
true;
2364 aTmp = aLanguage +
"-" + aCountry;
2366 aVec.push_back( aTmp);
2368 if (!aVariants.isEmpty() && !bHaveLanguageVariant)
2372 if (aVariants.getLength() >= 5 ||
2373 (aVariants.getLength() == 4 &&
'0' <= aVariants[0] && aVariants[0] <=
'9'))
2375 aTmp = aLanguage +
"-" + aVariants;
2377 aVec.push_back( aTmp);
2383 if (!aCountry.isEmpty())
2385 if (aLanguage ==
"sr" && aCountry ==
"CS")
2386 aVec.emplace_back(
"sr-YU");
2390 if (!aLanguage.isEmpty() && aLanguage !=
maBcp47)
2391 aVec.push_back( aLanguage);
2400 return "es-ES_tradnl";
2442 return getBcp47(
false).compareToIgnoreAsciiCase( rLanguageTag.
getBcp47(
false)) < 0;
2448 OUString& rLanguage, OUString& rScript, OUString& rCountry, OUString& rRegion, OUString& rVariants )
2451 const sal_Int32 nLen = rBcp47.getLength();
2452 const sal_Int32 nHyph1 = rBcp47.indexOf(
'-');
2453 sal_Int32 nHyph2 = (nHyph1 < 0 ? -1 : rBcp47.indexOf(
'-', nHyph1 + 1));
2454 sal_Int32 nHyph3 = (nHyph2 < 0 ? -1 : rBcp47.indexOf(
'-', nHyph2 + 1));
2455 sal_Int32 nHyph4 = (nHyph3 < 0 ? -1 : rBcp47.indexOf(
'-', nHyph3 + 1));
2456 if (nLen == 1 && rBcp47[0] ==
'*')
2461 else if (nHyph1 == 1 && rBcp47[0] ==
'x')
2466 else if (nLen == 1 && rBcp47[0] ==
'C')
2475 else if (nLen == 2 || nLen == 3)
2479 rLanguage = rBcp47.toAsciiLowerCase();
2487 else if ( (nHyph1 == 2 && nLen == 5)
2488 || (nHyph1 == 3 && nLen == 6))
2492 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2493 rCountry = rBcp47.copy( nHyph1 + 1, 2).toAsciiUpperCase();
2500 else if ( (nHyph1 == 2 && nLen == 6)
2501 || (nHyph1 == 3 && nLen == 7))
2505 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2507 rRegion = rBcp47.copy( nHyph1 + 1, 3);
2513 else if ( (nHyph1 == 2 && nLen == 7)
2514 || (nHyph1 == 3 && nLen == 8))
2519 if (
'0' <= c && c <=
'9')
2522 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2526 rVariants = rBcp47.copy( nHyph1 + 1);
2531 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2532 rScript = rBcp47.copy( nHyph1 + 1, 1).toAsciiUpperCase() +
2533 rBcp47.copy( nHyph1 + 2, 3).toAsciiLowerCase();
2541 else if ( (nHyph1 == 2 && nHyph2 == 7 && nLen == 10)
2542 || (nHyph1 == 3 && nHyph2 == 8 && nLen == 11))
2546 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2547 rScript = rBcp47.copy( nHyph1 + 1, 1).toAsciiUpperCase() + rBcp47.copy( nHyph1 + 2, 3).toAsciiLowerCase();
2548 rCountry = rBcp47.copy( nHyph2 + 1, 2).toAsciiUpperCase();
2554 else if ( (nHyph1 == 2 && nHyph2 == 7 && nLen == 11)
2555 || (nHyph1 == 3 && nHyph2 == 8 && nLen == 12))
2559 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2560 rScript = rBcp47.copy( nHyph1 + 1, 1).toAsciiUpperCase() + rBcp47.copy( nHyph1 + 2, 3).toAsciiLowerCase();
2562 rRegion = rBcp47.copy( nHyph2 + 1, 3);
2567 else if ( (nHyph1 == 2 && nHyph2 == 7 && nHyph3 == 10 && nLen >= 15)
2568 || (nHyph1 == 3 && nHyph2 == 8 && nHyph3 == 11 && nLen >= 16))
2571 nHyph4 = rBcp47.getLength();
2572 if (nHyph4 - nHyph3 > 4 && nHyph4 - nHyph3 <= 9)
2574 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2575 rScript = rBcp47.copy( nHyph1 + 1, 1).toAsciiUpperCase() + rBcp47.copy( nHyph1 + 2, 3).toAsciiLowerCase();
2576 rCountry = rBcp47.copy( nHyph2 + 1, 2).toAsciiUpperCase();
2578 rVariants = rBcp47.copy( nHyph3 + 1);
2582 else if ( (nHyph1 == 2 && nHyph2 == 7 && nHyph3 == 11 && nLen >= 16)
2583 || (nHyph1 == 3 && nHyph2 == 8 && nHyph3 == 12 && nLen >= 17))
2586 nHyph4 = rBcp47.getLength();
2587 if (nHyph4 - nHyph3 > 4 && nHyph4 - nHyph3 <= 9)
2589 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2590 rScript = rBcp47.copy( nHyph1 + 1, 1).toAsciiUpperCase() + rBcp47.copy( nHyph1 + 2, 3).toAsciiLowerCase();
2592 rRegion = rBcp47.copy( nHyph2 + 1, 3);
2593 rVariants = rBcp47.copy( nHyph3 + 1);
2597 else if ( (nHyph1 == 2 && nHyph2 == 5 && nHyph3 == 7)
2598 || (nHyph1 == 3 && nHyph2 == 6 && nHyph3 == 8))
2600 if (rBcp47[nHyph3-1] ==
'u')
2607 if (rBcp47.equalsIgnoreAsciiCase(
"es-ES-u-co-trad"))
2613 rVariants =
"u-co-trad";
2618 else if ( (nHyph1 == 2 && nHyph2 == 5 && nLen >= 10)
2619 || (nHyph1 == 3 && nHyph2 == 6 && nLen >= 11))
2622 nHyph3 = rBcp47.getLength();
2623 if (nHyph3 - nHyph2 > 4 && nHyph3 - nHyph2 <= 9)
2625 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2627 rCountry = rBcp47.copy( nHyph1 + 1, 2).toAsciiUpperCase();
2629 rVariants = rBcp47.copy( nHyph2 + 1);
2633 else if ( (nHyph1 == 2 && nHyph2 == 6 && nLen >= 11)
2634 || (nHyph1 == 3 && nHyph2 == 7 && nLen >= 12))
2637 nHyph3 = rBcp47.getLength();
2638 if (nHyph3 - nHyph2 > 4 && nHyph3 - nHyph2 <= 9)
2640 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2643 rRegion = rBcp47.copy( nHyph1 + 1, 3);
2644 rVariants = rBcp47.copy( nHyph2 + 1);
2648 else if ( (nHyph1 == 2 && nLen >= 8)
2649 || (nHyph1 == 3 && nLen >= 9))
2652 nHyph2 = rBcp47.getLength();
2653 if (nHyph2 - nHyph1 > 5 && nHyph2 - nHyph1 <= 9)
2655 rLanguage = rBcp47.copy( 0, nHyph1).toAsciiLowerCase();
2659 rVariants = rBcp47.copy( nHyph1 + 1);
2667 if (rBcp47.equalsIgnoreAsciiCase(
"en-GB-oed"))
2677 else if (rBcp47.equalsIgnoreAsciiCase(
"es-ES_tradnl"))
2684 rVariants =
"tradnl";
2691 SAL_INFO(
"i18nlangtag",
"LanguageTagImpl::simpleExtract: did not extract '" << rBcp47 <<
"'");
2700 assert(rLanguage.getLength() == 2 || rLanguage.getLength() == 3
2702 assert(rScript.isEmpty() || rScript.getLength() == 4);
2703 assert(rCountry.isEmpty() || rRegion.isEmpty());
2704 assert(rCountry.isEmpty() || rCountry.getLength() == 2);
2705 assert(rRegion.isEmpty() || rRegion.getLength() == 3);
2706 assert(rVariants.isEmpty() || rVariants.getLength() >= 4 || rVariants ==
"oed");
2714 const ::std::vector< OUString > & rList,
const OUString & rReference )
2720 ::std::vector< OUString >::const_iterator it = std::find(rList.begin(), rList.end(), rReference);
2721 if (it != rList.end())
2725 if (rReference !=
"en-US")
2727 aFallbacks.emplace_back(
"en-US");
2728 if (rReference !=
"en")
2729 aFallbacks.emplace_back(
"en");
2731 if (rReference !=
"x-default")
2732 aFallbacks.emplace_back(
"x-default");
2733 if (rReference !=
"x-no-translate")
2734 aFallbacks.emplace_back(
"x-no-translate");
2740 for (
const auto& fb : aFallbacks)
2742 it = std::find(rList.begin(), rList.end(), fb);
2743 if (it != rList.end())
2750 return rList.begin();
2756 const ::std::vector< css::lang::Locale > & rList,
2757 const css::lang::Locale & rReference )
2763 ::std::vector< lang::Locale >::const_iterator it = std::find_if(rList.begin(), rList.end(),
2764 [&rReference](
const lang::Locale& rLocale) {
2765 return rLocale.Language == rReference.Language
2766 && rLocale.Country == rReference.Country
2767 && rLocale.Variant == rReference.Variant; });
2768 if (it != rList.end())
2773 ::std::vector< ::std::vector< OUString > > aListFallbacks( rList.size());
2775 for (
auto const& elem : rList)
2778 aListFallbacks[
i++] = aTmp;
2780 for (
auto const& rfb : aFallbacks)
2783 for (
auto const& lfb : aListFallbacks)
2785 for (
auto const& fb : lfb)
2788 return rList.begin() + nPosFb;
2806 return nNewLangID != nLangID;
2814 return lang::Locale();
2816 return LanguageTag( nLangID).getLocale( bResolveSystem);
2823 if (rLocale.Language.isEmpty() && !bResolveSystem)
2826 return LanguageTag( rLocale).getLanguageType( bResolveSystem);
2834 if (rLocale.Language.isEmpty())
2840 aBcp47 = rLocale.Variant;
2847 if (rLocale.Country.isEmpty())
2848 aBcp47 = rLocale.Language;
2851 aBcp47 = rLocale.Language +
"-" + rLocale.Country;
2862 if (rLocale.Language.isEmpty())
2883 if (aLocale.Language.isEmpty())
2892 if (rBcp47.isEmpty() && !bResolveSystem)
2893 return lang::Locale();
2895 return LanguageTag( rBcp47).getLocale( bResolveSystem);
2909 return LanguageTag( rBcp47).makeFallback().getLanguageType();
2916 return LanguageTag( rBcp47).makeFallback().getLocale();
2923 if (rLocale.Language.isEmpty())
2926 return LanguageTag( rLocale).makeFallback().getLanguageType();
2934 bool bValid =
false;
2938 lt_tag_t* mpLangtag;
2941 theDataRef().init();
2942 mpLangtag = lt_tag_new();
2946 lt_tag_unref( mpLangtag);
2954 char* pTag = lt_tag_canonicalize( aVar.mpLangtag, &aError.p);
2955 SAL_WARN_IF( !pTag,
"i18nlangtag",
"LanguageTag:isValidBcp47: could not canonicalize '" << rString <<
"'");
2959 if (ePrivateUse != PrivateUse::ALLOW)
2963 const char* pLang =
nullptr;
2964 const lt_lang_t* pLangT = lt_tag_get_language( aVar.mpLangtag);
2967 pLang = lt_lang_get_tag( pLangT);
2976 if (ePrivateUse == PrivateUse::ALLOW_ART_X && pLang && strcmp( pLang,
"art") == 0)
2981 const lt_string_t* pPrivate = lt_tag_get_privateuse( aVar.mpLangtag);
2982 if (pPrivate && lt_string_length( pPrivate) > 0)
2987 if (o_pCanonicalized)
2988 *o_pCanonicalized = OUString::createFromAscii( pTag);
2994 SAL_INFO(
"i18nlangtag",
"LanguageTag:isValidBcp47: could not parse '" << rString <<
"'");
@ IRISH_GAELIC_WITH_DOT_ABOVE
FILE * init(int, char **)
bool cacheSimpleLSCV()
Obtain Language, Script, Country and Variants via simpleExtract() and assign them to the cached varia...
OUString getScriptFromLangtag()
bool convertLocaleToLang(bool bAllowOnTheFlyID)
void convertLangToLocale()
bool synCanonicalize()
Canonicalize if not yet done and synchronize initialized conversions.
OUString const & getGlibcLocaleString() const
static OUString convertToBcp47(const css::lang::Locale &rLocale)
Convert Locale to BCP 47 string without resolving system and creating temporary LanguageTag instances...
css::lang::Locale maLocale
LanguageTagImpl(const LanguageTag &rLanguageTag)
OUString getLanguageFromLangtag()
lt_tag_t * mpImplLangtag
liblangtag pointer
OUString const & getLanguage() const
LanguageTag::ImplPtr registerOnTheFly(LanguageType nRegisterID)
Generates on-the-fly LangID and registers the maBcp47,mnLangID pair.
LanguageTagImpl & operator=(const LanguageTagImpl &rLanguageTagImpl)
OUString const & getScript() const
OUString maCachedLanguage
cache getLanguage()
LanguageTag::ScriptType meScriptType
OUString const & getCountry() const
LanguageTag::ScriptType getScriptType() const
static Extraction simpleExtract(const OUString &rBcp47, OUString &rLanguage, OUString &rScript, OUString &rCountry, OUString &rRegion, OUString &rVariants)
Of a language tag of the form lll[-Ssss][-CC][-vvvvvvvv] extract the portions.
OUString maCachedScript
cache getScript()
void convertLocaleToBcp47()
OUString const & getVariants() const
OUString getRegionFromLangtag()
OUString getVariantsFromLangtag()
OUString getRegion() const
OUString maCachedCountry
cache getCountry()
OUString const & getBcp47() const
Decision meIsLiblangtagNeeded
whether processing with liblangtag needed
bool isValidBcp47() const
OUString maCachedVariants
cache getVariants()
void convertBcp47ToLocale()
void setScriptType(LanguageTag::ScriptType st)
void convertBcp47ToLang()
OUString maCachedGlibcString
cache getGlibcLocaleString()
void convertLangToBcp47()
Wrapper for liblangtag BCP 47 language tags, MS-LangIDs, locales and conversions in between.
void convertFromRtlLocale()
void syncVarsFromImpl() const
::std::vector< css::lang::Locale >::const_iterator getMatchingFallback(const ::std::vector< css::lang::Locale > &rList, const css::lang::Locale &rReference)
Search for an equal or for a similar locale in a list of possible ones where at least the language ma...
bool operator<(const LanguageTag &rLanguageTag) const
Test this LanguageTag less than that LanguageTag.
LanguageType getLanguageType(bool bResolveSystem=true) const
Obtain mapping to MS-LangID.
void convertLocaleToLang()
OUString getLanguageAndScript() const
Get combined language and script code, separated by '-' if non-default script, if default script only...
bool isSystemLocale() const
If this tag was constructed as an empty tag denoting the system locale.
void syncVarsFromRawImpl() const
static bool isIsoScript(const OUString &rScript)
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
Obtain language tag as Locale.
bool synCanonicalize()
Canonicalize if not yet done and synchronize initialized conversions.
LanguageTag(const OUString &rBcp47LanguageTag, bool bCanonicalize=false)
Init LanguageTag with existing BCP 47 language tag string.
bool operator!=(const LanguageTag &rLanguageTag) const
Test inequality of two LanguageTag.
LanguageTagImpl * getImpl()
OUString getLanguage() const
Get ISO 639 language code, or BCP 47 language.
static void setConfiguredSystemLanguage(LanguageType nLang)
@ATTENTION: ONLY to be called by the application's configuration!
static css::lang::Locale convertToLocaleWithFallback(const OUString &rBcp47)
Convert BCP 47 string to Locale with fallback, convenience method.
OUString getScript() const
Get ISO 15924 script code, if not the default script according to BCP 47.
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
Convert MS-LangID to Locale.
void convertLangToLocale()
static bool isIsoLanguage(const OUString &rLanguage)
const OUString & getBcp47(bool bResolveSystem=true) const
Obtain BCP 47 language tag.
LanguageTag & makeFallback()
Fall back to a known locale.
void convertBcp47ToLocale()
css::lang::Locale maLocale
bool isValidBcp47() const
If this is a valid BCP 47 language tag.
bool hasScript() const
If language tag has a non-default script specified.
bool isIsoLocale() const
If language tag is a locale that can be expressed using only ISO 639 language codes and ISO 3166 coun...
static void disable_lt_tag_parse()
@ATTENTION: ONLY to be called by fuzzing setup
static bool isOnTheFlyID(LanguageType nLang)
If nLang is a generated on-the-fly LangID.
static OUString convertToBcp47(LanguageType nLangID)
Convert MS-LangID to BCP 47 string.
void convertBcp47ToLang()
OUString getGlibcLocaleString(std::u16string_view rEncoding) const
Get a GLIBC locale string.
OUString getBcp47MS() const
Obtain BCP 47 language tag, but with MS malformed exceptions.
PrivateUse
Enums to be used with isValidBcp47().
ScriptType getScriptType() const
Returns the script type for this language, UNKNOWN if not set.
ScriptType
ScriptType for a language.
bool equals(const LanguageTag &rLanguageTag) const
Test equality of two LanguageTag, possibly resolving system locale.
OUString getCountry() const
Get ISO 3166 country alpha code.
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
Convert Locale to MS-LangID.
bool isIsoODF() const
If language tag is a locale that can be expressed using only ISO 639 language codes and ISO 15924 scr...
ImplPtr registerImpl() const
::std::vector< OUString >::const_iterator getFallback(const ::std::vector< OUString > &rList, const OUString &rReference)
Search for an equal or at least for a similar locale in a list of possible ones.
static ScriptType getOnTheFlyScriptType(LanguageType nLang)
static LanguageType convertToLanguageTypeWithFallback(const OUString &rBcp47)
Convert BCP 47 string to MS-LangID with fallback, convenience method.
static bool isIsoCountry(const OUString &rRegion)
LanguageTag & reset(const OUString &rBcp47LanguageTag)
Reset with existing BCP 47 language tag string.
::std::vector< OUString > getFallbackStrings(bool bIncludeFullBcp47) const
Return a vector of fall-back strings.
void setScriptType(ScriptType st)
Sets the script type for this language.
std::shared_ptr< LanguageTagImpl > ImplPtr
OUString getVariants() const
Get BCP 47 variant subtags, of the IANA Language Subtag Registry.
void getIsoLanguageScriptCountry(OUString &rLanguage, OUString &rScript, OUString &rCountry) const
Obtain ISO strings for language, script and country.
bool operator==(const LanguageTag &rLanguageTag) const
Test equality of two LanguageTag.
static I18NLANGTAG_DLLPRIVATE css::lang::Locale convertLanguageToLocale(LanguageType nLang, bool bIgnoreOverride)
Convert a LanguageType to a Locale.
static I18NLANGTAG_DLLPRIVATE LanguageType convertLocaleToLanguage(const css::lang::Locale &rLocale)
Convert a Locale to a LanguageType with handling of an empty language name designating LANGUAGE_SYSTE...
static I18NLANGTAG_DLLPRIVATE css::lang::Locale lookupFallbackLocale(const css::lang::Locale &rLocale)
static I18NLANGTAG_DLLPRIVATE css::lang::Locale getOverride(const css::lang::Locale &rLocale)
Used by LanguageTag::canonicalize()
static I18NLANGTAG_DLLPRIVATE LanguageType convertIsoNamesToLanguage(const OUString &rLang, const OUString &rCountry, bool bSkipIsoTable)
Used by convertLocaleToLanguageImpl(Locale) and LanguageTagImpl::convertLocaleToLang()
static I18NLANGTAG_DLLPRIVATE void setConfiguredSystemLanguage(LanguageType nLang)
Configured system locale needs always be synchronized with LanguageTag's system locale.
static LanguageType getPrimaryLanguage(LanguageType nLangID)
Get the primary language of a LangID.
static ::std::vector< LanguagetagMapping > getDefinedLanguagetags()
static LanguageType getSubLanguage(LanguageType nLangID)
Get the sublanguage of a LangID.
static LanguageType convertUnxByteStringToLanguage(std::string_view rString)
static LanguageType getRealLanguage(LanguageType nLang)
: A proper language/locale if the nLang parameter designates some special value.
static LanguageType makeLangID(LanguageType nSubLangId, LanguageType nPriLangId)
Create a LangID from a primary and a sublanguage.
o3tl::strong_int< sal_uInt16, struct LanguageTypeTag > LanguageType
These are MS LANGIDs, the lower 10 bits (mask 0x03ff, values below 0x0400 aren't real locale IDs) rep...
#define LANGUAGE_USER_KURDISH_TURKEY
#define LANGUAGE_ARMENIAN
#define LANGUAGE_SANSKRIT
#define LANGUAGE_UIGHUR_CHINA
#define LANGUAGE_KINYARWANDA_RWANDA
#define LANGUAGE_ARABIC_PRIMARY_ONLY
#define LANGUAGE_QUECHUA_BOLIVIA
#define LANGUAGE_MALAY_MALAYSIA
#define LANGUAGE_LITHUANIAN
#define LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA
#define LANGUAGE_ROMANIAN
#define LANGUAGE_CHINESE_TRADITIONAL
#define LANGUAGE_PORTUGUESE
#define LANGUAGE_GAELIC_IRELAND
#define LANGUAGE_HUNGARIAN
#define LANGUAGE_BELARUSIAN
#define LANGUAGE_AZERI_CYRILLIC
#define LANGUAGE_MACEDONIAN
#define LANGUAGE_SERBIAN_CYRILLIC_SERBIA
#define LANGUAGE_SAMI_NORTHERN_NORWAY
#define LANGUAGE_DZONGKHA_BHUTAN
#define LANGUAGE_USER_MALAY_ARABIC_MALAYSIA
#define LANGUAGE_KALAALLISUT_GREENLAND
#define LANGUAGE_GALICIAN
#define LANGUAGE_ON_THE_FLY_SUB_START
#define LANGUAGE_GUARANI_PARAGUAY
#define LANGUAGE_ICELANDIC
#define LANGUAGE_CHINESE_SIMPLIFIED
#define LANGUAGE_JAPANESE
#define LANGUAGE_SINHALESE_SRI_LANKA
#define LANGUAGE_USER_NYANJA
#define LANGUAGE_GAELIC_SCOTLAND
#define LANGUAGE_FAEROESE
#define LANGUAGE_UZBEK_CYRILLIC
#define LANGUAGE_USER_TAGALOG
#define LANGUAGE_ALBANIAN
#define LANGUAGE_BRETON_FRANCE
#define LANGUAGE_INUKTITUT_LATIN_CANADA
#define LANGUAGE_ROMANIAN_MOLDOVA
#define LANGUAGE_ASSAMESE
#define LANGUAGE_UKRAINIAN
#define LANGUAGE_USER_MANX
#define LANGUAGE_SPANISH_DATED
#define LANGUAGE_VIETNAMESE
#define LANGUAGE_DONTKNOW
#define LANGUAGE_USER_ANCIENT_GREEK
#define LANGUAGE_AFRIKAANS
#define LANGUAGE_NORWEGIAN
#define LANGUAGE_ON_THE_FLY_START
#define LANGUAGE_AZERI_LATIN
#define LANGUAGE_CROATIAN
#define LANGUAGE_MALAYALAM
#define LANGUAGE_GEORGIAN
#define LANGUAGE_BULGARIAN
#define LANGUAGE_URDU_PAKISTAN
#define LANGUAGE_KASHMIRI
#define LANGUAGE_AMHARIC_ETHIOPIA
#define LANGUAGE_DUTCH_BELGIAN
#define LANGUAGE_ESTONIAN
#define LANGUAGE_GUJARATI
#define LANGUAGE_SLOVENIAN
#define LANGUAGE_MALAGASY_PLATEAU
#define LANGUAGE_USER_ESPERANTO
#define LANGUAGE_MONGOLIAN_CYRILLIC_MONGOLIA
#define LANGUAGE_ENGLISH_US
#define LANGUAGE_TIGRIGNA_ETHIOPIA
#define LANGUAGE_ON_THE_FLY_SUB_END
#define LANGUAGE_INDONESIAN
#define LANGUAGE_ON_THE_FLY_END
LanguageTag makeLanguageTagFromAppleLanguageId(AppleLanguageId nLanguage)
Init LanguageTag with Apple LanguageId.
static bool lcl_isSystem(LanguageType nLangID)
static bool lcl_isKnownOnTheFlyID(LanguageType nLang)
static void handleVendorVariant(css::lang::Locale &rLocale)
static bool lt_tag_parse_disabled
std::unordered_set< OUString > KnownTagSet
static LanguageType getNextOnTheFlyLanguage()
static const KnownTagSet & getKnowns()
#define I18NLANGTAG_QLT_ASCII
The ISO 639-2 code reserved for local use used to indicate that a css::Locale contains a BCP 47 strin...
constexpr OUStringLiteral I18NLANGTAG_QLT
#define SAL_INFO_IF(condition, area, stream)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
constexpr OUStringLiteral aData
int compareToIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)