i18npool/source/defaultnumberingprovider/defaultnumberingprovider.cxx | 66 ++---- i18npool/source/nativenumber/nativenumbersupplier.cxx | 107 ++++++++-- offapi/com/sun/star/i18n/NativeNumberMode.idl | 11 + svl/CppunitTest_svl_qa_cppunit.mk | 14 + svl/qa/unit/svl.cxx | 12 + 5 files changed, 152 insertions(+), 58 deletions(-)
New commits: commit 56a7f308cf57f87d9e2cdeb77f48b570f81de85e Author: Mike Kaganski <mike.kagan...@collabora.com> Date: Sun May 13 03:09:43 2018 +0300 tdf#115007: add NatNum codes for cardinal/ordinal number names/indicators ... based on libnumbertext integrated since commit f1579d3d6c5f5f3a651825e035b93bee7a4f43c6. [NatNum12] gives cardinal number names (one, two, three, ...) [NatNum13] gives ordinal number names (first, second, third, ...) [NatNum14] gives ordinal indicators (1st, 2nd, 3rd, ...) Change-Id: Ie2afdeeb82da1b36e9755c02d7b2276c77be9c72 Reviewed-on: https://gerrit.libreoffice.org/54186 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Eike Rathke <er...@redhat.com> diff --git a/i18npool/source/defaultnumberingprovider/defaultnumberingprovider.cxx b/i18npool/source/defaultnumberingprovider/defaultnumberingprovider.cxx index e222611a2afe..af4e27d0f69f 100644 --- a/i18npool/source/defaultnumberingprovider/defaultnumberingprovider.cxx +++ b/i18npool/source/defaultnumberingprovider/defaultnumberingprovider.cxx @@ -19,7 +19,6 @@ #include <defaultnumberingprovider.hxx> #include <com/sun/star/lang/IllegalArgumentException.hpp> -#include <com/sun/star/linguistic2/NumberText.hpp> #include <com/sun/star/style/NumberingType.hpp> #include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/configuration/theDefaultProvider.hpp> @@ -32,9 +31,6 @@ #include <string.h> #include <comphelper/propertysequence.hxx> #include <cppuhelper/supportsservice.hxx> -#include <i18nlangtag/languagetag.hxx> -#include <unordered_map> -#include <map> // Cyrillic upper case #define C_CYR_A "\xD0\x90" @@ -588,6 +584,7 @@ DefaultNumberingProvider::makeNumberingString( const Sequence<beans::PropertyVal sal_Int16 tableSize = 0; const sal_Unicode *table = nullptr; // initialize to avoid compiler warning bool bRecycleSymbol = false; + bool bCapitalize = false; Locale locale; OUString prefix; @@ -639,45 +636,20 @@ DefaultNumberingProvider::makeNumberingString( const Sequence<beans::PropertyVal lcl_formatChars( lowerLetter, 26, number-1, result ); break; case TEXT_NUMBER: + natNum = NativeNumberMode::NATNUM14; // ordinal indicators (1st, 2nd, 3rd, ...) + locale = aLocale; + bCapitalize = true; + break; case TEXT_CARDINAL: + natNum = NativeNumberMode::NATNUM12; // cardinal number names (one, two, three, ...) + locale = aLocale; + bCapitalize = true; + break; case TEXT_ORDINAL: - { - static css::uno::Reference< css::linguistic2::XNumberText > xNumberText; - if (!xNumberText.is()) - xNumberText = linguistic2::NumberText::create( m_xContext ); - OUString aLoc = LanguageTag::convertToBcp47(aLocale); - OUString numbertext_prefix = ""; - if (numType == TEXT_NUMBER) - numbertext_prefix += "ordinal-number "; - else if (numType == TEXT_ORDINAL) - numbertext_prefix += "ordinal "; - // Several hundreds of headings could result typing lags because - // of the continuous update of the multiple number names during typing. - // We fix this by buffering the result of the conversion. - static std::unordered_map<sal_Int32,std::map<OUString, OUString> > aBuff; - auto aBuffItem = aBuff.find(number); - std::map<OUString, OUString> aItem; - if (aBuffItem == aBuff.end() || !aBuffItem->second.count(numbertext_prefix + aLoc)) - { - OUString snumber = OUString::number(number); - OUString aNum = - xNumberText->getNumberText( numbertext_prefix + snumber, aLocale); - if ( !xCharClass.is() ) - xCharClass = CharacterClassification::create( m_xContext ); - // use number at missing number to text conversion - if (aNum.getLength() == 0) - aNum = snumber; - // capitalize first letter - aItem[numbertext_prefix + aLoc] = xCharClass->toTitle(aNum, 0, 1, aLocale) + aNum.copy(1); - aBuff.insert(std::make_pair(number, aItem)); - } - else - { - aItem = aBuffItem->second; - } - result += aItem[numbertext_prefix + aLoc]; - break; - } + natNum = NativeNumberMode::NATNUM13; // ordinal number names (first, second, third, ...) + locale = aLocale; + bCapitalize = true; + break; case ROMAN_UPPER: result += toRoman( number ); break; @@ -937,7 +909,17 @@ DefaultNumberingProvider::makeNumberingString( const Sequence<beans::PropertyVal if (natNum) { rtl::Reference<NativeNumberSupplierService> xNatNum(new NativeNumberSupplierService); - result += xNatNum->getNativeNumberString(OUString::number( number ), locale, natNum); + OUString aNum + = xNatNum->getNativeNumberString(OUString::number(number), locale, natNum); + if (bCapitalize) + { + if (!xCharClass.is()) + xCharClass = CharacterClassification::create(m_xContext); + // capitalize first letter + result += xCharClass->toTitle(aNum, 0, 1, aLocale) + aNum.copy(1); + } + else + result += aNum; } else if (tableSize) { if ( number > tableSize && !bRecycleSymbol) result += OUString::number( number); diff --git a/i18npool/source/nativenumber/nativenumbersupplier.cxx b/i18npool/source/nativenumber/nativenumbersupplier.cxx index 6dc7c792c931..f3c40a2b7d61 100644 --- a/i18npool/source/nativenumber/nativenumbersupplier.cxx +++ b/i18npool/source/nativenumber/nativenumbersupplier.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <i18nlangtag/languagetag.hxx> #include <i18nlangtag/mslangid.hxx> #include <rtl/ustrbuf.hxx> #include <sal/macros.h> @@ -24,8 +25,12 @@ #include <localedata.hxx> #include "data/numberchar.h" #include <comphelper/string.hxx> +#include <comphelper/processfactory.hxx> #include <cppuhelper/supportsservice.hxx> +#include <map> #include <memory> +#include <unordered_map> +#include <com/sun/star/linguistic2/NumberText.hpp> using namespace ::com::sun::star::uno; using namespace ::com::sun::star::i18n; @@ -250,7 +255,10 @@ OUString AsciiToNative( const OUString& inStr, sal_Int32 nCount, } return aRet; } -static void NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str, + +namespace +{ +void NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str, sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, bool useOffset, OUString& numberChar, OUString& multiplierChar) { @@ -300,7 +308,7 @@ static void NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_U } /// @throws RuntimeException -static OUString NativeToAscii(const OUString& inStr, +OUString NativeToAscii(const OUString& inStr, sal_Int32 nCount, Sequence< sal_Int32 >& offset, bool useOffset ) { OUString aRet; @@ -374,7 +382,7 @@ static OUString NativeToAscii(const OUString& inStr, return aRet; } -static const Number natnum4[4] = { +const Number natnum4[4] = { { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, ExponentCount_6_CJK, MultiplierExponent_6_CJK }, { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, @@ -385,7 +393,7 @@ static const Number natnum4[4] = { ExponentCount_6_CJK, MultiplierExponent_6_CJK }, }; -static const Number natnum5[4] = { +const Number natnum5[4] = { { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], 0, ExponentCount_6_CJK, MultiplierExponent_6_CJK }, { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], 0, @@ -396,7 +404,7 @@ static const Number natnum5[4] = { ExponentCount_6_CJK, MultiplierExponent_6_CJK }, }; -static const Number natnum6[4] = { +const Number natnum6[4] = { { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, ExponentCount_6_CJK, MultiplierExponent_6_CJK }, { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, @@ -407,7 +415,7 @@ static const Number natnum6[4] = { ExponentCount_6_CJK, MultiplierExponent_6_CJK }, }; -static const Number natnum7[4] = { +const Number natnum7[4] = { { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], NUMBER_OMIT_ALL, ExponentCount_6_CJK, MultiplierExponent_6_CJK }, { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], NUMBER_OMIT_ALL, @@ -418,7 +426,7 @@ static const Number natnum7[4] = { ExponentCount_6_CJK, MultiplierExponent_6_CJK }, }; -static const Number natnum8[4] = { +const Number natnum8[4] = { { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], NUMBER_OMIT_ALL, ExponentCount_6_CJK, MultiplierExponent_6_CJK }, { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, @@ -429,14 +437,14 @@ static const Number natnum8[4] = { ExponentCount_6_CJK, MultiplierExponent_6_CJK }, }; -static const Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, +const Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, ExponentCount_6_CJK, MultiplierExponent_6_CJK }; -static const Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL, +const Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL, ExponentCount_6_CJK, MultiplierExponent_6_CJK }; //! ATTENTION: Do not change order of elements! //! Append new languages to the end of the list! -static const sal_Char *natnum1Locales[] = { +const sal_Char *natnum1Locales[] = { "zh_CN", "zh_TW", "ja", @@ -464,11 +472,11 @@ static const sal_Char *natnum1Locales[] = { "fa", "cu" }; -static sal_Int16 nbOfLocale = SAL_N_ELEMENTS(natnum1Locales); +sal_Int16 nbOfLocale = SAL_N_ELEMENTS(natnum1Locales); //! ATTENTION: Do not change order of elements! //! Number and order must match elements of natnum1Locales! -static const sal_Int16 natnum1[] = { +const sal_Int16 natnum1[] = { NumberChar_Lower_zh, NumberChar_Lower_zh, NumberChar_Modern_ja, @@ -496,20 +504,20 @@ static const sal_Int16 natnum1[] = { NumberChar_EastIndic_ar, NumberChar_cu }; -static const sal_Int16 sizeof_natnum1 = SAL_N_ELEMENTS(natnum1); +const sal_Int16 sizeof_natnum1 = SAL_N_ELEMENTS(natnum1); //! ATTENTION: Do not change order of elements! //! Order must match first elements of natnum1Locales! -static const sal_Int16 natnum2[] = { +const sal_Int16 natnum2[] = { NumberChar_Upper_zh, NumberChar_Upper_zh_TW, NumberChar_Traditional_ja, NumberChar_Upper_ko, NumberChar_he }; -static const sal_Int16 sizeof_natnum2 = SAL_N_ELEMENTS(natnum2); +const sal_Int16 sizeof_natnum2 = SAL_N_ELEMENTS(natnum2); -static sal_Int16 getLanguageNumber( const Locale& rLocale) +sal_Int16 getLanguageNumber( const Locale& rLocale) { // return zh_TW for TW, HK and MO, return zh_CN for other zh locales. if (rLocale.Language == "zh") return MsLangId::isTraditionalChinese(rLocale) ? 1 : 0; @@ -521,12 +529,76 @@ static sal_Int16 getLanguageNumber( const Locale& rLocale) return -1; } +OUString getNumberText(const Locale& aLocale, sal_Int16 numType, const OUString& rNumberString) +{ + assert(numType == NativeNumberMode::NATNUM12 || numType == NativeNumberMode::NATNUM13 + || numType == NativeNumberMode::NATNUM14); + + sal_Int32 i, count = 0; + const sal_Int32 len = rNumberString.getLength(); + const sal_Unicode* src = rNumberString.getStr(); + + OUStringBuffer sBuf(len); + for (i = 0; i < len; i++) + { + sal_Unicode ch = src[i]; + if (isNumber(ch)) + { + ++count; + sBuf.append(ch); + } + else if (isSeparator(ch) && count > 0) + continue; + else if (isMinus(ch) && count == 0) + sBuf.append(ch); + else + break; + } + + if (count == 0) + return rNumberString; + + OUString aNumberStr = sBuf.makeStringAndClear(); + + static auto xNumberText + = css::linguistic2::NumberText::create(comphelper::getProcessComponentContext()); + OUString aLoc = LanguageTag::convertToBcp47(aLocale); + OUString numbertext_prefix; + if (numType == NativeNumberMode::NATNUM14) + numbertext_prefix = "ordinal-number "; + else if (numType == NativeNumberMode::NATNUM13) + numbertext_prefix = "ordinal "; + // Several hundreds of headings could result typing lags because + // of the continuous update of the multiple number names during typing. + // We fix this by buffering the result of the conversion. + static std::unordered_map<OUString, std::map<OUString, OUString>> aBuff; + auto& rItems = aBuff[aNumberStr]; + auto& rItem = rItems[numbertext_prefix + aLoc]; + if (rItem.isEmpty()) + { + rItem = xNumberText->getNumberText(numbertext_prefix + aNumberStr, aLocale); + // use number at missing number to text conversion + if (rItem.isEmpty()) + rItem = aNumberStr; + } + OUString sResult = rItem; + if (i < len) + sResult += rNumberString.copy(i); + return sResult; +} +} + OUString NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) { if (!isValidNatNum(rLocale, nNativeNumberMode)) return aNumberString; + if (nNativeNumberMode == NativeNumberMode::NATNUM12 + || nNativeNumberMode == NativeNumberMode::NATNUM13 + || nNativeNumberMode == NativeNumberMode::NATNUM14) + return getNumberText(rLocale, nNativeNumberMode, aNumberString); + sal_Int16 langnum = getLanguageNumber(rLocale); if (langnum == -1) return aNumberString; @@ -664,6 +736,9 @@ sal_Bool SAL_CALL NativeNumberSupplierService::isValidNatNum( const Locale& rLoc switch (nNativeNumberMode) { case NativeNumberMode::NATNUM0: // Ascii case NativeNumberMode::NATNUM3: // Char, FullWidth + case NativeNumberMode::NATNUM12: // Cardinal number names (one, two, three, ...) + case NativeNumberMode::NATNUM13: // Ordinal number names (first, second, third, ...) + case NativeNumberMode::NATNUM14: // Ordinal indicators (1st, 2nd, 3rd, ...) return true; case NativeNumberMode::NATNUM1: // Char, Lower return (langnum >= 0); diff --git a/offapi/com/sun/star/i18n/NativeNumberMode.idl b/offapi/com/sun/star/i18n/NativeNumberMode.idl index 6af461350e7e..f19980b96edc 100644 --- a/offapi/com/sun/star/i18n/NativeNumberMode.idl +++ b/offapi/com/sun/star/i18n/NativeNumberMode.idl @@ -146,6 +146,17 @@ published constants NativeNumberMode */ const short NATNUM11 = 11; + /** Transliteration to cardinal number names (one, two, three, ...) + */ + const short NATNUM12 = 12; + + /** Transliteration to ordinal number names (first, second, third, ...) + */ + const short NATNUM13 = 13; + + /** Transliteration to ordinal indicators (1st, 2nd, 3rd, ...) + */ + const short NATNUM14 = 14; }; }; }; }; }; diff --git a/svl/CppunitTest_svl_qa_cppunit.mk b/svl/CppunitTest_svl_qa_cppunit.mk index 65be44e40b6f..a067efe8794f 100644 --- a/svl/CppunitTest_svl_qa_cppunit.mk +++ b/svl/CppunitTest_svl_qa_cppunit.mk @@ -27,6 +27,16 @@ $(eval $(call gb_CppunitTest_use_externals,svl_qa_cppunit, \ icu_headers \ )) +ifeq ($(ENABLE_LIBNUMBERTEXT),TRUE) +$(eval $(call gb_CppunitTest_use_package,svl_qa_cppunit, \ + libnumbertext_numbertext \ +)) +endif + +$(eval $(call gb_CppunitTest_add_defs,svl_qa_cppunit, \ + -DENABLE_LIBNUMBERTEXT=$(if $(filter TRUE,$(ENABLE_LIBNUMBERTEXT)),1,0) \ +)) + $(eval $(call gb_CppunitTest_add_exception_objects,svl_qa_cppunit, \ svl/qa/unit/svl \ )) @@ -52,6 +62,10 @@ $(eval $(call gb_CppunitTest_set_include,svl_qa_cppunit,\ $(eval $(call gb_CppunitTest_use_components,svl_qa_cppunit,\ i18npool/util/i18npool \ configmgr/source/configmgr \ + $(if $(filter TRUE,$(ENABLE_LIBNUMBERTEXT)), \ + framework/util/fwk \ + lingucomponent/source/numbertext/numbertext \ + ) \ )) $(eval $(call gb_CppunitTest_use_ure,svl_qa_cppunit)) diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx index 633e82b75eb2..b744e5a3bfbb 100644 --- a/svl/qa/unit/svl.cxx +++ b/svl/qa/unit/svl.cxx @@ -1383,6 +1383,18 @@ void Test::testUserDefinedNumberFormats() checkPreviewString(aFormatter, sCode, 120, eLang, sExpected); sCode = "[DBNum2][$-0404]General\\ "; checkPreviewString(aFormatter, sCode, 120, eLang, sExpected); +#if ENABLE_LIBNUMBERTEXT + // tdf#115007 - cardinal/ordinal number names/indicators + sCode = "[NatNum12]0"; + sExpected = "one hundred twenty-three"; + checkPreviewString(aFormatter, sCode, 123, eLang, sExpected); + sCode = "[NatNum13]0"; + sExpected = "one hundred twenty-third"; + checkPreviewString(aFormatter, sCode, 123, eLang, sExpected); + sCode = "[NatNum14]0"; + sExpected = "123rd"; + checkPreviewString(aFormatter, sCode, 123, eLang, sExpected); +#endif } { // tdf#105968 engineering format with value rounded up to next magnitude sCode = "##0.00E+00"; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits