Kaydet (Commit) 56a7f308 authored tarafından Mike Kaganski's avatar Mike Kaganski Kaydeden (comit) Eike Rathke

tdf#115007: add NatNum codes for cardinal/ordinal number names/indicators

... based on libnumbertext integrated since commit
f1579d3d.

[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/54186Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarEike Rathke <erack@redhat.com>
üst 5193d7fc
......@@ -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);
......
......@@ -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);
......
......@@ -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;
};
}; }; }; };
......
......@@ -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))
......
......@@ -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";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment