From 0fd7f81ec6765133bc2a964afd832631cd1bbf31 Mon Sep 17 00:00:00 2001 From: Zolnai Tamás Date: Thu, 1 Nov 2012 13:39:43 +0100 Subject: Implement new treex executable Which localize and update help tree files instead of update_tree.pl. Use it to update extensions' help. Next step: use it with general help. Change-Id: Ife9696bdd8b973ef3cf30626533e38720408179b --- l10ntools/Executable_treex.mk | 36 +++++ l10ntools/Module_l10ntools.mk | 1 + l10ntools/inc/treemerge.hxx | 38 ++++++ l10ntools/source/localize.cxx | 3 +- l10ntools/source/treemerge.cxx | 304 +++++++++++++++++++++++++++++++++++++++++ l10ntools/source/treex.cxx | 60 ++++++++ 6 files changed, 441 insertions(+), 1 deletion(-) create mode 100644 l10ntools/Executable_treex.mk create mode 100644 l10ntools/inc/treemerge.hxx create mode 100644 l10ntools/source/treemerge.cxx create mode 100644 l10ntools/source/treex.cxx (limited to 'l10ntools') diff --git a/l10ntools/Executable_treex.mk b/l10ntools/Executable_treex.mk new file mode 100644 index 000000000000..41af0a8bfbc9 --- /dev/null +++ b/l10ntools/Executable_treex.mk @@ -0,0 +1,36 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + + +$(eval $(call gb_Executable_Executable,treex)) + +$(eval $(call gb_Executable_set_include,treex,\ + -I$(SRCDIR)/l10ntools/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Executable_use_libraries,treex,\ + sal \ + i18nregexp \ +)) + +$(eval $(call gb_Executable_use_static_libraries,treex,\ + transex \ +)) + +$(eval $(call gb_Executable_add_exception_objects,treex,\ + l10ntools/source/treemerge \ + l10ntools/source/treex \ +)) + +$(eval $(call gb_Executable_use_externals,treex,\ + libxml2 \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/l10ntools/Module_l10ntools.mk b/l10ntools/Module_l10ntools.mk index e6c0cc3a8047..6efcd7f45596 100644 --- a/l10ntools/Module_l10ntools.mk +++ b/l10ntools/Module_l10ntools.mk @@ -39,6 +39,7 @@ $(eval $(call gb_Module_add_targets,l10ntools,\ Executable_transex3 \ Executable_renewpo \ Executable_propex \ + Executable_treex \ StaticLibrary_transex \ Package_inc \ Package_scripts \ diff --git a/l10ntools/inc/treemerge.hxx b/l10ntools/inc/treemerge.hxx new file mode 100644 index 000000000000..3b681126bfab --- /dev/null +++ b/l10ntools/inc/treemerge.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef _TREEMERGE_INCLUDED +#define _TREEMERGE_INCLUDED + +#include +#include +#include + +class TreeParser +{ +private: + xmlDocPtr m_pSource; + OString m_sLang; + bool m_bIsInitialized; + +public: + TreeParser( + const OString& rInputFile, const OString& rLang ); + ~TreeParser(); + + bool isInitialized() const { return m_bIsInitialized; } + void Extract( + const OString& rSDFFile, const OString& rPrj, const OString& rRoot ); + void Merge( + const OString &rMergeSrc, const OString &rDestinationFile, + const OString &rXhpRoot ); +}; + +#endif //_TREEMERGE_INCLUDED +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/localize.cxx b/l10ntools/source/localize.cxx index fd1d8ca4b4d0..f808af59d6cd 100644 --- a/l10ntools/source/localize.cxx +++ b/l10ntools/source/localize.cxx @@ -324,7 +324,8 @@ void handleFile( { RTL_CONSTASCII_STRINGPARAM(".xml"), "xrmex", true }, { RTL_CONSTASCII_STRINGPARAM(".xhp"), "helpex", false }, { RTL_CONSTASCII_STRINGPARAM(".properties"), "propex", false }, - { RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false } }; + { RTL_CONSTASCII_STRINGPARAM(".ui"), "uiex", false }, + { RTL_CONSTASCII_STRINGPARAM(".tree"), "treex", false } }; for (std::size_t i = 0; i != SAL_N_ELEMENTS(commands); ++i) { if (url.endsWithAsciiL( commands[i].extension, commands[i].extensionLength)) diff --git a/l10ntools/source/treemerge.cxx b/l10ntools/source/treemerge.cxx new file mode 100644 index 000000000000..12e931c6d221 --- /dev/null +++ b/l10ntools/source/treemerge.cxx @@ -0,0 +1,304 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "export.hxx" +#include "common.hxx" +#include "treemerge.hxx" + + +namespace +{ + //Write out an sdf line + static void lcl_WriteSDF( + std::ofstream &aSDFStream, const OString& rText, const OString& rPrj, + const OString& rActFileName, const OString& rID, const OString& rType ) + { + OString sOutput( rPrj ); sOutput += "\t"; + sOutput += rActFileName; + sOutput += "\t0\t"; + sOutput += rType; sOutput += "\t"; + sOutput += rID; sOutput += "\t\t\t\t0\ten-US\t"; + sOutput += rText; sOutput += "\t\t\t\t"; + aSDFStream << sOutput.getStr() << std::endl; + } + + //Convert xmlChar* to OString + static OString lcl_xmlStrToOString( const xmlChar* pString ) + { + xmlChar* pTemp = xmlStrdup( pString ); + OString sResult = + static_cast(reinterpret_cast( pTemp )); + xmlFree( pTemp ); + return sResult; + } + + //Extract strings from nodes on all level recursively + static void lcl_ExtractLevel( + const xmlDocPtr pSource, const xmlNodePtr pRoot, + const xmlChar* pNodeName, std::ofstream& rSDFStream, + const OString& rPrj, const OString& rRoot ) + { + if( !pRoot->children ) + { + return; + } + for( xmlNodePtr pCurrent = pRoot->children->next; + pCurrent; pCurrent = pCurrent->next) + { + if (!xmlStrcmp(pCurrent->name, pNodeName)) + { + xmlChar* pID = xmlGetProp(pCurrent, (const xmlChar*)("id")); + xmlChar* pText = + xmlGetProp(pCurrent, (const xmlChar*)("title")); + lcl_WriteSDF( + rSDFStream, + lcl_xmlStrToOString( pText ), + rPrj, + common::pathnameToken( + pSource->name, rRoot.getStr()), + lcl_xmlStrToOString( pID ), + lcl_xmlStrToOString( pNodeName )); + + xmlFree( pID ); + xmlFree( pText ); + + lcl_ExtractLevel( + pSource, pCurrent, (const xmlChar *)("node"), + rSDFStream, rPrj, rRoot ); + } + } + } + + //Update id and content of the topic + static xmlNodePtr lcl_UpdateTopic( + const xmlNodePtr pCurrent, const OString& rXhpRoot ) + { + xmlNodePtr pReturn = pCurrent; + xmlChar* pID = xmlGetProp(pReturn, (const xmlChar*)("id")); + const OString sID = + lcl_xmlStrToOString( pID ); + xmlFree( pID ); + + const sal_Int32 nFirstSlash = sID.indexOf("/"); + //Update id attribute of topic + { + OString sNewID = + sID.copy( 0, nFirstSlash + 1 ) + + rXhpRoot.copy( rXhpRoot.lastIndexOf("/") + 1 ) + + sID.copy( sID.indexOf( "/", nFirstSlash + 1 ) ); + xmlSetProp( + pReturn, (const xmlChar*)("id"), + reinterpret_cast(sNewID.getStr())); + } + + const OString sXhpPath = + rXhpRoot + + sID.copy(sID.indexOf("/", nFirstSlash + 1)); + xmlDocPtr pXhpFile = xmlParseFile( sXhpPath.getStr() ); + //if xhpfile is missing than we put this topic into comment + if ( !pXhpFile ) + { + xmlNodePtr pTemp = pReturn; + xmlChar* sNewID = + xmlGetProp(pReturn, (const xmlChar*)("id")); + xmlChar* sComment = + xmlStrcat( xmlCharStrdup("removed "), sNewID ); + pReturn = xmlNewComment( sComment ); + xmlReplaceNode( pTemp, pReturn ); + xmlFree( pTemp ); + xmlFree( sNewID ); + xmlFree( sComment ); + } + //update topic's content on the basis of xhpfile's title + else + { + xmlNodePtr pXhpNode = xmlDocGetRootElement( pXhpFile ); + for( pXhpNode = pXhpNode->children; + pXhpNode; pXhpNode = pXhpNode->children ) + { + while( pXhpNode->type != XML_ELEMENT_NODE ) + { + pXhpNode = pXhpNode->next; + } + if(!xmlStrcmp(pXhpNode->name, (const xmlChar *)("title"))) + { + xmlChar* sTitle = + xmlNodeListGetString(pXhpFile, pXhpNode->children, 1); + OString sNewTitle = + lcl_xmlStrToOString( sTitle ). + replaceAll("$[officename]","%PRODUCTNAME"). + replaceAll("$[officeversion]","%PRODUCTVERSION"); + xmlNodeSetContent( + pReturn, + reinterpret_cast( sNewTitle.getStr() )); + xmlFree( sTitle ); + break; + } + } + if( !pXhpNode ) + { + std::cerr + << "Treex error: Cannot find title in " + << sXhpPath.getStr() << std::endl; + return 0; + } + xmlFree( pXhpFile ); + xmlCleanupParser(); + } + return pReturn; + } + //Localize title attribute of help_section and node tags + static void lcl_MergeLevel( + xmlDocPtr io_pSource, const xmlNodePtr pRoot, + const xmlChar * pNodeName, MergeDataFile* pMergeDataFile, + const OString& rLang, const OString& rXhpRoot ) + { + if( !pRoot->children ) + { + return; + } + for( xmlNodePtr pCurrent = pRoot->children; + pCurrent; pCurrent = pCurrent->next) + { + if( !xmlStrcmp(pCurrent->name, pNodeName) ) + { + if( pMergeDataFile ) + { + xmlChar* pID = xmlGetProp(pCurrent, (const xmlChar*)("id")); + ResData aResData( + "", lcl_xmlStrToOString( pID ), + static_cast(io_pSource->name) ); + xmlFree( pID ); + aResData.sResTyp = lcl_xmlStrToOString( pNodeName ); + PFormEntrys* pEntrys = + pMergeDataFile->GetPFormEntrys( &aResData ); + if( pEntrys ) + { + OString sNewText; + pEntrys->GetText( sNewText, STRING_TYP_TEXT, rLang ); + xmlSetProp( + pCurrent, (const xmlChar*)("title"), + (const xmlChar*)(sNewText.getStr())); + } + } + lcl_MergeLevel( + io_pSource, pCurrent, (const xmlChar *)("node"), + pMergeDataFile, rLang, rXhpRoot ); + } + else if( !xmlStrcmp(pCurrent->name, (const xmlChar *)("topic")) ) + { + pCurrent = lcl_UpdateTopic( pCurrent, rXhpRoot ); + } + } + } +} + +//Parse tree file +TreeParser::TreeParser( + const OString& rInputFile, const OString& rLang ) + : m_pSource( 0 ) + , m_sLang( rLang ) + , m_bIsInitialized( false ) +{ + m_pSource = xmlParseFile( rInputFile.getStr() ); + if ( !m_pSource ) { + std::cerr + << "Treex error: Cannot open source file: " + << rInputFile.getStr() << std::endl; + return; + } + if( !m_pSource->name ) + { + m_pSource->name = new char[strlen(rInputFile.getStr())+1]; + strcpy( m_pSource->name, rInputFile.getStr() ); + } + m_bIsInitialized = true; +} + +TreeParser::~TreeParser() +{ +} + +//Extract strings form source file +void TreeParser::Extract( + const OString& rSDFFile, const OString& rPrj, const OString& rRoot ) +{ + assert( m_bIsInitialized ); + std::ofstream aSDFStream( + rSDFFile.getStr(), std::ios_base::out | std::ios_base::trunc ); + if( !aSDFStream.is_open() ) + { + std::cerr + << "Treex error: Cannot open sdffile for extract: " + << rSDFFile.getStr() << std::endl; + return; + } + + xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource ); + lcl_ExtractLevel( + m_pSource, pRootNode, (const xmlChar *)("help_section"), + aSDFStream, rPrj, rRoot ); + + xmlFreeDoc( m_pSource ); + xmlCleanupParser(); + aSDFStream.close(); + m_bIsInitialized = false; +} + +//Merge strings to tree file and update reference to help files(xhp) +void TreeParser::Merge( + const OString &rMergeSrc, const OString &rDestinationFile, + const OString &rXhpRoot ) +{ + assert( m_bIsInitialized ); + + const xmlNodePtr pRootNode = xmlDocGetRootElement( m_pSource ); + if( m_sLang == "en-US" ) + { + lcl_MergeLevel( + m_pSource, pRootNode, (const xmlChar *)("help_section"), + 0, m_sLang, rXhpRoot ); + } + else + { + MergeDataFile aMergeDataFile( + rMergeSrc, static_cast( m_pSource->name ), false ); + + if( aMergeDataFile.GetLanguages()[0] != m_sLang ) + { + std::cerr + << "Treex error: given language conflicts with " + << "language of Mergedata file: " + << m_sLang.getStr() << " - " << rMergeSrc.getStr() << std::endl; + return; + } + + lcl_MergeLevel( + m_pSource, pRootNode, (const xmlChar *)("help_section"), + &aMergeDataFile, m_sLang, rXhpRoot ); + } + + xmlSaveFile( rDestinationFile.getStr(), m_pSource ); + xmlFreeDoc( m_pSource ); + xmlCleanupParser(); + m_bIsInitialized = false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/treex.cxx b/l10ntools/source/treex.cxx new file mode 100644 index 000000000000..65807b1a5c0b --- /dev/null +++ b/l10ntools/source/treex.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include "sal/main.h" + +#include "export.hxx" +#include "treemerge.hxx" + +void WriteUsage() +{ + std::cout + << "Syntax: Treex [-p Prj] [-r Root] -i FileIn -o FileOut" + << " [-m DataBase] [-l l1,l2,...]\n" + << " Prj: Project\n" + << " Root: Path to project root (../.. etc.)\n" + << " or path to root of localized xhp files\n" + << " FileIn: Source files (*.tree)\n" + << " FileOut: Destination file (*.*)\n" + << " DataBase: Mergedata (*.po)\n" + << " -l: Restrict the handled languages; l1, l2, ... are elements of" + << " (de, en-US, ...)\n"; +} + + +SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) +{ + HandledArgs aArgs; + if( !Export::handleArguments(argc, argv, aArgs) ) + { + WriteUsage(); + return 1; + } + + TreeParser aParser(aArgs.m_sInputFile, Export::sLanguages); + if( !aParser.isInitialized() ) + { + return 1; + } + + if( aArgs.m_bMergeMode || aArgs.m_sPrj.isEmpty() ) + { + aParser.Merge( + aArgs.m_sMergeSrc, aArgs.m_sOutputFile, aArgs.m_sPrjRoot ); + } + else + { + aParser.Extract( + aArgs.m_sOutputFile, aArgs.m_sPrj, aArgs.m_sPrjRoot ); + } + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit