summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLászló Németh <nemeth@numbertext.org>2018-06-07 14:26:42 +0200
committerLászló Németh <nemeth@numbertext.org>2018-06-13 19:49:47 +0200
commit958c23246a3606f2cb33ad5c136127f951bbbc69 (patch)
tree425bfaa265d3e7700ffa22703b1a12b15cc94e85
parentcc46e7b9c75ddbcaaefde5f396ba76b0b866fa58 (diff)
tdf#115007 NatNum12 "spell out" formats in dates
to support variants of preposition, suffixation, article or their combination. For example, Catalan "de març"/"d'abril", English "1st of May"/"First of May" or Hungarian "május 1-je/május 2-a". When the date format contains more than a date keyword, it needs to specify in NatNum12 argument which date element needs special formatting by using libnumbertext: '[NatNum12 ordinal-number]D' -> "1st" '[NatNum12 D=ordinal-number]D" of "MMMM' -> "1st of April" '[NatNum12 D=ordinal]D" of "MMMM' -> "first of April" '[NatNum12 YYYY=year,D=ordinal]D" of "MMMM", "YYYY' -> "first of April, nineteen ninety" Note: set only for YYYY, MMMM, M, DDDD, D and NNN/AAAA in date formats. It's possible to extend this for other keywords and date + time combinations, as required. Note 2: default l10n date formats can use the new NatNum12 date formats, see FormatElement in i18npool/source/localedata/ XML files and FormatElement specification: https://opengrok.libreoffice.org/xref/core/i18npool/source/localedata/data/locale.dtd#223 Change-Id: I598849f1492f4012e83cef9293773badbff16206 Reviewed-on: https://gerrit.libreoffice.org/55613 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r--i18npool/source/nativenumber/nativenumbersupplier.cxx14
-rw-r--r--include/svl/zformat.hxx7
-rw-r--r--svl/qa/unit/svl.cxx9
-rw-r--r--svl/source/numbers/zformat.cxx119
4 files changed, 127 insertions, 22 deletions
diff --git a/i18npool/source/nativenumber/nativenumbersupplier.cxx b/i18npool/source/nativenumber/nativenumbersupplier.cxx
index 5c5942ed987f..b8cc35dcfef4 100644
--- a/i18npool/source/nativenumber/nativenumbersupplier.cxx
+++ b/i18npool/source/nativenumber/nativenumbersupplier.cxx
@@ -587,10 +587,8 @@ OUString getNumberText(const Locale& rLocale, const OUString& rNumberString,
break;
}
- if (count == 0)
- return rNumberString;
-
- OUString aNumberStr = sBuf.makeStringAndClear();
+ // Handle also month and day names for NatNum12 date formatting
+ const OUString& rNumberStr = (count == 0) ? rNumberString : sBuf.makeStringAndClear();
// Guard the static variables below.
osl::MutexGuard aGuard( theNatNumMutex::get());
@@ -605,17 +603,17 @@ OUString getNumberText(const Locale& rLocale, const OUString& rNumberString,
// 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& rItems = aBuff[rNumberStr];
auto& rItem = rItems[numbertext_prefix + aLoc];
if (rItem.isEmpty())
{
- rItem = xNumberText->getNumberText(numbertext_prefix + aNumberStr, rLocale);
+ rItem = xNumberText->getNumberText(numbertext_prefix + rNumberStr, rLocale);
// use number at missing number to text conversion
if (rItem.isEmpty())
- rItem = aNumberStr;
+ rItem = rNumberStr;
}
OUString sResult = rItem;
- if (i < len)
+ if (i != 0 && i < len)
sResult += rNumberString.copy(i);
return sResult;
}
diff --git a/include/svl/zformat.hxx b/include/svl/zformat.hxx
index 6357be2cea9d..dfab60c4beb3 100644
--- a/include/svl/zformat.hxx
+++ b/include/svl/zformat.hxx
@@ -699,6 +699,7 @@ private:
// transliterate according to NativeNumber
SVL_DLLPRIVATE OUString impTransliterateImpl(const OUString& rStr, const SvNumberNatNum& rNum) const;
SVL_DLLPRIVATE void impTransliterateImpl(OUStringBuffer& rStr, const SvNumberNatNum& rNum) const;
+ SVL_DLLPRIVATE OUString impTransliterateImpl(const OUString& rStr, const SvNumberNatNum& rNum, sal_uInt16 nDateKey) const;
OUString impTransliterate(const OUString& rStr, const SvNumberNatNum& rNum) const
{
@@ -712,6 +713,12 @@ private:
impTransliterateImpl(rStr, rNum);
}
}
+
+ OUString impTransliterate(const OUString& rStr, const SvNumberNatNum& rNum, sal_uInt16 nDateKey) const
+ {
+ return rNum.IsComplete() ? impTransliterateImpl(rStr, rNum, nDateKey) : rStr;
+ }
+
};
#endif // INCLUDED_SVL_ZFORMAT_HXX
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 45bff9ef2ca1..26b2f6a41588 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -1394,6 +1394,15 @@ void Test::testUserDefinedNumberFormats()
sCode = "[NatNum12 ordinal-number]0";
sExpected = "123rd";
checkPreviewString(aFormatter, sCode, 123, eLang, sExpected);
+ sCode = "[NatNum12 D=ordinal-number]D\" of \"MMMM";
+ sExpected = "2nd of January";
+ checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
+ sCode = "[NatNum12 D=ordinal-number,YYYY=year]D\" of \"MMMM\", \"YYYY";
+ sExpected = "2nd of January, nineteen hundred";
+ checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
+ sCode = "[NatNum12 YYYY=year, D=ordinal]D\" of \"MMMM\", \"YYYY";
+ sExpected = "second of January, nineteen hundred";
+ checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
#endif
}
{ // tdf#105968 engineering format with value rounded up to next magnitude
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index 1bc63e4ecfec..fd482cc27f2e 100644
--- a/svl/source/numbers/zformat.cxx
+++ b/svl/source/numbers/zformat.cxx
@@ -3560,7 +3560,23 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
const sal_uInt16 nCnt = NumFor[nIx].GetCount();
sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
- OUString aYear;
+ OUString aStr;
+
+ // NatNum12: if the date format contains more than a date
+ // field, it needs to specify in NatNum12 argument
+ // which date element needs special formatting:
+ //
+ // '[NatNum12 ordinal-number]D' -> "1st"
+ // '[NatNum12 D=ordinal-number]D" of "MMMM' -> "1st of April"
+ // '[NatNum12 D=ordinal]D" of "MMMM' -> "first of April"
+ // '[NatNum12 YYYY=year,D=ordinal]D" of "MMMM", "YYYY' -> "first of April, nineteen ninety"
+ //
+ // Note: set only for YYYY, MMMM, M, DDDD, D and NNN/AAAA in date formats.
+ // XXX It's possible to extend this for other keywords and date + time
+ // combinations, as required.
+
+ bool bUseSpellout = NatNumTakesParameters(nNatNum) &&
+ (nCnt == 1 || NumFor[nIx].GetNatNum().GetParams().indexOf('=') > -1);
for (sal_uInt16 i = 0; i < nCnt; i++)
{
@@ -3594,7 +3610,14 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
sBuff.append(rInfo.sStrArray[i]);
break;
case NF_KEY_M: // M
- sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_MONTH, nNatNum ));
+ aStr = rCal.getDisplayString( CalendarDisplayCode::SHORT_MONTH, nNatNum );
+ // NatNum12: support variants of preposition, suffixation or article
+ // for example, Catalan "de març", but "d'abril" etc.
+ if ( bUseSpellout )
+ {
+ aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i]);
+ }
+ sBuff.append(aStr);
break;
case NF_KEY_MM: // MM
sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_MONTH, nNatNum ));
@@ -3605,9 +3628,19 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
nNatNum));
break;
case NF_KEY_MMMM: // MMMM
- sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
+ // NatNum12: support variants of preposition, suffixation or article
+ // Note: result of the "spell out" conversion can depend from the optional
+ // PartitiveMonths or GenitiveMonths defined in the locale data,
+ // see description of ImpUseMonthCase(), and locale data in
+ // i18npool/source/localedata/data/ and libnumbertext
+ aStr = rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
- nNatNum));
+ nNatNum);
+ if ( bUseSpellout )
+ {
+ aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i]);
+ }
+ sBuff.append(aStr);
break;
case NF_KEY_MMMMM: // MMMMM
sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
@@ -3621,7 +3654,13 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum ));
break;
case NF_KEY_D: // D
- sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum ));
+ aStr = rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum );
+ // NatNum12: support variants of preposition, suffixation or article
+ if ( bUseSpellout )
+ {
+ aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i]);
+ }
+ sBuff.append(aStr);
break;
case NF_KEY_DD: // DD
sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum ));
@@ -3642,7 +3681,13 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
{
SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
}
- sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
+ aStr = rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ // NatNum12: support variants of preposition, suffixation or article
+ if ( bUseSpellout )
+ {
+ aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i]);
+ }
+ sBuff.append(aStr);
if ( bOtherCalendar )
{
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
@@ -3674,23 +3719,25 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
{
sBuff.append('-');
}
- aYear = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum );
- if (aYear.getLength() < 4)
+ aStr = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum );
+ if (aStr.getLength() < 4)
{
using namespace comphelper::string;
// Ensure that year consists of at least 4 digits, so it
// can be distinguished from 2 digits display and edited
// without suddenly being hit by the 2-digit year magic.
OUStringBuffer aBuf;
- padToLength(aBuf, 4 - aYear.getLength(), '0');
+ padToLength(aBuf, 4 - aStr.getLength(), '0');
impTransliterate(aBuf, NumFor[nIx].GetNatNum());
- aBuf.append(aYear);
- sBuff.append(aBuf);
+ aBuf.append(aStr);
+ aStr = aBuf.makeStringAndClear();
}
- else
+ // NatNum12: support variants of preposition, suffixation or article
+ if ( bUseSpellout )
{
- sBuff.append(aYear);
+ aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i]);
}
+ sBuff.append(aStr);
if ( bOtherCalendar )
{
SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
@@ -3709,7 +3756,13 @@ bool SvNumberformat::ImpGetDateOutput(double fNumber,
break;
case NF_KEY_NNN: // NNN
case NF_KEY_AAAA: // AAAA
- sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
+ aStr = rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ // NatNum12: support variants of preposition, suffixation or article
+ if ( bUseSpellout )
+ {
+ aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i]);
+ }
+ sBuff.append(aStr);
break;
case NF_KEY_NNNN: // NNNN
sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
@@ -5392,6 +5445,44 @@ void SvNumberformat::impTransliterateImpl(OUStringBuffer& rStr,
rStr.append(sTemp);
}
+OUString SvNumberformat::impTransliterateImpl(const OUString& rStr,
+ const SvNumberNatNum& rNum,
+ const sal_uInt16 nDateKey) const
+{
+ // no KEYWORD=argument list in NatNum12
+ if (rNum.GetParams().indexOf('=') == -1)
+ return impTransliterateImpl( rStr, rNum);
+
+ const NfKeywordTable & rKeywords = rScan.GetKeywords();
+
+ // Format: KEYWORD=numbertext_prefix, ..., for example:
+ // [NatNum12 YYYY=title ordinal,MMMM=article, D=ordinal-number]
+ sal_Int32 nField = -1;
+ do
+ {
+ nField = rNum.GetParams().indexOf(rKeywords[nDateKey] + "=", ++nField);
+ }
+ while (nField != -1 && nField != 0 &&
+ !(rNum.GetParams()[nField - 1] == ',' ||
+ rNum.GetParams()[nField - 1] == ' '));
+
+ // no format specified for actual keyword
+ if (nField == -1)
+ return rStr;
+
+ sal_Int32 nKeywordLen = rKeywords[nDateKey].getLength() + 1;
+ sal_Int32 nFieldEnd = rNum.GetParams().indexOf(',', nField);
+
+ if (nFieldEnd == -1)
+ nFieldEnd = rNum.GetParams().getLength();
+
+ css::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() );
+
+ return GetFormatter().GetNatNum()->getNativeNumberStringParams(
+ rStr, aLocale, rNum.GetNatNum(),
+ rNum.GetParams().copy(nField + nKeywordLen, nFieldEnd - nField - nKeywordLen));
+}
+
void SvNumberformat::GetNatNumXml( css::i18n::NativeNumberXmlAttributes2& rAttr,
sal_uInt16 nNumFor ) const
{