diff options
author | Eike Rathke <erack@redhat.com> | 2013-09-18 22:39:23 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2013-09-18 22:40:58 +0200 |
commit | 31db11d7efba6f9ee77e9c1cd1f0e82ce9e8feee (patch) | |
tree | bc29f1355c551f37507cf49bd000093e1565362e | |
parent | ecaadbf78794174c5f744b4982546901cb7fe8e8 (diff) |
changed to mpImpl
first step to register locales
Change-Id: I1a1f7b3f642cf892e91b17dd30c92a79129f184e
-rw-r--r-- | i18nlangtag/source/languagetag/languagetag.cxx | 628 | ||||
-rw-r--r-- | include/i18nlangtag/languagetag.hxx | 114 |
2 files changed, 497 insertions, 245 deletions
diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 93f9823f19a0..dde0a2e0541e 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -201,47 +201,276 @@ void LiblantagDataRef::setupDataPath() lt_db_set_datadir( maDataPath.getStr()); } -LanguageTag::LanguageTag( const OUString & rBcp47LanguageTag, bool bCanonicalize ) + +class LanguageTagImpl +{ +public: + + explicit LanguageTagImpl( const LanguageTag & rLanguageTag ); + explicit LanguageTagImpl( const LanguageTagImpl & rLanguageTagImpl ); + ~LanguageTagImpl(); + LanguageTagImpl& operator=( const LanguageTagImpl & rLanguageTagImpl ); + +private: + + friend class LanguageTag; + + enum Decision + { + DECISION_DONTKNOW, + DECISION_NO, + DECISION_YES + }; + + mutable com::sun::star::lang::Locale maLocale; + mutable OUString maBcp47; + mutable OUString maCachedLanguage; ///< cache getLanguage() + mutable OUString maCachedScript; ///< cache getScript() + mutable OUString maCachedCountry; ///< cache getCountry() + mutable OUString maCachedVariants; ///< cache getVariants() + mutable void* mpImplLangtag; ///< actually lt_tag_t pointer, encapsulated + mutable LanguageType mnLangID; + mutable Decision meIsValid; + mutable Decision meIsIsoLocale; + mutable Decision meIsIsoODF; + mutable Decision meIsLiblangtagNeeded; ///< whether processing with liblangtag needed + bool mbSystemLocale : 1; + mutable bool mbInitializedBcp47 : 1; + mutable bool mbInitializedLocale : 1; + mutable bool mbInitializedLangID : 1; + mutable bool mbCachedLanguage : 1; + mutable bool mbCachedScript : 1; + mutable bool mbCachedCountry : 1; + mutable bool mbCachedVariants : 1; + + const OUString & getBcp47( bool bResolveSystem = true ) const; + OUString getLanguage() const; + OUString getScript() const; + OUString getCountry() const; + OUString getRegion() const; + OUString getVariants() const; + bool hasScript() const; + + bool isIsoLocale() const; + bool isIsoODF() const; + bool isValidBcp47() const; + + void convertLocaleToBcp47(); + void convertLocaleToLang(); + void convertBcp47ToLocale(); + void convertBcp47ToLang(); + void convertLangToLocale(); + void convertLangToBcp47(); + + void convertFromRtlLocale(); + + /** @return whether BCP 47 language tag string was changed. */ + bool canonicalize(); + + /** Canonicalize if not yet done and synchronize initialized conversions. + + @return whether BCP 47 language tag string was changed. + */ + bool synCanonicalize(); + + OUString getLanguageFromLangtag(); + OUString getScriptFromLangtag(); + OUString getRegionFromLangtag(); + OUString getVariantsFromLangtag(); + + void resetVars(); + + /** Obtain Language, Script, Country and Variants via simpleExtract() and + assign them to the cached variables if successful. + + @return return of simpleExtract() + */ + bool cacheSimpleLSCV(); + + enum Extraction + { + EXTRACTED_NONE, + EXTRACTED_LSC, + EXTRACTED_LV, + EXTRACTED_X, + EXTRACTED_X_JOKER + }; + + /** Of a language tag of the form lll[-Ssss][-CC][-vvvvvvvv] extract the + portions. + + Does not check case or content! + + @return EXTRACTED_LSC if simple tag was detected (i.e. one that + would fulfill the isIsoODF() condition), + EXTRACTED_LV if a tag with variant was detected, + EXTRACTED_X if x-... privateuse tag was detected, + EXTRACTED_X_JOKER if "*" joker was detected, + EXTRACTED_NONE else. + */ + static Extraction simpleExtract( const OUString& rBcp47, + OUString& rLanguage, + OUString& rScript, + OUString& rCountry, + OUString& rVariants ); + +}; + + +LanguageTagImpl::LanguageTagImpl( const LanguageTag & rLanguageTag ) : - maBcp47( rBcp47LanguageTag), + maLocale( rLanguageTag.maLocale), + maBcp47( rLanguageTag.maBcp47), mpImplLangtag( NULL), - mnLangID( LANGUAGE_DONTKNOW), + mnLangID( rLanguageTag.mnLangID), meIsValid( DECISION_DONTKNOW), meIsIsoLocale( DECISION_DONTKNOW), meIsIsoODF( DECISION_DONTKNOW), meIsLiblangtagNeeded( DECISION_DONTKNOW), + mbSystemLocale( rLanguageTag.mbSystemLocale), + mbInitializedBcp47( rLanguageTag.mbInitializedBcp47), + mbInitializedLocale( rLanguageTag.mbInitializedLocale), + mbInitializedLangID( rLanguageTag.mbInitializedLangID), + mbCachedLanguage( false), + mbCachedScript( false), + mbCachedCountry( false), + mbCachedVariants( false) +{ +} + + +LanguageTagImpl::LanguageTagImpl( const LanguageTagImpl & rLanguageTagImpl ) + : + maLocale( rLanguageTagImpl.maLocale), + maBcp47( rLanguageTagImpl.maBcp47), + maCachedLanguage( rLanguageTagImpl.maCachedLanguage), + maCachedScript( rLanguageTagImpl.maCachedScript), + maCachedCountry( rLanguageTagImpl.maCachedCountry), + maCachedVariants( rLanguageTagImpl.maCachedVariants), + mpImplLangtag( rLanguageTagImpl.mpImplLangtag ? + lt_tag_copy( LANGTAGCAST( rLanguageTagImpl.mpImplLangtag)) : NULL), + mnLangID( rLanguageTagImpl.mnLangID), + meIsValid( rLanguageTagImpl.meIsValid), + meIsIsoLocale( rLanguageTagImpl.meIsIsoLocale), + meIsIsoODF( rLanguageTagImpl.meIsIsoODF), + meIsLiblangtagNeeded( rLanguageTagImpl.meIsLiblangtagNeeded), + mbSystemLocale( rLanguageTagImpl.mbSystemLocale), + mbInitializedBcp47( rLanguageTagImpl.mbInitializedBcp47), + mbInitializedLocale( rLanguageTagImpl.mbInitializedLocale), + mbInitializedLangID( rLanguageTagImpl.mbInitializedLangID), + mbCachedLanguage( rLanguageTagImpl.mbCachedLanguage), + mbCachedScript( rLanguageTagImpl.mbCachedScript), + mbCachedCountry( rLanguageTagImpl.mbCachedCountry), + mbCachedVariants( rLanguageTagImpl.mbCachedVariants) +{ + if (mpImplLangtag) + theDataRef::get().incRef(); +} + + +LanguageTagImpl& LanguageTagImpl::operator=( const LanguageTagImpl & rLanguageTagImpl ) +{ + maLocale = rLanguageTagImpl.maLocale; + maBcp47 = rLanguageTagImpl.maBcp47; + maCachedLanguage = rLanguageTagImpl.maCachedLanguage; + maCachedScript = rLanguageTagImpl.maCachedScript; + maCachedCountry = rLanguageTagImpl.maCachedCountry; + maCachedVariants = rLanguageTagImpl.maCachedVariants; + mpImplLangtag = rLanguageTagImpl.mpImplLangtag; + mpImplLangtag = rLanguageTagImpl.mpImplLangtag ? + lt_tag_copy( LANGTAGCAST( rLanguageTagImpl.mpImplLangtag)) : NULL; + mnLangID = rLanguageTagImpl.mnLangID; + meIsValid = rLanguageTagImpl.meIsValid; + meIsIsoLocale = rLanguageTagImpl.meIsIsoLocale; + meIsIsoODF = rLanguageTagImpl.meIsIsoODF; + meIsLiblangtagNeeded= rLanguageTagImpl.meIsLiblangtagNeeded; + mbSystemLocale = rLanguageTagImpl.mbSystemLocale; + mbInitializedBcp47 = rLanguageTagImpl.mbInitializedBcp47; + mbInitializedLocale = rLanguageTagImpl.mbInitializedLocale; + mbInitializedLangID = rLanguageTagImpl.mbInitializedLangID; + mbCachedLanguage = rLanguageTagImpl.mbCachedLanguage; + mbCachedScript = rLanguageTagImpl.mbCachedScript; + mbCachedCountry = rLanguageTagImpl.mbCachedCountry; + mbCachedVariants = rLanguageTagImpl.mbCachedVariants; + if (mpImplLangtag) + theDataRef::get().incRef(); + return *this; +} + + +LanguageTagImpl::~LanguageTagImpl() +{ + if (mpImplLangtag) + { + lt_tag_unref( MPLANGTAG); + theDataRef::get().decRef(); + } +} + + +void LanguageTagImpl::resetVars() +{ + if (mpImplLangtag) + { + lt_tag_unref( MPLANGTAG); + mpImplLangtag = NULL; + theDataRef::get().decRef(); + } + + maLocale = lang::Locale(); + if (!maBcp47.isEmpty()) + maBcp47 = OUString(); + if (!maCachedLanguage.isEmpty()) + maCachedLanguage= OUString(); + if (!maCachedScript.isEmpty()) + maCachedScript = OUString(); + if (!maCachedCountry.isEmpty()) + maCachedCountry = OUString(); + if (!maCachedVariants.isEmpty()) + maCachedVariants = OUString(); + mnLangID = LANGUAGE_DONTKNOW; + meIsValid = DECISION_DONTKNOW; + meIsIsoLocale = DECISION_DONTKNOW; + meIsIsoODF = DECISION_DONTKNOW; + meIsLiblangtagNeeded= DECISION_DONTKNOW; + mbSystemLocale = true; + mbInitializedBcp47 = false; + mbInitializedLocale = false; + mbInitializedLangID = false; + mbCachedLanguage = false; + mbCachedScript = false; + mbCachedCountry = false; + mbCachedVariants = false; +} + + +LanguageTag::LanguageTag( const OUString & rBcp47LanguageTag, bool bCanonicalize ) + : + maBcp47( rBcp47LanguageTag), + mnLangID( LANGUAGE_DONTKNOW), mbSystemLocale( rBcp47LanguageTag.isEmpty()), mbInitializedBcp47( !mbSystemLocale), mbInitializedLocale( false), mbInitializedLangID( false), - mbCachedLanguage( false), - mbCachedScript( false), - mbCachedCountry( false), - mbCachedVariants( false), mbIsFallback( false) { if (bCanonicalize) - canonicalize(); + { + if (getImpl()->canonicalize()) + syncFromImpl(); + } + } LanguageTag::LanguageTag( const com::sun::star::lang::Locale & rLocale ) : maLocale( rLocale), - mpImplLangtag( NULL), mnLangID( LANGUAGE_DONTKNOW), - meIsValid( DECISION_DONTKNOW), - meIsIsoLocale( DECISION_DONTKNOW), - meIsIsoODF( DECISION_DONTKNOW), - meIsLiblangtagNeeded( DECISION_DONTKNOW), mbSystemLocale( rLocale.Language.isEmpty()), mbInitializedBcp47( false), mbInitializedLocale( !mbSystemLocale), mbInitializedLangID( false), - mbCachedLanguage( false), - mbCachedScript( false), - mbCachedCountry( false), - mbCachedVariants( false), mbIsFallback( false) { } @@ -249,20 +478,11 @@ LanguageTag::LanguageTag( const com::sun::star::lang::Locale & rLocale ) LanguageTag::LanguageTag( LanguageType nLanguage ) : - mpImplLangtag( NULL), mnLangID( nLanguage), - meIsValid( DECISION_DONTKNOW), - meIsIsoLocale( DECISION_DONTKNOW), - meIsIsoODF( DECISION_DONTKNOW), - meIsLiblangtagNeeded( DECISION_DONTKNOW), mbSystemLocale( nLanguage == LANGUAGE_SYSTEM), mbInitializedBcp47( false), mbInitializedLocale( false), mbInitializedLangID( !mbSystemLocale), - mbCachedLanguage( false), - mbCachedScript( false), - mbCachedCountry( false), - mbCachedVariants( false), mbIsFallback( false) { } @@ -272,27 +492,21 @@ LanguageTag::LanguageTag( const OUString& rBcp47, const OUString& rLanguage, const OUString& rScript, const OUString& rCountry ) : maBcp47( rBcp47), - mpImplLangtag( NULL), mnLangID( LANGUAGE_DONTKNOW), - meIsValid( DECISION_DONTKNOW), - meIsIsoLocale( DECISION_DONTKNOW), - meIsIsoODF( DECISION_DONTKNOW), - meIsLiblangtagNeeded( DECISION_DONTKNOW), mbSystemLocale( rBcp47.isEmpty() && rLanguage.isEmpty()), mbInitializedBcp47( !rBcp47.isEmpty()), mbInitializedLocale( false), mbInitializedLangID( false), - mbCachedLanguage( false), - mbCachedScript( false), - mbCachedCountry( false), - mbCachedVariants( false), mbIsFallback( false) { if (!mbSystemLocale && !mbInitializedBcp47) { if (rScript.isEmpty()) { - maLocale = lang::Locale( rLanguage, rCountry, ""); + maBcp47 = rLanguage + "-" + rCountry; + mbInitializedBcp47 = true; + maLocale.Language = rLanguage; + maLocale.Country = rCountry; mbInitializedLocale = true; } else @@ -302,6 +516,10 @@ LanguageTag::LanguageTag( const OUString& rBcp47, const OUString& rLanguage, else maBcp47 = rLanguage + "-" + rScript + "-" + rCountry; mbInitializedBcp47 = true; + maLocale.Language = I18NLANGTAG_QLT; + maLocale.Country = rCountry; + maLocale.Variant = maBcp47; + mbInitializedLocale = true; } } } @@ -310,20 +528,11 @@ LanguageTag::LanguageTag( const OUString& rBcp47, const OUString& rLanguage, LanguageTag::LanguageTag( const rtl_Locale & rLocale ) : maLocale( rLocale.Language, rLocale.Country, rLocale.Variant), - mpImplLangtag( NULL), mnLangID( LANGUAGE_DONTKNOW), - meIsValid( DECISION_DONTKNOW), - meIsIsoLocale( DECISION_DONTKNOW), - meIsIsoODF( DECISION_DONTKNOW), - meIsLiblangtagNeeded( DECISION_DONTKNOW), mbSystemLocale( maLocale.Language.isEmpty()), mbInitializedBcp47( false), mbInitializedLocale( !mbSystemLocale), mbInitializedLangID( false), - mbCachedLanguage( false), - mbCachedScript( false), - mbCachedCountry( false), - mbCachedVariants( false), mbIsFallback( false) { convertFromRtlLocale(); @@ -334,29 +543,13 @@ LanguageTag::LanguageTag( const LanguageTag & rLanguageTag ) : maLocale( rLanguageTag.maLocale), maBcp47( rLanguageTag.maBcp47), - maCachedLanguage( rLanguageTag.maCachedLanguage), - maCachedScript( rLanguageTag.maCachedScript), - maCachedCountry( rLanguageTag.maCachedCountry), - maCachedVariants( rLanguageTag.maCachedVariants), - mpImplLangtag( rLanguageTag.mpImplLangtag ? - lt_tag_copy( LANGTAGCAST( rLanguageTag.mpImplLangtag)) : NULL), mnLangID( rLanguageTag.mnLangID), - meIsValid( rLanguageTag.meIsValid), - meIsIsoLocale( rLanguageTag.meIsIsoLocale), - meIsIsoODF( rLanguageTag.meIsIsoODF), - meIsLiblangtagNeeded( rLanguageTag.meIsLiblangtagNeeded), + mpImpl( rLanguageTag.mpImpl), mbSystemLocale( rLanguageTag.mbSystemLocale), mbInitializedBcp47( rLanguageTag.mbInitializedBcp47), mbInitializedLocale( rLanguageTag.mbInitializedLocale), - mbInitializedLangID( rLanguageTag.mbInitializedLangID), - mbCachedLanguage( rLanguageTag.mbCachedLanguage), - mbCachedScript( rLanguageTag.mbCachedScript), - mbCachedCountry( rLanguageTag.mbCachedCountry), - mbCachedVariants( rLanguageTag.mbCachedVariants), - mbIsFallback( rLanguageTag.mbIsFallback) + mbInitializedLangID( rLanguageTag.mbInitializedLangID) { - if (mpImplLangtag) - theDataRef::get().incRef(); } @@ -364,76 +557,39 @@ LanguageTag& LanguageTag::operator=( const LanguageTag & rLanguageTag ) { maLocale = rLanguageTag.maLocale; maBcp47 = rLanguageTag.maBcp47; - maCachedLanguage = rLanguageTag.maCachedLanguage; - maCachedScript = rLanguageTag.maCachedScript; - maCachedCountry = rLanguageTag.maCachedCountry; - maCachedVariants = rLanguageTag.maCachedVariants; - mpImplLangtag = rLanguageTag.mpImplLangtag; - mpImplLangtag = rLanguageTag.mpImplLangtag ? - lt_tag_copy( LANGTAGCAST( rLanguageTag.mpImplLangtag)) : NULL; mnLangID = rLanguageTag.mnLangID; - meIsValid = rLanguageTag.meIsValid; - meIsIsoLocale = rLanguageTag.meIsIsoLocale; - meIsIsoODF = rLanguageTag.meIsIsoODF; - meIsLiblangtagNeeded= rLanguageTag.meIsLiblangtagNeeded; + mpImpl = rLanguageTag.mpImpl; mbSystemLocale = rLanguageTag.mbSystemLocale; mbInitializedBcp47 = rLanguageTag.mbInitializedBcp47; mbInitializedLocale = rLanguageTag.mbInitializedLocale; mbInitializedLangID = rLanguageTag.mbInitializedLangID; - mbCachedLanguage = rLanguageTag.mbCachedLanguage; - mbCachedScript = rLanguageTag.mbCachedScript; - mbCachedCountry = rLanguageTag.mbCachedCountry; - mbCachedVariants = rLanguageTag.mbCachedVariants; - mbIsFallback = rLanguageTag.mbIsFallback; - if (mpImplLangtag) - theDataRef::get().incRef(); return *this; } LanguageTag::~LanguageTag() { - if (mpImplLangtag) - { - lt_tag_unref( MPLANGTAG); - theDataRef::get().decRef(); - } } -void LanguageTag::resetVars() +LanguageTagImpl* LanguageTag::getImpl() const { - if (mpImplLangtag) - { - lt_tag_unref( MPLANGTAG); - mpImplLangtag = NULL; - theDataRef::get().decRef(); - } + if (!mpImpl) + mpImpl.reset( new LanguageTagImpl( *this)); + return mpImpl.get(); +} + +void LanguageTag::resetVars() +{ + mpImpl.reset(); maLocale = lang::Locale(); - if (!maBcp47.isEmpty()) - maBcp47 = OUString(); - if (!maCachedLanguage.isEmpty()) - maCachedLanguage= OUString(); - if (!maCachedScript.isEmpty()) - maCachedScript = OUString(); - if (!maCachedCountry.isEmpty()) - maCachedCountry = OUString(); - if (!maCachedVariants.isEmpty()) - maCachedVariants = OUString(); - mnLangID = LANGUAGE_DONTKNOW; - meIsValid = DECISION_DONTKNOW; - meIsIsoLocale = DECISION_DONTKNOW; - meIsIsoODF = DECISION_DONTKNOW; - meIsLiblangtagNeeded= DECISION_DONTKNOW; + maBcp47 = OUString(); + mnLangID = LANGUAGE_SYSTEM; mbSystemLocale = true; mbInitializedBcp47 = false; mbInitializedLocale = false; mbInitializedLangID = false; - mbCachedLanguage = false; - mbCachedScript = false; - mbCachedCountry = false; - mbCachedVariants = false; mbIsFallback = false; } @@ -446,7 +602,7 @@ void LanguageTag::reset( const OUString & rBcp47LanguageTag, bool bCanonicalize mbInitializedBcp47 = !mbSystemLocale; if (bCanonicalize) - canonicalize(); + getImpl()->canonicalize(); } @@ -475,7 +631,7 @@ void LanguageTag::reset( const rtl_Locale & rLocale ) } -bool LanguageTag::canonicalize() +bool LanguageTagImpl::canonicalize() { #ifdef erDEBUG // dump once @@ -603,7 +759,7 @@ bool LanguageTag::canonicalize() return bChanged; // that's it } meIsLiblangtagNeeded = DECISION_YES; - SAL_INFO( "i18nlangtag", "LanguageTag::canonicalize: using liblangtag for " << maBcp47); + SAL_INFO( "i18nlangtag", "LanguageTagImpl::canonicalize: using liblangtag for " << maBcp47); if (!mpImplLangtag) { @@ -616,7 +772,7 @@ bool LanguageTag::canonicalize() if (lt_tag_parse( MPLANGTAG, OUStringToOString( maBcp47, RTL_TEXTENCODING_UTF8).getStr(), &aError.p)) { char* pTag = lt_tag_canonicalize( MPLANGTAG, &aError.p); - SAL_WARN_IF( !pTag, "i18nlangtag", "LanguageTag::canonicalize: could not canonicalize " << maBcp47); + SAL_WARN_IF( !pTag, "i18nlangtag", "LanguageTagImpl::canonicalize: could not canonicalize " << maBcp47); if (pTag) { OUString aOld( maBcp47); @@ -630,7 +786,7 @@ bool LanguageTag::canonicalize() meIsIsoODF = DECISION_DONTKNOW; if (!lt_tag_parse( MPLANGTAG, pTag, &aError.p)) { - SAL_WARN( "i18nlangtag", "LanguageTag::canonicalize: could not reparse " << maBcp47); + SAL_WARN( "i18nlangtag", "LanguageTagImpl::canonicalize: could not reparse " << maBcp47); free( pTag); meIsValid = DECISION_NO; return bChanged; @@ -643,14 +799,14 @@ bool LanguageTag::canonicalize() } else { - SAL_INFO( "i18nlangtag", "LanguageTag::canonicalize: could not parse " << maBcp47); + SAL_INFO( "i18nlangtag", "LanguageTagImpl::canonicalize: could not parse " << maBcp47); } meIsValid = DECISION_NO; return bChanged; } -bool LanguageTag::synCanonicalize() +bool LanguageTagImpl::synCanonicalize() { bool bChanged = false; if (meIsLiblangtagNeeded != DECISION_NO && !mpImplLangtag) @@ -668,7 +824,28 @@ bool LanguageTag::synCanonicalize() } -void LanguageTag::convertLocaleToBcp47() +void LanguageTag::syncFromImpl() +{ + LanguageTagImpl* pImpl = getImpl(); + mbInitializedBcp47 = pImpl->mbInitializedBcp47; + maBcp47 = pImpl->maBcp47; + mbInitializedLocale = pImpl->mbInitializedLocale; + maLocale = pImpl->maLocale; + mbInitializedLangID = pImpl->mbInitializedLangID; + mnLangID = pImpl->mnLangID; +} + + +bool LanguageTag::synCanonicalize() +{ + bool bChanged = getImpl()->synCanonicalize(); + if (bChanged) + syncFromImpl(); + return bChanged; +} + + +void LanguageTagImpl::convertLocaleToBcp47() { if (mbSystemLocale && !mbInitializedLocale) convertLangToLocale(); @@ -680,13 +857,22 @@ void LanguageTag::convertLocaleToBcp47() } else { - maBcp47 = convertToBcp47( maLocale, true); + maBcp47 = LanguageTag::convertToBcp47( maLocale, true); } mbInitializedBcp47 = true; } -void LanguageTag::convertLocaleToLang() +void LanguageTag::convertLocaleToBcp47() +{ + LanguageTagImpl* pImpl = getImpl(); + pImpl->convertLocaleToBcp47(); + maBcp47 = pImpl->maBcp47; + mbInitializedBcp47 = pImpl->mbInitializedBcp47; +} + + +void LanguageTagImpl::convertLocaleToLang() { if (mbSystemLocale) { @@ -694,13 +880,22 @@ void LanguageTag::convertLocaleToLang() } else { - mnLangID = convertToLanguageType( maLocale, true); + mnLangID = LanguageTag::convertToLanguageType( maLocale, true); } mbInitializedLangID = true; } -void LanguageTag::convertBcp47ToLocale() +void LanguageTag::convertLocaleToLang() +{ + LanguageTagImpl* pImpl = getImpl(); + pImpl->convertLocaleToLang(); + mnLangID = pImpl->mnLangID; + mbInitializedLangID = pImpl->mbInitializedLangID; +} + + +void LanguageTagImpl::convertBcp47ToLocale() { bool bIso = isIsoLocale(); if (bIso) @@ -719,7 +914,16 @@ void LanguageTag::convertBcp47ToLocale() } -void LanguageTag::convertBcp47ToLang() +void LanguageTag::convertBcp47ToLocale() +{ + LanguageTagImpl* pImpl = getImpl(); + pImpl->convertBcp47ToLocale(); + maLocale = pImpl->maLocale; + mbInitializedLocale = pImpl->mbInitializedLocale; +} + + +void LanguageTagImpl::convertBcp47ToLang() { if (mbSystemLocale) { @@ -735,7 +939,16 @@ void LanguageTag::convertBcp47ToLang() } -void LanguageTag::convertLangToLocale() +void LanguageTag::convertBcp47ToLang() +{ + LanguageTagImpl* pImpl = getImpl(); + pImpl->convertBcp47ToLang(); + mnLangID = pImpl->mnLangID; + mbInitializedLangID = pImpl->mbInitializedLangID; +} + + +void LanguageTagImpl::convertLangToLocale() { if (mbSystemLocale && !mbInitializedLangID) { @@ -743,12 +956,21 @@ void LanguageTag::convertLangToLocale() mbInitializedLangID = true; } // Resolve system here! The original is remembered as mbSystemLocale. - maLocale = convertToLocale( mnLangID, true); + maLocale = LanguageTag::convertToLocale( mnLangID, true); mbInitializedLocale = true; } -void LanguageTag::convertLangToBcp47() +void LanguageTag::convertLangToLocale() +{ + LanguageTagImpl* pImpl = getImpl(); + pImpl->convertLangToLocale(); + maLocale = pImpl->maLocale; + mbInitializedLocale = pImpl->mbInitializedLocale; +} + + +void LanguageTagImpl::convertLangToBcp47() { if (!mbInitializedLocale) convertLangToLocale(); @@ -757,6 +979,15 @@ void LanguageTag::convertLangToBcp47() } +void LanguageTag::convertLangToBcp47() +{ + LanguageTagImpl* pImpl = getImpl(); + pImpl->convertLangToBcp47(); + maBcp47 = pImpl->maBcp47; + mbInitializedBcp47 = pImpl->mbInitializedBcp47; +} + + void LanguageTag::convertFromRtlLocale() { // The rtl_Locale follows the Open Group Base Specification, @@ -797,22 +1028,37 @@ void LanguageTag::convertFromRtlLocale() } -const OUString & LanguageTag::getBcp47( bool bResolveSystem ) const +const OUString & LanguageTagImpl::getBcp47( bool bResolveSystem ) const { if (!bResolveSystem && mbSystemLocale) return theEmptyBcp47::get(); if (!mbInitializedBcp47) { if (mbInitializedLocale) - const_cast<LanguageTag*>(this)->convertLocaleToBcp47(); + const_cast<LanguageTagImpl*>(this)->convertLocaleToBcp47(); else - const_cast<LanguageTag*>(this)->convertLangToBcp47(); + const_cast<LanguageTagImpl*>(this)->convertLangToBcp47(); + } + return maBcp47; +} + + +const OUString & LanguageTag::getBcp47( bool bResolveSystem ) const +{ + if (!bResolveSystem && mbSystemLocale) + return theEmptyBcp47::get(); + if (!mbInitializedBcp47) + const_cast<LanguageTag*>(this)->syncFromImpl(); + if (!mbInitializedBcp47) + { + getImpl()->getBcp47( bResolveSystem); + const_cast<LanguageTag*>(this)->syncFromImpl(); } return maBcp47; } -OUString LanguageTag::getLanguageFromLangtag() +OUString LanguageTagImpl::getLanguageFromLangtag() { OUString aLanguage; synCanonicalize(); @@ -838,7 +1084,7 @@ OUString LanguageTag::getLanguageFromLangtag() } -OUString LanguageTag::getScriptFromLangtag() +OUString LanguageTagImpl::getScriptFromLangtag() { OUString aScript; synCanonicalize(); @@ -864,7 +1110,7 @@ OUString LanguageTag::getScriptFromLangtag() } -OUString LanguageTag::getRegionFromLangtag() +OUString LanguageTagImpl::getRegionFromLangtag() { OUString aRegion; synCanonicalize(); @@ -897,7 +1143,7 @@ OUString LanguageTag::getRegionFromLangtag() } -OUString LanguageTag::getVariantsFromLangtag() +OUString LanguageTagImpl::getVariantsFromLangtag() { OUString aVariants; synCanonicalize(); @@ -936,6 +1182,8 @@ const com::sun::star::lang::Locale & LanguageTag::getLocale( bool bResolveSystem if (!bResolveSystem && mbSystemLocale) return theEmptyLocale::get(); if (!mbInitializedLocale) + const_cast<LanguageTag*>(this)->syncFromImpl(); + if (!mbInitializedLocale) { if (mbInitializedBcp47) const_cast<LanguageTag*>(this)->convertBcp47ToLocale(); @@ -951,6 +1199,8 @@ LanguageType LanguageTag::getLanguageType( bool bResolveSystem ) const if (!bResolveSystem && mbSystemLocale) return LANGUAGE_SYSTEM; if (!mbInitializedLangID) + const_cast<LanguageTag*>(this)->syncFromImpl(); + if (!mbInitializedLangID) { if (mbInitializedBcp47) const_cast<LanguageTag*>(this)->convertBcp47ToLang(); @@ -982,9 +1232,9 @@ void LanguageTag::getIsoLanguageScriptCountry( OUString& rLanguage, OUString& rS } else { - rLanguage = (isIsoLanguage( getLanguage()) ? getLanguage() : OUString()); - rScript = (isIsoScript( getScript()) ? getScript() : OUString()); - rCountry = (isIsoCountry( getCountry()) ? getCountry() : OUString()); + rLanguage = (LanguageTag::isIsoLanguage( getLanguage()) ? getLanguage() : OUString()); + rScript = (LanguageTag::isIsoScript( getScript()) ? getScript() : OUString()); + rCountry = (LanguageTag::isIsoCountry( getCountry()) ? getCountry() : OUString()); } } @@ -1052,28 +1302,40 @@ bool LanguageTag::isIsoScript( const OUString& rScript ) } -OUString LanguageTag::getLanguage() const +OUString LanguageTagImpl::getLanguage() const { if (!mbCachedLanguage) { - maCachedLanguage = const_cast<LanguageTag*>(this)->getLanguageFromLangtag(); + maCachedLanguage = const_cast<LanguageTagImpl*>(this)->getLanguageFromLangtag(); mbCachedLanguage = true; } return maCachedLanguage; } -OUString LanguageTag::getScript() const +OUString LanguageTag::getLanguage() const +{ + return getImpl()->getLanguage(); +} + + +OUString LanguageTagImpl::getScript() const { if (!mbCachedScript) { - maCachedScript = const_cast<LanguageTag*>(this)->getScriptFromLangtag(); + maCachedScript = const_cast<LanguageTagImpl*>(this)->getScriptFromLangtag(); mbCachedScript = true; } return maCachedScript; } +OUString LanguageTag::getScript() const +{ + return getImpl()->getScript(); +} + + OUString LanguageTag::getLanguageAndScript() const { OUString aLanguageScript( getLanguage()); @@ -1086,12 +1348,12 @@ OUString LanguageTag::getLanguageAndScript() const } -OUString LanguageTag::getCountry() const +OUString LanguageTagImpl::getCountry() const { if (!mbCachedCountry) { - maCachedCountry = const_cast<LanguageTag*>(this)->getRegionFromLangtag(); - if (!isIsoCountry( maCachedCountry)) + maCachedCountry = const_cast<LanguageTagImpl*>(this)->getRegionFromLangtag(); + if (!LanguageTag::isIsoCountry( maCachedCountry)) maCachedCountry = OUString(); mbCachedCountry = true; } @@ -1099,23 +1361,41 @@ OUString LanguageTag::getCountry() const } +OUString LanguageTag::getCountry() const +{ + return getImpl()->getCountry(); +} + + +OUString LanguageTagImpl::getRegion() const +{ + return const_cast<LanguageTagImpl*>(this)->getRegionFromLangtag(); +} + + OUString LanguageTag::getRegion() const { - return const_cast<LanguageTag*>(this)->getRegionFromLangtag(); + return getImpl()->getRegion(); } -OUString LanguageTag::getVariants() const +OUString LanguageTagImpl::getVariants() const { if (!mbCachedVariants) { - maCachedVariants = const_cast<LanguageTag*>(this)->getVariantsFromLangtag(); + maCachedVariants = const_cast<LanguageTagImpl*>(this)->getVariantsFromLangtag(); mbCachedVariants = true; } return maCachedVariants; } +OUString LanguageTag::getVariants() const +{ + return getImpl()->getVariants(); +} + + OUString LanguageTag::getGlibcLocaleString( const OUString & rEncoding ) const { OUString aRet; @@ -1139,7 +1419,7 @@ OUString LanguageTag::getGlibcLocaleString( const OUString & rEncoding ) const } -bool LanguageTag::hasScript() const +bool LanguageTagImpl::hasScript() const { if (!mbCachedScript) getScript(); @@ -1147,7 +1427,13 @@ bool LanguageTag::hasScript() const } -bool LanguageTag::cacheSimpleLSCV() +bool LanguageTag::hasScript() const +{ + return getImpl()->hasScript(); +} + + +bool LanguageTagImpl::cacheSimpleLSCV() { OUString aLanguage, aScript, aCountry, aVariants; Extraction eExt = simpleExtract( maBcp47, aLanguage, aScript, aCountry, aVariants); @@ -1164,27 +1450,33 @@ bool LanguageTag::cacheSimpleLSCV() } -bool LanguageTag::isIsoLocale() const +bool LanguageTagImpl::isIsoLocale() const { if (meIsIsoLocale == DECISION_DONTKNOW) { - const_cast<LanguageTag*>(this)->synCanonicalize(); + const_cast<LanguageTagImpl*>(this)->synCanonicalize(); // It must be at most ll-CC or lll-CC // Do not use getCountry() here, use getRegion() instead. meIsIsoLocale = ((maBcp47.isEmpty() || - (maBcp47.getLength() <= 6 && isIsoLanguage( getLanguage()) && isIsoCountry( getRegion()))) ? - DECISION_YES : DECISION_NO); + (maBcp47.getLength() <= 6 && LanguageTag::isIsoLanguage( getLanguage()) && + LanguageTag::isIsoCountry( getRegion()))) ? DECISION_YES : DECISION_NO); } return meIsIsoLocale == DECISION_YES; } -bool LanguageTag::isIsoODF() const +bool LanguageTag::isIsoLocale() const +{ + return getImpl()->isIsoLocale(); +} + + +bool LanguageTagImpl::isIsoODF() const { if (meIsIsoODF == DECISION_DONTKNOW) { - const_cast<LanguageTag*>(this)->synCanonicalize(); - if (!isIsoScript( getScript())) + const_cast<LanguageTagImpl*>(this)->synCanonicalize(); + if (!LanguageTag::isIsoScript( getScript())) return ((meIsIsoODF = DECISION_NO) == DECISION_YES); // The usual case is lll-CC so simply check that first. if (isIsoLocale()) @@ -1192,19 +1484,25 @@ bool LanguageTag::isIsoODF() const // If this is not ISO locale for which script must not exist it can // still be ISO locale plus ISO script lll-Ssss-CC, but not ll-vvvv ... // ll-vvvvvvvv - meIsIsoODF = ((maBcp47.getLength() <= 11 && - isIsoLanguage( getLanguage()) && isIsoCountry( getRegion()) && isIsoScript( getScript()) && + meIsIsoODF = ((maBcp47.getLength() <= 11 && LanguageTag::isIsoLanguage( getLanguage()) && + LanguageTag::isIsoCountry( getRegion()) && LanguageTag::isIsoScript( getScript()) && getVariants().isEmpty()) ? DECISION_YES : DECISION_NO); } return meIsIsoODF == DECISION_YES; } -bool LanguageTag::isValidBcp47() const +bool LanguageTag::isIsoODF() const +{ + return getImpl()->isIsoODF(); +} + + +bool LanguageTagImpl::isValidBcp47() const { if (meIsValid == DECISION_DONTKNOW) { - const_cast<LanguageTag*>(this)->synCanonicalize(); + const_cast<LanguageTagImpl*>(this)->synCanonicalize(); SAL_WARN_IF( meIsValid == DECISION_DONTKNOW, "i18nlangtag", "LanguageTag::isValidBcp47: canonicalize() didn't set meIsValid"); } @@ -1212,6 +1510,12 @@ bool LanguageTag::isValidBcp47() const } +bool LanguageTag::isValidBcp47() const +{ + return getImpl()->isValidBcp47(); +} + + bool LanguageTag::isSystemLocale() const { return mbSystemLocale; @@ -1446,7 +1750,7 @@ bool LanguageTag::operator!=( const LanguageTag & rLanguageTag ) const // static -LanguageTag::Extraction LanguageTag::simpleExtract( const OUString& rBcp47, +LanguageTagImpl::Extraction LanguageTagImpl::simpleExtract( const OUString& rBcp47, OUString& rLanguage, OUString& rScript, OUString& rCountry, OUString& rVariants ) { Extraction eRet = EXTRACTED_NONE; diff --git a/include/i18nlangtag/languagetag.hxx b/include/i18nlangtag/languagetag.hxx index 06baf8d27993..aef59d0d738c 100644 --- a/include/i18nlangtag/languagetag.hxx +++ b/include/i18nlangtag/languagetag.hxx @@ -16,6 +16,7 @@ #include <i18nlangtag/i18nlangtagdllapi.h> #include <i18nlangtag/lang.h> +#include <boost/shared_ptr.hpp> #include <vector> typedef struct _rtl_Locale rtl_Locale; // as in rtl/locale.h @@ -35,6 +36,9 @@ typedef struct _rtl_Locale rtl_Locale; // as in rtl/locale.h #define I18NLANGTAG_QLT "qlt" +class LanguageTagImpl; + + /** Wrapper for liblangtag BCP 47 language tags, MS-LangIDs, locales and conversions in between. @@ -47,6 +51,8 @@ typedef struct _rtl_Locale rtl_Locale; // as in rtl/locale.h */ class I18NLANGTAG_DLLPUBLIC LanguageTag { + friend class LanguageTagImpl; + public: /** Init LanguageTag with existing BCP 47 language tag string. @@ -480,97 +486,39 @@ public: private: - enum Decision - { - DECISION_DONTKNOW, - DECISION_NO, - DECISION_YES - }; - - mutable com::sun::star::lang::Locale maLocale; - mutable OUString maBcp47; - mutable OUString maCachedLanguage; ///< cache getLanguage() - mutable OUString maCachedScript; ///< cache getScript() - mutable OUString maCachedCountry; ///< cache getCountry() - mutable OUString maCachedVariants; ///< cache getVariants() - mutable void* mpImplLangtag; ///< actually lt_tag_t pointer, encapsulated - mutable LanguageType mnLangID; - mutable Decision meIsValid; - mutable Decision meIsIsoLocale; - mutable Decision meIsIsoODF; - mutable Decision meIsLiblangtagNeeded; ///< whether processing with liblangtag needed - bool mbSystemLocale : 1; - mutable bool mbInitializedBcp47 : 1; - mutable bool mbInitializedLocale : 1; - mutable bool mbInitializedLangID : 1; - mutable bool mbCachedLanguage : 1; - mutable bool mbCachedScript : 1; - mutable bool mbCachedCountry : 1; - mutable bool mbCachedVariants : 1; - bool mbIsFallback : 1; - - void convertLocaleToBcp47(); - void convertLocaleToLang(); - void convertBcp47ToLocale(); - void convertBcp47ToLang(); - void convertLangToLocale(); - void convertLangToBcp47(); - - void convertFromRtlLocale(); - - /** @return whether BCP 47 language tag string was changed. */ - bool canonicalize(); + mutable com::sun::star::lang::Locale maLocale; + mutable OUString maBcp47; + mutable LanguageType mnLangID; + mutable boost::shared_ptr< LanguageTagImpl > mpImpl; + bool mbSystemLocale : 1; + mutable bool mbInitializedBcp47 : 1; + mutable bool mbInitializedLocale : 1; + mutable bool mbInitializedLangID : 1; + bool mbIsFallback : 1; - /** Canonicalize if not yet done and synchronize initialized conversions. - - @return whether BCP 47 language tag string was changed. - */ - bool synCanonicalize(); + LanguageTagImpl* getImpl() const; + void syncFromImpl(); - OUString getLanguageFromLangtag(); - OUString getScriptFromLangtag(); - OUString getRegionFromLangtag(); - OUString getVariantsFromLangtag(); + void convertLocaleToBcp47(); + void convertLocaleToLang(); + void convertBcp47ToLocale(); + void convertBcp47ToLang(); + void convertLangToLocale(); + void convertLangToBcp47(); - void resetVars(); + void convertFromRtlLocale(); - /** Obtain Language, Script, Country and Variants via simpleExtract() and - assign them to the cached variables if successful. + /** Canonicalize if not yet done and synchronize initialized conversions. - @return return of simpleExtract() + @return whether BCP 47 language tag string was changed. */ - bool cacheSimpleLSCV(); - - static bool isIsoLanguage( const OUString& rLanguage ); - static bool isIsoScript( const OUString& rScript ); - static bool isIsoCountry( const OUString& rRegion ); + bool synCanonicalize(); - enum Extraction - { - EXTRACTED_NONE, - EXTRACTED_LSC, - EXTRACTED_LV, - EXTRACTED_X, - EXTRACTED_X_JOKER - }; + void resetVars(); - /** Of a language tag of the form lll[-Ssss][-CC][-vvvvvvvv] extract the - portions. - - Does not check case or content! - - @return EXTRACTED_LSC if simple tag was detected (i.e. one that - would fulfill the isIsoODF() condition), - EXTRACTED_LV if a tag with variant was detected, - EXTRACTED_X if x-... privateuse tag was detected, - EXTRACTED_X_JOKER if "*" joker was detected, - EXTRACTED_NONE else. - */ - static Extraction simpleExtract( const OUString& rBcp47, - OUString& rLanguage, - OUString& rScript, - OUString& rCountry, - OUString& rVariants ); + static bool isIsoLanguage( const OUString& rLanguage ); + static bool isIsoScript( const OUString& rScript ); + static bool isIsoCountry( const OUString& rRegion ); }; |