Implement translation mapper for XML content.
Loads content from a stream with this syntax: # list of supported bcp47 lang tags en-US,de-DE,fr-FR,en-GB # then each string This is a string [en-US] This is stil a string [en-GB] I say old boy, what a string etc. Change-Id: Id6e3c0de03f57c68246fd3eee7b4912f9adc218e Signed-off-by: Michael Meeks <michael.meeks@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193627 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Andras Timar <andras.timar@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195192 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
committed by
Caolán McNamara
parent
d66a2686d0
commit
50e0a48105
@@ -29,6 +29,7 @@
|
||||
#include <utility>
|
||||
#include <vcl/embeddedfontsmanager.hxx>
|
||||
#include <vcl/graph.hxx>
|
||||
#include <vcl/svapp.hxx>
|
||||
#include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
|
||||
#include <xmloff/namespacemap.hxx>
|
||||
#include <xmloff/xmlgrhlp.hxx>
|
||||
@@ -66,10 +67,12 @@
|
||||
#include <cppuhelper/implbase.hxx>
|
||||
#include <cppuhelper/supportsservice.hxx>
|
||||
#include <comphelper/extract.hxx>
|
||||
#include <comphelper/processfactory.hxx>
|
||||
#include <comphelper/documentconstants.hxx>
|
||||
#include <comphelper/documentinfo.hxx>
|
||||
#include <comphelper/storagehelper.hxx>
|
||||
#include <comphelper/attributelist.hxx>
|
||||
#include <comphelper/string.hxx>
|
||||
#include <unotools/fontcvt.hxx>
|
||||
#include <fasttokenhandler.hxx>
|
||||
#include <vcl/GraphicExternalLink.hxx>
|
||||
@@ -79,6 +82,18 @@
|
||||
#include <com/sun/star/rdf/XRepositorySupplier.hpp>
|
||||
#include <RDFaImportHelper.hxx>
|
||||
|
||||
// L10nMapper bits to split out ...
|
||||
#include <com/sun/star/uno/Type.hxx>
|
||||
#include <com/sun/star/lang/XInitialization.hpp>
|
||||
#include <com/sun/star/io/XTextInputStream2.hpp>
|
||||
#include <com/sun/star/io/TextInputStream.hpp>
|
||||
#include <com/sun/star/container/XMap.hpp>
|
||||
#include <cppuhelper/compbase.hxx>
|
||||
#include <i18nlangtag/languagetag.hxx>
|
||||
#include <comphelper/lok.hxx>
|
||||
#include <com/sun/star/lang/XLocalizable.hpp>
|
||||
#include <com/sun/star/configuration/theDefaultProvider.hpp>
|
||||
|
||||
using ::com::sun::star::beans::XPropertySetInfo;
|
||||
|
||||
using namespace ::com::sun::star;
|
||||
@@ -457,6 +472,162 @@ void SvXMLImport::InitCtor_()
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class L10nMapper : public cppu::WeakImplHelper<css::container::XMap>
|
||||
{
|
||||
std::unordered_map<OUString, OUString> maMap;
|
||||
|
||||
L10nMapper() { }
|
||||
virtual ~L10nMapper() override {}
|
||||
|
||||
public:
|
||||
static css::uno::Reference< XMap > load(const uno::Reference<css::embed::XStorage> &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<css::io::XInputStream>(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<OUString> 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 <opt-prefix|string>\nlocale\t<translated-string>\n<repeat>\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<OUString>::get(); };
|
||||
virtual Type SAL_CALL getValueType() override { return cppu::UnoType<OUString>::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<OUString>());
|
||||
if (it == maMap.end())
|
||||
{
|
||||
SAL_WARN("xmloff", "Key '" << key << "' with no translation");
|
||||
return css::uno::Any(cleanDomain(key.get<OUString>()));
|
||||
}
|
||||
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<lang::XInitialization> 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
|
||||
|
||||
Reference in New Issue
Block a user