i18npool/source/localedata/data/hu_HU.xml | 102 +++++++++++++++ i18npool/source/nativenumber/nativenumbersupplier.cxx | 14 -- include/svl/zformat.hxx | 7 + svl/qa/unit/svl.cxx | 9 + svl/source/numbers/zformat.cxx | 119 +++++++++++++++--- 5 files changed, 229 insertions(+), 22 deletions(-)
New commits: commit ee81a4cd7778e3733b8237380b996fd3e4fee77b Author: László Németh <[email protected]> Date: Tue Jun 26 23:54:41 2018 +0200 locale hu_HU.xml: add date formats with suffixes, articles and spelling out using the new NatNum12 modifier to support common "in", "on", "from", "to", etc. date suffix variants, "dash-free" spell out format of years of the new Hungarian orthographical reform, and months with articles. For example, "in 2018" is "2018-ban", "in 2019" is "2019-ben" in Hungarian because of "vowel harmony", the word stem dependent fluctuation of the suffix variants, a frequent linguistic feature of other agglutinative languages, too, including Estonian, Finnish and Turkish. Note: some of the new date formats will work correctly only with the upcoming update of the external libnumbertext. Note 2: add also alternative (real) abbreviated month names, because the default abbreviated month names are Roman numbers. Change-Id: Ibb33ff6a627b8e27fd02388653e3b33ebd446a10 Reviewed-on: https://gerrit.libreoffice.org/55637 Tested-by: Jenkins Reviewed-by: László Németh <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/56530 Reviewed-by: Eike Rathke <[email protected]> diff --git a/i18npool/source/localedata/data/hu_HU.xml b/i18npool/source/localedata/data/hu_HU.xml index c51795aa3b19..406ef9b124d5 100644 --- a/i18npool/source/localedata/data/hu_HU.xml +++ b/i18npool/source/localedata/data/hu_HU.xml @@ -169,6 +169,108 @@ <FormatElement msgid="DateFormatskey21" default="false" type="medium" usage="DATE" formatindex="38"> <FormatCode>WW.</FormatCode> </FormatElement> + <FormatElement msgid="DateFormatskey22" default="false" type="long" usage="DATE" formatindex="60"> + <FormatCode>[NatNum12 MMMM=abbreviation]YYYY". "MMMM D.</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey23" default="false" type="long" usage="DATE" formatindex="61"> + <FormatCode>[NatNum12 D=possessive]YYYY". "MMMM D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey24" default="false" type="long" usage="DATE" formatindex="62"> + <FormatCode>[NatNum12 D=possessive-superessive]YYYY". "MMMM D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey25" default="false" type="long" usage="DATE" formatindex="63"> + <FormatCode>[NatNum12 D=possessive-ablative]YYYY". "MMMM D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey26" default="false" type="long" usage="DATE" formatindex="64"> + <FormatCode>[NatNum12 D=possessive-terminative]YYYY". "MMMM D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey27" default="false" type="long" usage="DATE" formatindex="65"> + <FormatCode>[NatNum12 D=possessive-adjective]YYYY". "MMMM D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey28" default="false" type="long" usage="DATE" formatindex="66"> + <FormatCode>[NatNum12 D=possessive-superessive,NNN=superessive]YYYY". "MMMM D, NNN</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey29" default="false" type="medium" usage="DATE" formatindex="67"> + <FormatCode>[NatNum12 D=possessive]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey30" default="false" type="medium" usage="DATE" formatindex="68"> + <FormatCode>[NatNum12 D=possessive-superessive]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey31" default="false" type="medium" usage="DATE" formatindex="69"> + <FormatCode>[NatNum12 D=possessive-ablative]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey32" default="false" type="medium" usage="DATE" formatindex="70"> + <FormatCode>[NatNum12 D=possessive-terminative]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey33" default="false" type="long" usage="DATE" formatindex="71"> + <FormatCode>[NatNum12 MMMM=article,D=possessive-adjective]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey34" default="false" type="medium" usage="DATE" formatindex="72"> + <FormatCode>[NatNum12 MMMM=capitalize article,D=possessive-adjective]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey35" default="false" type="long" usage="DATE" formatindex="73"> + <FormatCode>[NatNum12 MMMM=article,D=adjective]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey36" default="false" type="medium" usage="DATE" formatindex="74"> + <FormatCode>[NatNum12 MMMM=capitalize article,D=adjective]MMMM" "D</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey37" default="false" type="long" usage="DATE" formatindex="75"> + <FormatCode>[NatNum12 MMMM=article]MMMM"i"</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey38" default="false" type="medium" usage="DATE" formatindex="76"> + <FormatCode>[NatNum12 MMMM=capitalize article]MMMM"i"</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey39" default="false" type="medium" usage="DATE" formatindex="77"> + <FormatCode>[NatNum12 superessive]NNN</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey40" default="false" type="medium" usage="DATE" formatindex="79"> + <FormatCode>[NatNum12 ablative]NNN</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey41" default="false" type="medium" usage="DATE" formatindex="80"> + <FormatCode>[NatNum12 terminative]NNN</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey42" default="false" type="medium" usage="DATE" formatindex="81"> + <FormatCode>[NatNum12 inessive]YYYY</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey43" default="false" type="medium" usage="DATE" formatindex="82"> + <FormatCode>[NatNum12 ablative]YYYY</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey44" default="false" type="medium" usage="DATE" formatindex="83"> + <FormatCode>[NatNum12 article]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey45" default="false" type="medium" usage="DATE" formatindex="84"> + <FormatCode>[NatNum12 capitalize article]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey46" default="false" type="medium" usage="DATE" formatindex="85"> + <FormatCode>[NatNum12 inessive]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey47" default="false" type="medium" usage="DATE" formatindex="86"> + <FormatCode>[NatNum12 article inessive]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey48" default="false" type="medium" usage="DATE" formatindex="87"> + <FormatCode>[NatNum12 capitalize article inessive]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey49" default="false" type="medium" usage="DATE" formatindex="88"> + <FormatCode>[NatNum12 ablative]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey50" default="false" type="medium" usage="DATE" formatindex="89"> + <FormatCode>[NatNum12 article ablative]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey51" default="false" type="medium" usage="DATE" formatindex="90"> + <FormatCode>[NatNum12 capitalize article ablative]MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey52" default="false" type="medium" usage="DATE" formatindex="91"> + <FormatCode>[NatNum12 MMMM=possessive-inessive]YYYY" "MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey53" default="false" type="medium" usage="DATE" formatindex="92"> + <FormatCode>[NatNum12 MMMM=possessive-ablative]YYYY" "MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey54" default="false" type="medium" usage="DATE" formatindex="93"> + <FormatCode>[NatNum12 MMMM=possessive-terminative]YYYY" "MMMM</FormatCode> + </FormatElement> + <FormatElement msgid="DateFormatskey55" default="false" type="medium" usage="DATE" formatindex="94"> + <FormatCode>[NatNum12 ordinal year]YYYY</FormatCode> + </FormatElement> <FormatElement msgid="TimeFormatskey1" default="true" type="short" usage="TIME" formatindex="39"> <FormatCode>HH:MM</FormatCode> </FormatElement> commit b435767f8953702bb5fe01edae3ad0abfbd2cacc Author: László Németh <[email protected]> Date: Thu Jun 7 14:26:42 2018 +0200 tdf#115007 add NatNum12 formatting to dates to support variants of preposition, suffixation, article or their combinations. For example, Catalan "de març"/"d'abril", English "1st of May"/"First of May", Hungarian "május 1-je/május 2-a" (May 1/2) or Turkish "2018'de/2019'da" (in 2018/2019) usage can be automatic in templates and mail merge. When the date format contains more than a date keyword, it needs to specify in the NatNum12 argument which date element has got special formatting (described by libnumbertext formatting codes, and an optional initial capitalize/upper/title argument): '[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=title year,D=capitalize 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, according to the possible language requirements. Note 2: l10n date formats can use the new NatNum12 date formats from formatindex=60, 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 <[email protected]> Reviewed-by: László Németh <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/55767 Tested-by: Jenkins Reviewed-by: Eike Rathke <[email protected]> diff --git a/i18npool/source/nativenumber/nativenumbersupplier.cxx b/i18npool/source/nativenumber/nativenumbersupplier.cxx index 5fb34c993167..8c3698216b81 100644 --- a/i18npool/source/nativenumber/nativenumbersupplier.cxx +++ b/i18npool/source/nativenumber/nativenumbersupplier.cxx @@ -588,10 +588,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()); @@ -606,17 +604,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 ffa66ae80b74..205af97f1bc3 100644 --- a/svl/qa/unit/svl.cxx +++ b/svl/qa/unit/svl.cxx @@ -1403,6 +1403,15 @@ void Test::testUserDefinedNumberFormats() sCode = "[NatNum12 upper ordinal-number]0"; sExpected = "12345TH"; checkPreviewString(aFormatter, sCode, 12345, 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 a863b984891d..66f54867cf5c 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 )); @@ -5386,6 +5439,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 { _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
