diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index 497e92890bc7..dd0e21fa192f 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -66,10 +67,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -79,6 +82,18 @@ #include #include +// L10nMapper bits to split out ... +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + using ::com::sun::star::beans::XPropertySetInfo; using namespace ::com::sun::star; @@ -457,6 +472,162 @@ void SvXMLImport::InitCtor_() } } +namespace { + + class L10nMapper : public cppu::WeakImplHelper + { + std::unordered_map maMap; + + L10nMapper() { } + virtual ~L10nMapper() override {} + + public: + static css::uno::Reference< XMap > load(const uno::Reference &xStorage) + { + try { + OUString streamName = u"l10n"_ustr; + if (xStorage && xStorage->isStreamElement(streamName)) + { + auto xIn = xStorage->openStreamElement(streamName, css::embed::ElementModes::READ|css::embed::ElementModes::NOCREATE); + if (!xIn) + return css::uno::Reference< XMap >(); + + auto xInStrm = uno::Reference(xIn, UNO_QUERY_THROW); + + rtl::Reference< L10nMapper > pMap = new L10nMapper(); + + auto xContext = comphelper::getProcessComponentContext(); + + Reference< XTextInputStream2 > xTextStrm; + xTextStrm = css::io::TextInputStream::create(xContext); + xTextStrm->setInputStream(xInStrm); + xTextStrm->setEncoding(u"utf8"_ustr); + + ::std::vector aLocales; + if (comphelper::LibreOfficeKit::isActive()) + aLocales = comphelper::LibreOfficeKit::getLanguageTag().getFallbackStrings(true); + else + aLocales = LanguageTag(css::uno::Reference< css::lang::XLocalizable >( + css::configuration::theDefaultProvider::get(xContext), + css::uno::UNO_QUERY_THROW)->getLocale()).getFallbackStrings(true); + OUString aLocale; // cached best locale match + + // Format is \nlocale\t\n\n\n + OUString aKeyString; + size_t nLine = 0; + while (!xTextStrm->isEOF()) + { + OUString aStr = xTextStrm->readLine(); + nLine++; + if (aStr.getLength() < 1 || aStr[0] == '#') + { + aKeyString = ""; + continue; + } + + // Read ',' separated locale list at the start + if (aLocale.isEmpty()) + { + auto aFileLocales = comphelper::string::split(aStr, ','); + + // find and cache the best match + for (const auto &f : aFileLocales) + { + for (const auto &i : aLocales) + { + if (f == i) + { + aLocale = f + u"\t"_ustr; + break; + } + } + if (!aLocale.isEmpty()) + break; + } + } + if (aKeyString.isEmpty()) + aKeyString = aStr; + else + { + if (aStr.startsWith(aLocale)) + { + auto aValues = comphelper::string::split(aStr, '\t'); + if (aValues.size() > 1) + pMap->maMap[aKeyString] = aValues[1]; + else + pMap->maMap[aKeyString] = OUString::Concat(u"invalid line "_ustr) + OUString::number(nLine); + } + } + } + + xTextStrm->closeInput(); + + auto xMap = css::uno::Reference< XMap >(pMap); + + return xMap; + } + } + catch (Exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.core", "exception getting BuildId"); + } + return css::uno::Reference< XMap >(); + } + + // XMap + virtual Type SAL_CALL getKeyType() override { return cppu::UnoType::get(); }; + virtual Type SAL_CALL getValueType() override { return cppu::UnoType::get(); }; + virtual void SAL_CALL clear() override { maMap.clear(); } + virtual sal_Bool SAL_CALL containsKey( const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + virtual sal_Bool SAL_CALL containsValue( const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + + static OUString cleanDomain(const OUString &str) + { + sal_Int32 idx = str.indexOf('|'); + if (idx > 0) + return str.copy(idx+1); + else + return str; + } + + virtual Any SAL_CALL get( const Any& key ) override + { + auto it = maMap.find(key.get()); + if (it == maMap.end()) + { + SAL_WARN("xmloff", "Key '" << key << "' with no translation"); + return css::uno::Any(cleanDomain(key.get())); + } + else + return css::uno::Any(it->second); + } + virtual Any SAL_CALL put( const Any&, const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + virtual Any SAL_CALL remove( const Any& ) override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + + // XElementAccess (base) + virtual Type SAL_CALL getElementType() override + { + throw css::uno::RuntimeException(u"not implemented"_ustr); + } + virtual sal_Bool SAL_CALL hasElements() override + { + return !maMap.empty(); + } +}; +} + SvXMLImport::SvXMLImport( const css::uno::Reference< css::uno::XComponentContext >& xContext, OUString const & implementationName, @@ -478,6 +649,7 @@ SvXMLImport::SvXMLImport( SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); InitCtor_(); mxParser = xml::sax::FastParser::create( xContext ); + setNamespaceHandler( maNamespaceHandler ); setTokenHandler( xTokenHandler ); if ( !bIsNSMapsInitialized ) @@ -1085,7 +1257,12 @@ void SAL_CALL SvXMLImport::initialize( const uno::Sequence< uno::Any >& aArgumen } uno::Reference const xInit(mxParser, uno::UNO_QUERY_THROW); - xInit->initialize( { Any(u"IgnoreMissingNSDecl"_ustr) }); + + css::uno::Reference< XMap > xMap = L10nMapper::load(GetSourceStorage()); + css::uno::Sequence< css::uno::Any > args{ + css::uno::Any(u"IgnoreMissingNSDecl"_ustr), + css::uno::Any(xMap) }; + xInit->initialize(args); } // XServiceInfo