i18nlangtag/qa/cppunit/test_languagetag.cxx | 22 +- i18nlangtag/source/isolang/mslangid.cxx | 6 i18nlangtag/source/languagetag/languagetag.cxx | 242 +++++++++++++++++++++---- include/i18nlangtag/languagetag.hxx | 3 include/i18nlangtag/mslangid.hxx | 1 5 files changed, 228 insertions(+), 46 deletions(-)
New commits: commit f77085ce584b1400d4d245582fa3e214143e9c09 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 18:05:46 2013 +0200 theDontKnow Impl Change-Id: I6d4738041e3f4eaffc3adbdb0b324eda24903b72 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 3d2fc8a..01cd6d2 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -94,6 +94,7 @@ typedef ::std::map< OUString, LanguageTag::ImplPtr, compareIgnoreAsciiCaseLess > typedef ::std::map< LanguageType, LanguageTag::ImplPtr > MapLangID; struct theMapBcp47 : public rtl::Static< MapBcp47, theMapBcp47 > {}; struct theMapLangID : public rtl::Static< MapLangID, theMapLangID > {}; +struct theDontKnow : public rtl::Static< LanguageTag::ImplPtr, theDontKnow > {}; } @@ -787,6 +788,16 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const } } } + else if (mbInitializedLangID && mnLangID == LANGUAGE_DONTKNOW) + { + // Heavy usage of LANGUAGE_DONTKNOW, make it an own Impl for all the + // conversion attempts. At the same time provide a central breakpoint + // to inspect such places. + LanguageTag::ImplPtr& rDontKnow = theDontKnow::get(); + if (!rDontKnow) + rDontKnow.reset( new LanguageTagImpl( *this)); + pImpl = rDontKnow; + } else { SAL_WARN( "i18nlangtag", "LanguageTag::registerImpl: can't register for 0x" << ::std::hex << mnLangID ); commit ababc9bba77784754b7c903d24f08b1869c584ef Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 17:32:27 2013 +0200 0x Change-Id: Ie400046c513b278115ec6fc67b3c531a1153ef9e diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index bf835195..3d2fc8a 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -789,7 +789,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const } else { - SAL_WARN( "i18nlangtag", "LanguageTag::registerImpl: can't register for " << ::std::hex << mnLangID ); + SAL_WARN( "i18nlangtag", "LanguageTag::registerImpl: can't register for 0x" << ::std::hex << mnLangID ); pImpl.reset( new LanguageTagImpl( *this)); } return pImpl; commit 79dbf611175e8a91557e288feb463f78fa1a06b9 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 17:27:20 2013 +0200 do not register LANGUAGE_DONTKNOW Change-Id: Ibfe4407c1b2740e806c7d9cb75529a8babc3fd92 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 91de5fd..bf835195 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -676,7 +676,8 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const #endif // Prefer LangID map as find+insert needs less comparison work. - if (mbInitializedLangID) + // Never insert LANGUAGE_DONTKNOW + if (mbInitializedLangID && mnLangID != LANGUAGE_DONTKNOW) { MapLangID& rMap = theMapLangID::get(); MapLangID::const_iterator it( rMap.find( mnLangID)); @@ -753,10 +754,13 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const OUString aBcp47; if (!bInsert) { - // May have involved canonicalize(), so compare with pImpl->maBcp47! - aBcp47 = LanguageTagImpl::convertToBcp47( + if (pImpl->mnLangID != LANGUAGE_DONTKNOW) + { + // May have involved canonicalize(), so compare with pImpl->maBcp47! + aBcp47 = LanguageTagImpl::convertToBcp47( MsLangId::Conversion::convertLanguageToLocale( pImpl->mnLangID, true)); - bInsert = (aBcp47 == pImpl->maBcp47); + bInsert = (aBcp47 == pImpl->maBcp47); + } } // If round-trip is identical cross-insert to Bcp47 map. if (bInsert) commit c640f19ca3aa1d918bd8df454d5ec45fbc2fad05 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 16:41:59 2013 +0200 now with on-the-fly LangID assignment Change-Id: I0766705191176381beaf331de3d10dfc0086a9b4 diff --git a/i18nlangtag/qa/cppunit/test_languagetag.cxx b/i18nlangtag/qa/cppunit/test_languagetag.cxx index 945fc74..91ef1ef 100644 --- a/i18nlangtag/qa/cppunit/test_languagetag.cxx +++ b/i18nlangtag/qa/cppunit/test_languagetag.cxx @@ -74,7 +74,7 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "qlt" ); CPPUNIT_ASSERT( aLocale.Country == "DE" ); CPPUNIT_ASSERT( aLocale.Variant == "de-Latn-DE" ); - CPPUNIT_ASSERT( nLanguageType == LANGUAGE_SYSTEM ); // XXX not resolved! + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( nLanguageType) ); // XXX not canonicalized! CPPUNIT_ASSERT( de_DE.getLanguage() == "de" ); CPPUNIT_ASSERT( de_DE.getCountry() == "DE" ); CPPUNIT_ASSERT( de_DE.getScript() == "Latn" ); @@ -92,19 +92,25 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "tlh" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == "" ); - CPPUNIT_ASSERT( klingon.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( klingon.getLanguageType()) ); CPPUNIT_ASSERT( klingon.isValidBcp47() == true ); CPPUNIT_ASSERT( klingon.isIsoLocale() == true ); CPPUNIT_ASSERT( klingon.isIsoODF() == true ); + LanguageType nLang = klingon.getLanguageType(); + LanguageTag klingon_id( nLang); + CPPUNIT_ASSERT( klingon_id.getBcp47() == "tlh" ); #else CPPUNIT_ASSERT( klingon.getBcp47() == s_klingon ); CPPUNIT_ASSERT( aLocale.Language == "qlt" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == s_klingon ); - CPPUNIT_ASSERT( klingon.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( klingon.getLanguageType()) ); CPPUNIT_ASSERT( klingon.isValidBcp47() == true ); CPPUNIT_ASSERT( klingon.isIsoLocale() == false ); CPPUNIT_ASSERT( klingon.isIsoODF() == false ); + LanguageType nLang = klingon.getLanguageType(); + LanguageTag klingon_id( nLang); + CPPUNIT_ASSERT( klingon_id.getBcp47() == s_klingon ); #endif } @@ -232,7 +238,7 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "qlt" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == s_ca_valencia ); - CPPUNIT_ASSERT( ca_valencia.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( ca_valencia.getLanguageType()) ); CPPUNIT_ASSERT( ca_valencia.isValidBcp47() == true ); CPPUNIT_ASSERT( ca_valencia.isIsoLocale() == false ); CPPUNIT_ASSERT( ca_valencia.isIsoODF() == false ); @@ -328,7 +334,7 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "qlt" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == s_de_1901 ); - CPPUNIT_ASSERT( de_1901.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( de_1901.getLanguageType()) ); CPPUNIT_ASSERT( de_1901.isValidBcp47() == true ); CPPUNIT_ASSERT( de_1901.isIsoLocale() == false ); CPPUNIT_ASSERT( de_1901.isIsoODF() == false ); @@ -385,7 +391,7 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "qty" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == "" ); - CPPUNIT_ASSERT( qty.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( qty.getLanguageType()) ); } // 'x-comment' is a privateuse known "locale" @@ -409,7 +415,7 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "qlt" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == "x-foobar" ); - CPPUNIT_ASSERT( xfoobar.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( xfoobar.getLanguageType()) ); } // '*' the dreaded jolly joker is a "privateuse" known "locale" @@ -470,7 +476,7 @@ void TestLanguageTag::testAllTags() CPPUNIT_ASSERT( aLocale.Language == "qlt" ); CPPUNIT_ASSERT( aLocale.Country == "" ); CPPUNIT_ASSERT( aLocale.Variant == s_uab ); - CPPUNIT_ASSERT( uab.getLanguageType() == LANGUAGE_SYSTEM ); + CPPUNIT_ASSERT( uab.getLanguageType() == LANGUAGE_DONTKNOW ); CPPUNIT_ASSERT( uab.isValidBcp47() == false ); CPPUNIT_ASSERT( uab.isIsoLocale() == false ); CPPUNIT_ASSERT( uab.isIsoODF() == false ); diff --git a/i18nlangtag/source/isolang/mslangid.cxx b/i18nlangtag/source/isolang/mslangid.cxx index 0b0253f..f547c34 100644 --- a/i18nlangtag/source/isolang/mslangid.cxx +++ b/i18nlangtag/source/isolang/mslangid.cxx @@ -177,11 +177,7 @@ LanguageType MsLangId::Conversion::convertLocaleToLanguage( if (rLocale.Language.isEmpty()) return LANGUAGE_SYSTEM; - LanguageType nRet = convertLocaleToLanguageImpl( rLocale); - if (nRet == LANGUAGE_DONTKNOW) - nRet = LANGUAGE_SYSTEM; - - return nRet; + return convertLocaleToLanguageImpl( rLocale); } diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index e960ea9..91de5fd 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -740,7 +740,9 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const if (pImpl->synCanonicalize()) { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: canonicalized to '" << pImpl->maBcp47 << "'"); - rMap.insert( ::std::make_pair( pImpl->maBcp47, pImpl)); + bool bInserted = rMap.insert( ::std::make_pair( pImpl->maBcp47, pImpl)).second; + SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: " << (bInserted ? "" : "not ") << "inserted '" + << pImpl->maBcp47 << "'"); } // Try round-trip Bcp47->Locale->LangID->Locale->Bcp47. if (!pImpl->mbInitializedLocale) @@ -1122,7 +1124,16 @@ void LanguageTagImpl::convertLocaleToLang( bool bAllowOnTheFlyID ) else { mnLangID = MsLangId::Conversion::convertLocaleToLanguage( maLocale); - (void)bAllowOnTheFlyID; + if (mnLangID == LANGUAGE_DONTKNOW && bAllowOnTheFlyID) + { + if (isValidBcp47()) + registerOnTheFly(); + else + { + SAL_WARN( "i18nlangtag", "LanguageTagImpl::convertLocaleToLang: with bAllowOnTheFlyID invalid '" + << maBcp47 << "'"); + } + } } mbInitializedLangID = true; } commit 75cb1e8541f1fb377fd4504ef5fd6ffea6bee7a1 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 15:45:50 2013 +0200 more preparation for on-the-fli IDs Change-Id: Ic4d53d0e3e8e149d09017dd7a567b879601073fc diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index ee4a142..e960ea9 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -277,7 +277,7 @@ private: bool isValidBcp47() const; void convertLocaleToBcp47(); - void convertLocaleToLang(); + void convertLocaleToLang( bool bAllowOnTheFlyID ); void convertBcp47ToLocale(); void convertBcp47ToLang(); void convertLangToLocale(); @@ -736,17 +736,28 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: new impl for '" << maBcp47 << "'"); pImpl.reset( new LanguageTagImpl( *this)); rMap.insert( ::std::make_pair( maBcp47, pImpl)); + // If changed after canonicalize() also add the resulting tag to map. + if (pImpl->synCanonicalize()) + { + SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: canonicalized to '" << pImpl->maBcp47 << "'"); + rMap.insert( ::std::make_pair( pImpl->maBcp47, pImpl)); + } // Try round-trip Bcp47->Locale->LangID->Locale->Bcp47. if (!pImpl->mbInitializedLocale) pImpl->convertBcp47ToLocale(); if (!pImpl->mbInitializedLangID) - pImpl->convertLocaleToLang(); - OUString aBcp47( LanguageTagImpl::convertToBcp47( - MsLangId::Conversion::convertLanguageToLocale( pImpl->mnLangID, true))); + pImpl->convertLocaleToLang( true); + bool bInsert = LanguageTag::isOnTheFlyID( pImpl->mnLangID); + OUString aBcp47; + if (!bInsert) + { + // May have involved canonicalize(), so compare with pImpl->maBcp47! + aBcp47 = LanguageTagImpl::convertToBcp47( + MsLangId::Conversion::convertLanguageToLocale( pImpl->mnLangID, true)); + bInsert = (aBcp47 == pImpl->maBcp47); + } // If round-trip is identical cross-insert to Bcp47 map. - // May have involved canonicalize(), so compare with - // pImpl->maBcp47! - if (aBcp47 == pImpl->maBcp47) + if (bInsert) { ::std::pair< MapLangID::const_iterator, bool > res( theMapLangID::get().insert( ::std::make_pair( pImpl->mnLangID, pImpl))); @@ -940,7 +951,7 @@ bool LanguageTagImpl::canonicalize() { if (!mbInitializedLangID) { - convertLocaleToLang(); + convertLocaleToLang( false); if (bTemporaryLocale) bTemporaryLangID = true; } @@ -1102,7 +1113,7 @@ void LanguageTag::convertLocaleToBcp47() } -void LanguageTagImpl::convertLocaleToLang() +void LanguageTagImpl::convertLocaleToLang( bool bAllowOnTheFlyID ) { if (mbSystemLocale) { @@ -1111,6 +1122,7 @@ void LanguageTagImpl::convertLocaleToLang() else { mnLangID = MsLangId::Conversion::convertLocaleToLanguage( maLocale); + (void)bAllowOnTheFlyID; } mbInitializedLangID = true; } @@ -1118,7 +1130,7 @@ void LanguageTagImpl::convertLocaleToLang() void LanguageTag::convertLocaleToLang() { - getImpl()->convertLocaleToLang(); + getImpl()->convertLocaleToLang( true); syncFromImpl(); } @@ -1159,7 +1171,7 @@ void LanguageTagImpl::convertBcp47ToLang() { if (!mbInitializedLocale) convertBcp47ToLocale(); - convertLocaleToLang(); + convertLocaleToLang( true); } mbInitializedLangID = true; } commit 01bde208acc429a0c65fdf6e65415ebea72e9ddc Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 15:39:06 2013 +0200 added isOnTheFlyID() Change-Id: Ifddbec485814e3287e671e6bc4059689ca3f6c93 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 7d03597..ee4a142 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -126,6 +126,17 @@ static LanguageType getNextOnTheFlyLanguage() } +// static +bool LanguageTag::isOnTheFlyID( LanguageType nLang ) +{ + LanguageType nPri = MsLangId::getPrimaryLanguage( nLang); + LanguageType nSub = MsLangId::getSubLanguage( nLang); + return + LANGUAGE_ON_THE_FLY_START <= nPri && nPri <= LANGUAGE_ON_THE_FLY_END && + LANGUAGE_ON_THE_FLY_SUB_START <= nSub && nSub <= LANGUAGE_ON_THE_FLY_SUB_END; +} + + /** A reference holder for liblangtag data de/initialization, one static instance. Currently implemented such that the first "ref" inits and dtor (our library deinitialized) tears down. diff --git a/include/i18nlangtag/languagetag.hxx b/include/i18nlangtag/languagetag.hxx index 50cfef5..27bcb34 100644 --- a/include/i18nlangtag/languagetag.hxx +++ b/include/i18nlangtag/languagetag.hxx @@ -484,6 +484,9 @@ public: */ static com::sun::star::lang::Locale convertToLocaleWithFallback( const OUString& rBcp47 ); + /** If nLang is a generated on-the-fly LangID */ + static bool isOnTheFlyID( LanguageType nLang ); + typedef ::boost::shared_ptr< LanguageTagImpl > ImplPtr; private: commit e81359a9a3240187bf3a02fdb48b8709238bdc51 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 14:47:27 2013 +0200 added registerImpl() re-entered warning Change-Id: I064d7241343fadd0256bb0fa5ad32fabcd6738a4 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 98dd2a5..7d03597 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -654,6 +654,16 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const osl::MutexGuard aGuard( theMutex::get()); +#if OSL_DEBUG_LEVEL > 0 + static long nRunning = 0; + // Entering twice here is ok, which is needed for fallback init in + // getKnowns() in canonicalize() via pImpl->convertBcp47ToLocale() below, + // everything else is suspicious. + SAL_WARN_IF( nRunning > 1, "i18nlangtag", "LanguageTag::registerImpl: re-entered for '" + << maBcp47 << "' 0x" << ::std::hex << mnLangID ); + struct Runner { Runner() { ++nRunning; } ~Runner() { --nRunning; } } aRunner; +#endif + // Prefer LangID map as find+insert needs less comparison work. if (mbInitializedLangID) { commit 5ec8a9b13a5805d641555fa35057965f6f45a420 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 14:07:47 2013 +0200 added registerOnTheFly() Change-Id: I1e270686ad73bf32c580dddcab7f03c4a3d85054 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index f1f05d8..98dd2a5 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -97,9 +97,6 @@ struct theMapLangID : public rtl::Static< MapLangID, theMapLangID > {}; } -/* TODO: this is how on-the-fly LangID assignment will work, now implement - * usage and registration. */ -#if 0 static LanguageType getNextOnTheFlyLanguage() { static LanguageType nOnTheFlyLanguage = 0; @@ -116,15 +113,17 @@ static LanguageType getNextOnTheFlyLanguage() if (nSub != LANGUAGE_ON_THE_FLY_SUB_END) nOnTheFlyLanguage = MsLangId::makeLangID( ++nSub, LANGUAGE_ON_THE_FLY_START); else + { SAL_WARN( "i18nlangtag", "getNextOnTheFlyLanguage: none left! (" << ((LANGUAGE_ON_THE_FLY_END - LANGUAGE_ON_THE_FLY_START + 1) * (LANGUAGE_ON_THE_FLY_SUB_END - LANGUAGE_ON_THE_FLY_SUB_START + 1)) << " consumed?!?)"); + return 0; + } } } return nOnTheFlyLanguage; } -#endif /** A reference holder for liblangtag data de/initialization, one static @@ -289,6 +288,12 @@ private: OUString getRegionFromLangtag(); OUString getVariantsFromLangtag(); + /** Generates on-the-fly LangID and registers the maBcp47,mnLangID pair. + + @return NULL if no ID could be obtained or registration failed. + */ + LanguageTag::ImplPtr registerOnTheFly(); + /** Obtain Language, Script, Country and Variants via simpleExtract() and assign them to the cached variables if successful. @@ -325,7 +330,7 @@ private: /** Convert Locale to BCP 47 string without resolving system and creating temporary LanguageTag instances. */ - static OUString convertToBcp47( const com::sun::star::lang::Locale& rLocale ); + static OUString convertToBcp47( const com::sun::star::lang::Locale& rLocale ); }; @@ -557,6 +562,72 @@ LanguageTag::~LanguageTag() } +LanguageTag::ImplPtr LanguageTagImpl::registerOnTheFly() +{ + LanguageTag::ImplPtr pImpl; + + if (!mbInitializedBcp47) + { + if (mbInitializedLocale) + { + maBcp47 = LanguageTagImpl::convertToBcp47( maLocale); + mbInitializedBcp47 = !maBcp47.isEmpty(); + } + } + if (maBcp47.isEmpty()) + { + SAL_WARN( "i18nlangtag", "LanguageTagImpl::registerOnTheFly: no Bcp47 string, no registering"); + return pImpl; + } + + LanguageType nLang = getNextOnTheFlyLanguage(); + if (!nLang) + { + // out of IDs, nothing to register + return pImpl; + } + mnLangID = nLang; + mbInitializedLangID = true; + + osl::MutexGuard aGuard( theMutex::get()); + + MapBcp47& rMap = theMapBcp47::get(); + MapBcp47::const_iterator it( rMap.find( maBcp47)); + if (it != rMap.end()) + { + SAL_INFO( "i18nlangtag", "LanguageTag::registerOnTheFly: found impl for '" << maBcp47 << "'"); + pImpl = (*it).second; + if (pImpl.get() != this) + { + SAL_WARN( "i18nlangtag", "LanguageTag::registerOnTheFly: impl should be this"); + *pImpl = *this; // ensure consistency + } + } + else + { + SAL_INFO( "i18nlangtag", "LanguageTag::registerOnTheFly: new impl for '" << maBcp47 << "'"); + pImpl.reset( new LanguageTagImpl( *this)); + rMap.insert( ::std::make_pair( maBcp47, pImpl)); + } + + ::std::pair< MapLangID::const_iterator, bool > res( + theMapLangID::get().insert( ::std::make_pair( pImpl->mnLangID, pImpl))); + if (res.second) + { + SAL_INFO( "i18nlangtag", "LanguageTag::registerOnTheFly: cross-inserted 0x" + << ::std::hex << pImpl->mnLangID << " for '" << maBcp47 << "'"); + } + else + { + SAL_WARN( "i18nlangtag", "LanguageTag::registerOnTheFly: not cross-inserted 0x" + << ::std::hex << pImpl->mnLangID << " for '" << maBcp47 << "' have '" + << (*res.first).second->maBcp47 << "'"); + } + + return pImpl; +} + + LanguageTag::ImplPtr LanguageTag::registerImpl() const { // XXX NOTE: Do not use non-static LanguageTag::convert...() member methods commit e3a01c2b0c00a502622f3b6f0be560cf32b3b774 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 13:36:33 2013 +0200 check for identity in operator=() Change-Id: I687dc4bdd3093054a6e2c1fd383cfc2a8c948303 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 3154639..f1f05d8 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -383,6 +383,9 @@ LanguageTagImpl::LanguageTagImpl( const LanguageTagImpl & rLanguageTagImpl ) LanguageTagImpl& LanguageTagImpl::operator=( const LanguageTagImpl & rLanguageTagImpl ) { + if (&rLanguageTagImpl == this) + return *this; + maLocale = rLanguageTagImpl.maLocale; maBcp47 = rLanguageTagImpl.maBcp47; maCachedLanguage = rLanguageTagImpl.maCachedLanguage; @@ -534,6 +537,9 @@ LanguageTag::LanguageTag( const LanguageTag & rLanguageTag ) LanguageTag& LanguageTag::operator=( const LanguageTag & rLanguageTag ) { + if (&rLanguageTag == this) + return *this; + maLocale = rLanguageTag.maLocale; maBcp47 = rLanguageTag.maBcp47; mnLangID = rLanguageTag.mnLangID; commit 862766d569e51d91c11139cc831fb083c8bbdd01 Author: Eike Rathke <er...@redhat.com> Date: Fri Sep 20 12:11:13 2013 +0200 prepare for on-the-fly assigned LangIDs Change-Id: Id4ba99f0b1894457ca95c209b8394447c6fd7893 diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 11cec0c..3154639 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -323,6 +323,10 @@ private: OUString& rCountry, OUString& rVariants ); + /** Convert Locale to BCP 47 string without resolving system and creating + temporary LanguageTag instances. */ + static OUString convertToBcp47( const com::sun::star::lang::Locale& rLocale ); + }; @@ -551,7 +555,9 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const { // XXX NOTE: Do not use non-static LanguageTag::convert...() member methods // here as they access getImpl() and syncFromImpl() and would lead to - // recursion. + // recursion. Also do not use the static LanguageTag::convertTo...() + // methods as they may create temporary LanguageTag instances. Only + // LanguageTagImpl::convertToBcp47(Locale) is ok. ImplPtr pImpl; @@ -565,8 +571,8 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const // Force Bcp47 if not LangID. if (!mbInitializedLangID && !mbInitializedBcp47 && mbInitializedLocale) { - maBcp47 = LanguageTag::convertToBcp47( maLocale, true); - mbInitializedBcp47 = true; + maBcp47 = LanguageTagImpl::convertToBcp47( maLocale); + mbInitializedBcp47 = !maBcp47.isEmpty(); } osl::MutexGuard aGuard( theMutex::get()); @@ -637,7 +643,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const pImpl->convertBcp47ToLocale(); if (!pImpl->mbInitializedLangID) pImpl->convertLocaleToLang(); - OUString aBcp47( LanguageTag::convertToBcp47( + OUString aBcp47( LanguageTagImpl::convertToBcp47( MsLangId::Conversion::convertLanguageToLocale( pImpl->mnLangID, true))); // If round-trip is identical cross-insert to Bcp47 map. // May have involved canonicalize(), so compare with @@ -966,7 +972,19 @@ void LanguageTagImpl::convertLocaleToBcp47() if (mbSystemLocale && !mbInitializedLocale) convertLangToLocale(); - if (maLocale.Language == I18NLANGTAG_QLT) + if (maLocale.Language.isEmpty()) + { + // Do not call LanguageTag::convertToBcp47(Locale) that for an empty + // locale via LanguageTag::convertToBcp47(LanguageType) and + // LanguageTag::convertToLocale(LanguageType) would instanciate another + // LanguageTag. + maLocale = MsLangId::Conversion::convertLanguageToLocale( LANGUAGE_SYSTEM, true); + } + if (maLocale.Language.isEmpty()) + { + maBcp47 = OUString(); // bad luck + } + else if (maLocale.Language == I18NLANGTAG_QLT) { maBcp47 = maLocale.Variant; meIsIsoLocale = DECISION_NO; @@ -994,7 +1012,7 @@ void LanguageTagImpl::convertLocaleToLang() } else { - mnLangID = LanguageTag::convertToLanguageType( maLocale, true); + mnLangID = MsLangId::Conversion::convertLocaleToLanguage( maLocale); } mbInitializedLangID = true; } @@ -1064,7 +1082,7 @@ void LanguageTagImpl::convertLangToLocale() mbInitializedLangID = true; } // Resolve system here! The original is remembered as mbSystemLocale. - maLocale = LanguageTag::convertToLocale( mnLangID, true); + maLocale = MsLangId::Conversion::convertLanguageToLocale( mnLangID, true); mbInitializedLocale = true; } @@ -2126,7 +2144,7 @@ com::sun::star::lang::Locale LanguageTag::convertToLocale( LanguageType nLangID, if (!bResolveSystem && lcl_isSystem( nLangID)) return lang::Locale(); - return MsLangId::Conversion::convertLanguageToLocale( nLangID, bResolveSystem); + return LanguageTag( nLangID).getLocale( bResolveSystem); } @@ -2136,19 +2154,17 @@ LanguageType LanguageTag::convertToLanguageType( const com::sun::star::lang::Loc if (rLocale.Language.isEmpty() && !bResolveSystem) return LANGUAGE_SYSTEM; - return MsLangId::Conversion::convertLocaleToLanguage( rLocale); + return LanguageTag( rLocale).getLanguageType( bResolveSystem); } // static -OUString LanguageTag::convertToBcp47( const com::sun::star::lang::Locale& rLocale, bool bResolveSystem ) +OUString LanguageTagImpl::convertToBcp47( const com::sun::star::lang::Locale& rLocale ) { OUString aBcp47; if (rLocale.Language.isEmpty()) { - if (bResolveSystem) - aBcp47 = convertToBcp47( LANGUAGE_SYSTEM, true); - // else aBcp47 stays empty + // aBcp47 stays empty } else if (rLocale.Language == I18NLANGTAG_QLT) { @@ -2171,25 +2187,46 @@ OUString LanguageTag::convertToBcp47( const com::sun::star::lang::Locale& rLocal // static +OUString LanguageTag::convertToBcp47( const com::sun::star::lang::Locale& rLocale, bool bResolveSystem ) +{ + OUString aBcp47; + if (rLocale.Language.isEmpty()) + { + if (bResolveSystem) + aBcp47 = LanguageTag::convertToBcp47( LANGUAGE_SYSTEM, true); + // else aBcp47 stays empty + } + else + { + aBcp47 = LanguageTagImpl::convertToBcp47( rLocale); + } + return aBcp47; +} + + +// static OUString LanguageTag::convertToBcp47( LanguageType nLangID, bool bResolveSystem ) { // Catch this first so we don't need the rest. if (!bResolveSystem && lcl_isSystem( nLangID)) return OUString(); - lang::Locale aLocale( convertToLocale( nLangID, bResolveSystem)); + lang::Locale aLocale( LanguageTag::convertToLocale( nLangID, bResolveSystem)); // If system for some reason (should not happen.. haha) could not be - // resolved DO NOT CALL convertToBcp47() because that would recurse into - // this method here! + // resolved DO NOT CALL LanguageTag::convertToBcp47(Locale) because that + // would recurse into this method here! if (aLocale.Language.isEmpty() && bResolveSystem) return OUString(); // bad luck, bail out - return convertToBcp47( aLocale, bResolveSystem); + return LanguageTagImpl::convertToBcp47( aLocale); } // static com::sun::star::lang::Locale LanguageTag::convertToLocale( const OUString& rBcp47, bool bResolveSystem ) { + if (rBcp47.isEmpty() && !bResolveSystem) + return lang::Locale(); + return LanguageTag( rBcp47).getLocale( bResolveSystem); } @@ -2197,6 +2234,9 @@ com::sun::star::lang::Locale LanguageTag::convertToLocale( const OUString& rBcp4 // static LanguageType LanguageTag::convertToLanguageType( const OUString& rBcp47, bool bResolveSystem ) { + if (rBcp47.isEmpty() && !bResolveSystem) + return LANGUAGE_SYSTEM; + return LanguageTag( rBcp47).getLanguageType( bResolveSystem); } diff --git a/include/i18nlangtag/mslangid.hxx b/include/i18nlangtag/mslangid.hxx index 95adb91..e0582d8 100644 --- a/include/i18nlangtag/mslangid.hxx +++ b/include/i18nlangtag/mslangid.hxx @@ -200,6 +200,7 @@ public: private: friend class LanguageTag; + friend class LanguageTagImpl; friend ::com::sun::star::lang::Locale MsLangId::getFallbackLocale( const ::com::sun::star::lang::Locale & rLocale ); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits