include/xmloff/xmlnumfe.hxx | 1 include/xmloff/xmltoken.hxx | 1 sc/qa/unit/data/ods/tdf152724-Blank-width-char.ods |binary sc/qa/unit/subsequent_export_test4.cxx | 13 + schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 28 +++ xmloff/source/core/xmltoken.cxx | 1 xmloff/source/style/xmlnumfe.cxx | 107 +++++++++--- xmloff/source/style/xmlnumfi.cxx | 103 ++++++++++- xmloff/source/token/tokens.txt | 1 9 files changed, 222 insertions(+), 33 deletions(-)
New commits: commit 74d9da037cac01c5abd768a99b2f948553fbf144 Author: Laurent Balland <laurent.ball...@mailo.fr> AuthorDate: Sat Feb 4 09:29:20 2023 +0100 Commit: Eike Rathke <er...@redhat.com> CommitDate: Fri Aug 25 17:49:17 2023 +0200 tdf#152724 Extend ODF for blank width "_x" Number format code "_x" is currently saved as a text string containing a number of spaces corresponding to the width of character "x". It may be confusing for user if its format code is modified. This change introduces a new XML tag XML_BLANK_WIDTH_CHAR to replace the previous text string if ODF version is extended <number:text> and <number:embedded-text>: the attribute is composed of a string containing the used character and its position in the text string (if position is 0, it is omitted). Several blank code characters are separated by '_'. Replacement blanks in the text string are preserved to enable compatibility. Example: format code "foo"_M_I_N"!"???,???.000_.000"!"_) is saved as: <number:number-style style:name="N173"> <number:text loext:blank-width-char="M3_I6_N7">foo !</number:text> <number:number number:decimal-places="6" number:min-decimal-places="6" number:min-integer-digits="6" loext:max-blank-integer-digits="6" number:grouping="true"> <number:embedded-text number:position="-4" loext:blank-width-char="."> </number:embedded-text> </number:number> <number:text loext:blank-width-char=")1">! </number:text> </number:number-style> Add QA test Change-Id: I785e1a14ecccc900e9fd5af88dd7b743fefcc48c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146582 Tested-by: Jenkins Reviewed-by: Eike Rathke <er...@redhat.com> diff --git a/include/xmloff/xmlnumfe.hxx b/include/xmloff/xmlnumfe.hxx index 43e1814dc26b..7c76e5117b1f 100644 --- a/include/xmloff/xmlnumfe.hxx +++ b/include/xmloff/xmlnumfe.hxx @@ -51,6 +51,7 @@ private: OUString m_sPrefix; SvNumberFormatter* m_pFormatter; OUStringBuffer m_sTextContent; + OUStringBuffer m_sBlankWidthString; bool m_bHasText; std::unique_ptr<SvXMLNumUsedList_Impl> m_pUsedList; std::unique_ptr<LocaleDataWrapper> m_pLocaleData; diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index e8ffd3fedcd5..7771577a453d 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3466,6 +3466,7 @@ namespace xmloff::token { XML_ZEROS_DENOMINATOR_DIGITS, XML_INTEGER_FRACTION_DELIMITER, XML_MAX_BLANK_INTEGER_DIGITS, + XML_BLANK_WIDTH_CHAR, // tdf#115319 XML_REFERENCE_LANGUAGE, diff --git a/sc/qa/unit/data/ods/tdf152724-Blank-width-char.ods b/sc/qa/unit/data/ods/tdf152724-Blank-width-char.ods new file mode 100644 index 000000000000..4716d4be5355 Binary files /dev/null and b/sc/qa/unit/data/ods/tdf152724-Blank-width-char.ods differ diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx index 74313ef67c27..357ac567575f 100644 --- a/sc/qa/unit/subsequent_export_test4.cxx +++ b/sc/qa/unit/subsequent_export_test4.cxx @@ -1480,6 +1480,19 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testSecondsWithoutTruncateAndDecimals) lcl_TestNumberFormat(*getScDoc(), "[SS].00"); } +CPPUNIT_TEST_FIXTURE(ScExportTest4, testBlankWidthCharacter) +{ + createScDoc("ods/tdf152724-Blank-width-char.ods"); + + // save to ODS and reload + saveAndReload("calc8"); + lcl_TestNumberFormat(*getScDoc(), "[>0]_-?0;[<0]-?0;_-?0;@"); + + // save to XLSX and reload + saveAndReload("Calc Office Open XML"); + lcl_TestNumberFormat(*getScDoc(), "_-?0;-?0;_-?0;@"); +} + CPPUNIT_TEST_FIXTURE(ScExportTest4, testEmbeddedTextInDecimal) { createScDoc("xlsx/embedded-text-in-decimal.xlsx"); diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index b1a344e7bf4a..b7ad4b8a1a7c 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -2047,6 +2047,14 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. <rng:empty/> </rng:element> </rng:define> + <rng:define name="number-text"> + <rng:element name="number:text"> + <rng:optional> + <rng:ref name="number-text-attlist"/> + </rng:optional> + <rng:text/> + </rng:element> + </rng:define> </rng:include> @@ -2745,6 +2753,26 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:optional> </rng:define> + <rng:define name="number-embedded-text-attlist" combine="interleave"> + <!-- TODO no proposal, --> + <rng:optional> + <rng:attribute name="loext:blank-width-char"> + <rng:ref name="string"/> + </rng:attribute> + </rng:optional> + </rng:define> + + <!-- TODO no proposal, --> + <rng:define name="number-text-attlist"> + <rng:interleave> + <rng:optional> + <rng:attribute name="loext:blank-width-char"> + <rng:ref name="string"/> + </rng:attribute> + </rng:optional> + </rng:interleave> + </rng:define> + <!-- TODO no proposal --> <rng:define name="table-data-pilot-level-attlist" combine="interleave"> <rng:optional> diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 8127996aa1c9..4f6f2223e721 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3471,6 +3471,7 @@ namespace xmloff::token { TOKEN( "zeros-denominator-digits", XML_ZEROS_DENOMINATOR_DIGITS ), TOKEN( "integer-fraction-delimiter", XML_INTEGER_FRACTION_DELIMITER ), TOKEN( "max-blank-integer-digits", XML_MAX_BLANK_INTEGER_DIGITS ), + TOKEN( "blank-width-char", XML_BLANK_WIDTH_CHAR ), // for optional language-dependent reference formats TOKEN( "reference-language", XML_REFERENCE_LANGUAGE ), diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index fb767dc3a10d..67675cf22ab3 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -66,9 +66,10 @@ struct SvXMLEmbeddedTextEntry sal_uInt16 nSourcePos; // position in NumberFormat (to skip later) sal_Int32 nFormatPos; // resulting position in embedded-text element OUString aText; + bool isBlankWidth; // "_x" - SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, OUString aT ) : - nSourcePos(nSP), nFormatPos(nFP), aText(std::move(aT)) {} + SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, OUString aT, bool bBW = false ) : + nSourcePos(nSP), nFormatPos(nFP), aText(std::move(aT)), isBlankWidth( bBW ) {} }; } @@ -323,6 +324,16 @@ void SvXMLNumFmtExport::FinishTextElement_Impl(bool bUseExtensionNS) { if ( m_bHasText ) { + if ( !m_sBlankWidthString.isEmpty() ) + { + // Export only for 1.3 with extensions and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_013 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 )) + { + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_BLANK_WIDTH_CHAR, + m_sBlankWidthString.makeStringAndClear() ); + } + } sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER; SvXMLElementExport aElem( m_rExport, nNS, XML_TEXT, true, false ); @@ -502,6 +513,36 @@ void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar ) } } +namespace { +void lcl_WriteBlankWidthString( std::u16string_view rBlankWidthChar, OUStringBuffer& rBlankWidthString, OUStringBuffer& rTextContent ) +{ + // export "_x" + if ( rBlankWidthString.isEmpty() ) + { + rBlankWidthString.append( rBlankWidthChar ); + if ( !rTextContent.isEmpty() ) + { + // add position in rTextContent + rBlankWidthString.append( rTextContent.getLength() ); + } + } + else + { + // add "_" as separator if there are several blank width char + rBlankWidthString.append( "_" ); + rBlankWidthString.append( rBlankWidthChar ); + rBlankWidthString.append( rTextContent.getLength() ); + } + // for previous versions, turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat + if ( !rBlankWidthChar.empty() ) + { + OUString aBlanks; + SvNumberformat::InsertBlanks( aBlanks, 0, rBlankWidthChar[0] ); + rTextContent.append( aBlanks ); + } +} +} + void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals ) { FinishTextElement_Impl(); @@ -553,28 +594,45 @@ void SvXMLNumFmtExport::WriteIntegerElement_Impl( void SvXMLNumFmtExport::WriteEmbeddedEntries_Impl( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) { auto nEntryCount = rEmbeddedEntries.size(); + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); for (decltype(nEntryCount) nEntry=0; nEntry < nEntryCount; ++nEntry) { - const SvXMLEmbeddedTextEntry *const pObj = &rEmbeddedEntries[nEntry]; + const SvXMLEmbeddedTextEntry* pObj = &rEmbeddedEntries[nEntry]; // position attribute // position == 0 is between first integer digit and decimal separator // position < 0 is inside decimal part m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION, OUString::number( pObj->nFormatPos ) ); - SvXMLElementExport aChildElem( m_rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT, - true, false ); // text as element content - OUStringBuffer aContent( pObj->aText ); - while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos ) + OUStringBuffer aContent; + OUStringBuffer aBlankWidthString; + do { - // The array can contain several elements for the same position in the number - // (for example, literal text and space from underscores). They must be merged - // into a single embedded-text element. - aContent.append(rEmbeddedEntries[nEntry+1].aText); + pObj = &rEmbeddedEntries[nEntry]; + if ( pObj->isBlankWidth ) + { + // (#i20396# the spaces may also be in embedded-text elements) + lcl_WriteBlankWidthString( pObj->aText, aBlankWidthString, aContent ); + } + else + { + // The array can contain several elements for the same position in the number. + // Literal texts are merged into a single embedded-text element. + aContent.append( pObj->aText ); + } ++nEntry; } + while ( nEntry < nEntryCount + && rEmbeddedEntries[nEntry].nFormatPos == pObj->nFormatPos ); + --nEntry; + + // Export only for 1.3 with extensions and later. + if ( !aBlankWidthString.isEmpty() && eVersion > SvtSaveOptions::ODFSVER_013 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) ) + m_rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_BLANK_WIDTH_CHAR, aBlankWidthString.makeStringAndClear() ); + SvXMLElementExport aChildElem( m_rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT, + true, false ); m_rExport.Characters( aContent.makeStringAndClear() ); } } @@ -1196,13 +1254,13 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt aAttr.Style ); } + SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); if ( !aAttr.Spellout.isEmpty() ) { const bool bWriteSpellout = aAttr.Format.isEmpty(); assert(bWriteSpellout); // mutually exclusive // Export only for 1.2 and later with extensions - SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); // Also ensure that duplicated transliteration-language and // transliteration-country attributes never escape into the wild with // releases. @@ -1389,7 +1447,6 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt } // collect strings for embedded-text (must be known before number element is written) - SvtSaveOptions::ODFSaneDefaultVersion eVersion = m_rExport.getSaneDefaultVersion(); bool bAllowEmbedded = ( nFmtType == SvNumFormatType::ALL || nFmtType == SvNumFormatType::NUMBER || nFmtType == SvNumFormatType::CURRENCY || // Export only for 1.x with extensions @@ -1429,18 +1486,25 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element OUString aEmbeddedStr; + bool bSaveBlankWidthSymbol = false; if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT ) { aEmbeddedStr = *pElemStr; } else if (pElemStr->getLength() >= 2) { - SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] ); + if ( eVersion > SvtSaveOptions::ODFSVER_013 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) ) + { + aEmbeddedStr = pElemStr->copy( 1, 1 ); + bSaveBlankWidthSymbol = true; + } + else // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat + SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] ); } sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed; aEmbeddedEntries.push_back( - SvXMLEmbeddedTextEntry(nPos, nEmbedPos, aEmbeddedStr)); + SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr, bSaveBlankWidthSymbol )); } break; } @@ -1505,13 +1569,12 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt case NF_SYMBOLTYPE_BLANK: if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) { - // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat - // (#i20396# the spaces may also be in embedded-text elements) - - OUString aBlanks; - if (pElemStr->getLength() >= 2) - SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] ); - AddToTextElement_Impl( aBlanks ); + if ( pElemStr->getLength() == 2 ) + { + OUString aBlankWidthChar = pElemStr->copy( 1 ); + lcl_WriteBlankWidthString( aBlankWidthChar, m_sBlankWidthString, m_sTextContent ); + m_bHasText = true; + } } break; case NF_KEY_GENERAL : diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index e43e732a4ba8..f9f9bce5f675 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -123,6 +123,7 @@ class SvXMLNumFmtElementContext : public SvXMLImportContext bool bLong; bool bTextual; OUString sCalendar; + OUString sBlankWidthString; public: SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nElement, @@ -134,7 +135,7 @@ public: virtual void SAL_CALL characters( const OUString& rChars ) override; virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; - void AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent ); + void AddEmbeddedElement( sal_Int32 nFormatPos, std::u16string_view rContent, std::u16string_view rBlankWidthString ); }; class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext @@ -142,6 +143,7 @@ class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext SvXMLNumFmtElementContext& rParent; OUStringBuffer aContent; sal_Int32 nTextPosition; + OUString aBlankWidthString; public: SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_Int32 nElement, @@ -461,6 +463,11 @@ SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rIm if (::sax::Converter::convertNumber( nAttrVal, aIter.toView() )) nTextPosition = nAttrVal; } + else if ( aIter.getToken() == XML_ELEMENT(LO_EXT, XML_BLANK_WIDTH_CHAR) + || aIter.getToken() == XML_ELEMENT(NUMBER, XML_BLANK_WIDTH_CHAR) ) + { + aBlankWidthString = aIter.toString(); + } else XMLOFF_WARN_UNKNOWN("xmloff", aIter); } @@ -473,7 +480,7 @@ void SvXMLNumFmtEmbeddedTextContext::characters( const OUString& rChars ) void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32 ) { - rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() ); + rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear(), aBlankWidthString ); } static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent ) @@ -778,6 +785,10 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, case XML_ELEMENT(NUMBER, XML_CALENDAR): sCalendar = aIter.toString(); break; + case XML_ELEMENT(NUMBER, XML_BLANK_WIDTH_CHAR): + case XML_ELEMENT(LO_EXT, XML_BLANK_WIDTH_CHAR): + sBlankWidthString = aIter.toString(); + break; default: XMLOFF_WARN_UNKNOWN("xmloff", aIter); } @@ -856,15 +867,83 @@ void SvXMLNumFmtElementContext::characters( const OUString& rChars ) aContent.append( rChars ); } -void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent ) +namespace { +void lcl_InsertBlankWidthChars( std::u16string_view rBlankWidthString, OUStringBuffer& rContent ) { - if (rContent.isEmpty()) - return; + sal_Int32 nShiftPosition = 1; // rContent starts with a quote + const size_t nLenBlank = rBlankWidthString.size(); + for ( size_t i = 0 ; i < nLenBlank ; i++ ) + { + sal_Unicode nChar = rBlankWidthString[ i ]; + OUString aBlanks; + SvNumberformat::InsertBlanks( aBlanks, 0, nChar ); + sal_Int32 nPositionContent = 0; + if ( ++i < nLenBlank ) + { + sal_Int32 nNext = rBlankWidthString.find( '_', i ); + if ( static_cast<sal_Int32>( i ) < nNext ) + { + nPositionContent = o3tl::toInt32( rBlankWidthString.substr( i, nNext - i ) ); + i = nNext; + } + else + nPositionContent = o3tl::toInt32( rBlankWidthString.substr( i ) ); + } + nPositionContent += nShiftPosition; + if ( nPositionContent >= 0 ) + { + rContent.remove( nPositionContent, aBlanks.getLength() ); + if ( nPositionContent >= 1 && rContent[ nPositionContent-1 ] == '\"' ) + { + nPositionContent--; + rContent.insert( nPositionContent, nChar ); + rContent.insert( nPositionContent, '_' ); + } + else + { + rContent.insert( nPositionContent, '\"' ); + rContent.insert( nPositionContent, nChar ); + rContent.insert( nPositionContent, "\"_" ); + nShiftPosition += 2; + } + // rContent length was modified: remove blanks, add "_x" + nShiftPosition += 2 - aBlanks.getLength(); + } + } + // remove empty string at the end of rContent + if ( std::u16string_view( rContent ).substr( rContent.getLength() - 2 ) == u"\"\"" ) + { + sal_Int32 nLen = rContent.getLength(); + if ( nLen >= 3 && rContent[ nLen-3 ] != '\\' ) + rContent.truncate( nLen - 2 ); + } +} +} - auto iterPair = aNumInfo.m_EmbeddedElements.emplace(nFormatPos, rContent); +void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, std::u16string_view rContentEmbedded, std::u16string_view rBlankWidthString ) +{ + if ( rContentEmbedded.empty() ) + return; + OUStringBuffer aContentEmbedded( rContentEmbedded ); + // #107805# always quote embedded strings - even space would otherwise + // be recognized as thousands separator in French. + aContentEmbedded.insert( 0, '"' ); + aContentEmbedded.append( '"' ); + if ( !rBlankWidthString.empty() ) + lcl_InsertBlankWidthChars( rBlankWidthString, aContentEmbedded ); + + auto iterPair = aNumInfo.m_EmbeddedElements.emplace( nFormatPos, aContentEmbedded.toString() ); if (!iterPair.second) + { // there's already an element at this position - append text to existing element - iterPair.first->second += rContent; + if ( iterPair.first->second.endsWith( "\"" ) && aContentEmbedded[ 0 ] == '"' ) + { // remove double quote + iterPair.first->second = OUString::Concat( iterPair.first->second.subView( 0, iterPair.first->second.getLength() - 1 ) ) + + aContentEmbedded.subView( 1, aContentEmbedded.getLength() - 1 ); + } + else + iterPair.first->second += aContentEmbedded; + } } void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) @@ -889,6 +968,11 @@ void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) if ( !aContent.isEmpty() ) { lcl_EnquoteIfNecessary( aContent, rParent ); + if ( !sBlankWidthString.isEmpty() ) + { + lcl_InsertBlankWidthChars( sBlankWidthString, aContent ); + sBlankWidthString = ""; + } rParent.AddToCode( aContent ); aContent.setLength(0); } @@ -1818,10 +1902,7 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) sal_Int32 nInsertPos = nZeroPos - nFormatPos; if ( nInsertPos >= 0 ) { - // #107805# always quote embedded strings - even space would otherwise - // be recognized as thousands separator in French. - - aNumStr.insert(nInsertPos, OUString::Concat("\"") + it.second + "\""); + aNumStr.insert( nInsertPos, it.second ); } } } diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index e8022d14dfce..469d03645276 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -3227,6 +3227,7 @@ zeros-numerator-digits zeros-denominator-digits integer-fraction-delimiter max-blank-integer-digits +blank-width-char reference-language newline creator-initials