diff options
Diffstat (limited to 'l10ntools')
40 files changed, 2588 insertions, 1340 deletions
diff --git a/l10ntools/Executable_cfgex.mk b/l10ntools/Executable_cfgex.mk index 5531606abc86..7804470c05a7 100644 --- a/l10ntools/Executable_cfgex.mk +++ b/l10ntools/Executable_cfgex.mk @@ -33,6 +33,7 @@ $(eval $(call gb_Executable_set_include,cfgex,\ $(eval $(call gb_Executable_use_libraries,cfgex,\ sal \ + i18nregexp \ )) $(eval $(call gb_Executable_use_unpacked,cfgex,boost)) diff --git a/l10ntools/Executable_helpex.mk b/l10ntools/Executable_helpex.mk index f1d447c92bed..22f2ae9288a4 100644 --- a/l10ntools/Executable_helpex.mk +++ b/l10ntools/Executable_helpex.mk @@ -33,6 +33,7 @@ $(eval $(call gb_Executable_set_include,helpex,\ $(eval $(call gb_Executable_use_libraries,helpex,\ sal \ + i18nregexp \ )) $(eval $(call gb_Executable_use_external,helpex,expat_utf8)) diff --git a/l10ntools/Executable_localize.mk b/l10ntools/Executable_localize.mk index 511604ac74d2..e6e7f1fc2c6e 100644 --- a/l10ntools/Executable_localize.mk +++ b/l10ntools/Executable_localize.mk @@ -26,8 +26,18 @@ $(eval $(call gb_Executable_Executable,localize)) +$(eval $(call gb_Executable_set_include,localize,\ + -I$(SRCDIR)/l10ntools/inc \ + $$(INCLUDE) \ +)) + $(eval $(call gb_Executable_use_libraries,localize,\ sal \ + i18nregexp \ +)) + +$(eval $(call gb_Executable_use_static_libraries,localize,\ + transex \ )) $(eval $(call gb_Executable_add_exception_objects,localize,\ diff --git a/l10ntools/Executable_propex.mk b/l10ntools/Executable_propex.mk new file mode 100644 index 000000000000..d8dc16d323c2 --- /dev/null +++ b/l10ntools/Executable_propex.mk @@ -0,0 +1,32 @@ +# -*- 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,propex)) + +$(eval $(call gb_Executable_set_include,propex,\ + -I$(SRCDIR)/l10ntools/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Executable_use_libraries,propex,\ + sal \ + i18nregexp \ +)) + +$(eval $(call gb_Executable_use_static_libraries,propex,\ + transex \ +)) + +$(eval $(call gb_Executable_add_exception_objects,propex,\ + l10ntools/source/propmerge \ + l10ntools/source/propex \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/l10ntools/Executable_renewpo.mk b/l10ntools/Executable_renewpo.mk new file mode 100644 index 000000000000..5aa036a40100 --- /dev/null +++ b/l10ntools/Executable_renewpo.mk @@ -0,0 +1,32 @@ +# -*- 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/. +# +# convert old po to new po +# + +$(eval $(call gb_Executable_Executable,renewpo)) + +$(eval $(call gb_Executable_set_include,renewpo,\ + -I$(SRCDIR)/l10ntools/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Executable_use_libraries,renewpo,\ + sal \ + i18nregexp \ +)) + +$(eval $(call gb_Executable_use_static_libraries,renewpo,\ + transex \ +)) + +$(eval $(call gb_Executable_add_exception_objects,renewpo,\ + l10ntools/source/renewpo \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/l10ntools/Executable_transex3.mk b/l10ntools/Executable_transex3.mk index bc9a85272d9f..2d9590641d83 100644 --- a/l10ntools/Executable_transex3.mk +++ b/l10ntools/Executable_transex3.mk @@ -33,6 +33,7 @@ $(eval $(call gb_Executable_set_include,transex3,\ $(eval $(call gb_Executable_use_libraries,transex3,\ sal \ + i18nregexp \ )) $(eval $(call gb_Executable_add_scanners,transex3,\ 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/Executable_uiex.mk b/l10ntools/Executable_uiex.mk index 03699f67a505..520b010265f0 100644 --- a/l10ntools/Executable_uiex.mk +++ b/l10ntools/Executable_uiex.mk @@ -16,6 +16,7 @@ $(eval $(call gb_Executable_set_include,uiex,\ $(eval $(call gb_Executable_use_libraries,uiex,\ sal \ + i18nregexp \ )) $(eval $(call gb_Executable_use_unpacked,uiex,boost)) diff --git a/l10ntools/Executable_ulfex.mk b/l10ntools/Executable_ulfex.mk index c045eb11e4a9..b975f5c47e11 100644 --- a/l10ntools/Executable_ulfex.mk +++ b/l10ntools/Executable_ulfex.mk @@ -33,6 +33,7 @@ $(eval $(call gb_Executable_set_include,ulfex,\ $(eval $(call gb_Executable_use_libraries,ulfex,\ sal \ + i18nregexp \ )) $(eval $(call gb_Executable_use_unpacked,ulfex,boost)) diff --git a/l10ntools/Executable_xrmex.mk b/l10ntools/Executable_xrmex.mk index 1aeef2121b7a..02e776a2277b 100644 --- a/l10ntools/Executable_xrmex.mk +++ b/l10ntools/Executable_xrmex.mk @@ -33,6 +33,7 @@ $(eval $(call gb_Executable_set_include,xrmex,\ $(eval $(call gb_Executable_use_libraries,xrmex,\ sal \ + i18nregexp \ )) $(eval $(call gb_Executable_use_unpacked,xrmex,boost)) diff --git a/l10ntools/Module_l10ntools.mk b/l10ntools/Module_l10ntools.mk index 6fe7dcb5d083..6efcd7f45596 100644 --- a/l10ntools/Module_l10ntools.mk +++ b/l10ntools/Module_l10ntools.mk @@ -37,6 +37,9 @@ $(eval $(call gb_Module_add_targets,l10ntools,\ Executable_xrmex \ Executable_localize \ Executable_transex3 \ + Executable_renewpo \ + Executable_propex \ + Executable_treex \ StaticLibrary_transex \ Package_inc \ Package_scripts \ diff --git a/l10ntools/Package_scripts.mk b/l10ntools/Package_scripts.mk index 3739f123b434..d00d283a8cc6 100644 --- a/l10ntools/Package_scripts.mk +++ b/l10ntools/Package_scripts.mk @@ -30,11 +30,5 @@ $(eval $(call gb_Package_add_file,l10ntools_scripts,bin/addkeyid2pot.pl,addkeyid $(eval $(call gb_Package_add_file,l10ntools_scripts,bin/fast_merge.pl,fast_merge.pl)) $(eval $(call gb_Package_add_file,l10ntools_scripts,bin/keyidGen.pl,keyidGen.pl)) $(eval $(call gb_Package_add_file,l10ntools_scripts,bin/po2lo,po2lo)) -$(eval $(call gb_Package_add_file,l10ntools_scripts,bin/propex,propex)) -$(eval $(call gb_Package_add_file,l10ntools_scripts,bin/propmerge,propmerge)) - -ifeq ($(OS_FOR_BUILD),WNT) -$(eval $(call gb_Package_add_file,l10ntools_scripts,bin/propex.bat,propex.bat)) -endif # vim: set noet sw=4 ts=4: diff --git a/l10ntools/StaticLibrary_transex.mk b/l10ntools/StaticLibrary_transex.mk index 4996b05f0342..65b1f08e9c81 100644 --- a/l10ntools/StaticLibrary_transex.mk +++ b/l10ntools/StaticLibrary_transex.mk @@ -42,11 +42,14 @@ $(eval $(call gb_StaticLibrary_use_packages,transex,\ sal_inc \ )) +$(eval $(call gb_StaticLibrary_use_sdk_api,transex)) + $(eval $(call gb_StaticLibrary_add_exception_objects,transex,\ l10ntools/source/export2 \ l10ntools/source/merge \ l10ntools/source/file \ l10ntools/source/directory \ + l10ntools/source/po \ )) # vim: set noet sw=4 ts=4: diff --git a/l10ntools/inc/export.hxx b/l10ntools/inc/export.hxx index 9a4ce788ec77..28807f6c95a8 100644 --- a/l10ntools/inc/export.hxx +++ b/l10ntools/inc/export.hxx @@ -248,6 +248,27 @@ typedef ::std::vector< ResData* > ResStack; class WordTransformer; class ParserQueue; +//result type of handleArguments() +struct HandledArgs +{ + OString m_sPrj; + OString m_sPrjRoot; + OString m_sInputFile; + OString m_sOutputFile; + OString m_sMergeSrc; + OString m_sLanguages; + bool m_bMergeMode; + HandledArgs() + : m_sPrj( OString() ) + , m_sPrjRoot( OString() ) + , m_sInputFile( OString() ) + , m_sOutputFile( OString() ) + , m_sMergeSrc( OString() ) + , m_sLanguages( OString() ) + , m_bMergeMode( false ) + {} +}; + class Export { private: @@ -285,6 +306,9 @@ public: static rtl::OString sLanguages; // public ? static rtl::OString sForcedLanguages; // public ? + static bool handleArguments(int argc, char * argv[], HandledArgs& o_aHandledArgs); + static void writeUsage(const OString& rName, const OString& rFileType); + static void InitLanguages( bool bMergeMode = false ); static void InitForcedLanguages( bool bMergeMode = false ); static std::vector<rtl::OString> GetLanguages(); diff --git a/l10ntools/inc/po.hxx b/l10ntools/inc/po.hxx new file mode 100644 index 000000000000..856c7bb04ff1 --- /dev/null +++ b/l10ntools/inc/po.hxx @@ -0,0 +1,129 @@ +/* -*- 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 _PO_INCLUDED +#define _PO_INCLUDED + +#include <fstream> +#include <rtl/string.hxx> +#include <boost/noncopyable.hpp> + +class PoOfstream; +class PoIfstream; +class GenPoEntry; + +class PoEntry +{ +private: + + GenPoEntry* m_pGenPo; + bool m_bIsInitialized; + +public: + + friend class PoOfstream; + friend class PoIfstream; + + enum SDFPART { PROJECT, SOURCEFILE, DUMMY, RESOURCETYPE, GROUPID, + LOCALID, HELPID, PLATFORM, WIDTH, LANGUAGEID, + TEXT, HELPTEXT, QUICKHELPTEXT, TITLE, TIMESTAMP }; + enum TYPE { TTEXT=TEXT, TQUICKHELPTEXT=QUICKHELPTEXT, TTITLE=TITLE }; + enum Exception { INVALIDSDFLINE }; + + PoEntry(); + PoEntry(const OString& rSDFLine, + const TYPE eType = TTEXT); + ~PoEntry(); + + PoEntry( const PoEntry& rPo ); + PoEntry& operator=( const PoEntry& rPo ); + + OString getSourceFile() const; + OString getGroupId() const; + OString getLocalId() const; + OString getResourceType() const; + TYPE getType() const; + OString getMsgId() const; + OString getMsgStr() const; + bool isFuzzy() const; + OString getKeyId() const; + void setMsgId(const OString& rUnTransStr); + void setMsgStr(const OString& rTransStr); + void setFuzzy(const bool bFuzzy); + + static bool IsInSameComp(const PoEntry& rPo1,const PoEntry& rPo2); + +}; + +class PoHeader: private boost::noncopyable +{ +private: + + GenPoEntry* m_pGenPo; + bool m_bIsInitialized; + +public: + + friend class PoOfstream; + friend class PoIfstream; + + enum Exception { NOLANG }; + + PoHeader(); + PoHeader( const OString& rExtSrc ); + PoHeader( std::ifstream& rOldPo ); + ~PoHeader(); + + OString getLanguage() const; +}; + +class PoOfstream: private boost::noncopyable +{ +private: + + std::ofstream m_aOutPut; + bool m_bIsAfterHeader; + +public: + PoOfstream(); + ~PoOfstream(); + bool isOpen() const { return m_aOutPut.is_open(); } + + void open(const OString& rFileName); + void close(); + void writeHeader(const PoHeader& rHeader); + void writeEntry(const PoEntry& rPo); +}; + +class PoIfstream: private boost::noncopyable +{ +private: + + std::ifstream m_aInPut; + bool m_bIsAfterHeader; + bool m_bEof; + +public: + + enum Exception { INVALIDENTRY, INVALIDHEADER }; + + PoIfstream(); + ~PoIfstream(); + bool isOpen() const { return m_aInPut.is_open(); } + bool eof() const { return m_bEof; } + + void open(const OString& rFileName); + void close(); + void readHeader(PoHeader& rHeader); + void readEntry(PoEntry& rPo); +}; + +#endif // _PO_INCLUDED + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/inc/propmerge.hxx b/l10ntools/inc/propmerge.hxx new file mode 100644 index 000000000000..4f0e3275a434 --- /dev/null +++ b/l10ntools/inc/propmerge.hxx @@ -0,0 +1,37 @@ +/* -*- 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 _PROPMERGE_INCLUDED +#define _PROPMERGE_INCLUDED + +#include <rtl/string.hxx> +#include <vector> + +class PropParser +{ +private: + std::vector<OString> m_vLines; + OString m_sSource; + OString m_sLang; + bool m_bIsInitialized; + +public: + PropParser( + const OString& rInputFile, const OString& rLang, + const bool bMergeMode ); + ~PropParser(); + + 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 ); +}; + +#endif //_PROPMERGE_INCLUDED +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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 <libxml/tree.h> +#include <rtl/string.hxx> +#include <vector> + +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/prj/build.lst b/l10ntools/prj/build.lst index 5f7fca144415..888b2343a4b5 100644 --- a/l10ntools/prj/build.lst +++ b/l10ntools/prj/build.lst @@ -1,3 +1,3 @@ -tr l10ntools : EXPAT:expat LIBXSLT:libxslt sal NULL +tr l10ntools : EXPAT:expat LIBXSLT:libxslt sal regexp NULL tr l10ntools usr1 - all tr_mkout NULL tr l10ntools\prj nmake - all tr_prj NULL diff --git a/l10ntools/scripts/po2lo b/l10ntools/scripts/po2lo index cdf8892fc950..579699102710 100755 --- a/l10ntools/scripts/po2lo +++ b/l10ntools/scripts/po2lo @@ -41,6 +41,7 @@ class Entry: """Represents a single line in an SDF file.""" def __init__(self, items): + self.has_translation = None; self.items = items # list of 15 fields path = self.items[1].split('\\') self.po = "%s/%s/%s.po" % (options.input.replace('\\', '/'), self.items[0], "/".join(path[:-1])) @@ -65,13 +66,20 @@ class Entry: """Translates text in the entry based on translations.""" self.items[9] = options.language + self.items[2] = "" + self.has_translation = False for idx, key in self.keys: try: - self.items[idx] = translations.data[(self.po, key)] + if translations.data[(self.po, key)][1]: + self.items[2] += "1" + else: + self.items[2] += "0" + self.items[idx] = translations.data[(self.po, key)][0] + self.has_translation = True self.items[14] = "2002-02-02 02:02:02" except KeyError: - pass + self.items[idx]="" self.items[14] = self.items[14].strip() def sdf2po(self, s): @@ -95,8 +103,10 @@ class Template: sock = xopen(options.output, "w", encoding='utf-8') for line in self.lines: + sock.write("\t".join(line.items)) line.translate(translations) - sock.write("\t".join(line.items)+"\r\n") + if line.has_translation: + sock.write("\t".join(line.items)+"\r\n") sock.close() class Translations: @@ -120,10 +130,10 @@ class Translations: elif line.startswith("msgstr "): trans = line.strip()[8:-1] if len(trans): + self.setdata(path, key, trans, fuzzy) if fuzzy: fuzzy = False else: - self.setdata(path, key, trans) multiline = False else: buf = [] @@ -132,16 +142,15 @@ class Translations: elif multiline and line.startswith('"'): buf.append(line.strip()[1:-1]) elif multiline and not len(line.strip()) and len("".join(buf)): + self.setdata(path, key, "".join(buf),fuzzy) if fuzzy: fuzzy = False - else: - self.setdata(path, key, "".join(buf)) buf = [] multiline = False - if multiline and len("".join(buf)) and not fuzzy: - self.setdata(path, key, "".join(buf)) + if multiline and len("".join(buf)): + self.setdata(path, key, "".join(buf),fuzzy) - def setdata(self, path, key, s): + def setdata(self, path, key, s, fuzzy = False): """Sets the translation for a given path and key, handling (un)escaping as well.""" if key: @@ -151,7 +160,7 @@ class Translations: s = self.escape_help_text(s) else: s = s.replace('\\\\', '\\') - self.data[(path.replace('\\', '/'), key)] = s + self.data[(path.replace('\\', '/'), key)] = ( s , fuzzy ) def escape_help_text(self, text): """Escapes the help text as it would be in an SDF file.""" diff --git a/l10ntools/scripts/propex b/l10ntools/scripts/propex deleted file mode 100755 index 35dcb258e381..000000000000 --- a/l10ntools/scripts/propex +++ /dev/null @@ -1,68 +0,0 @@ -: -eval 'exec perl -S $0 ${1+"$@"}' - if 0; -# Version: MPL 1.1 / GPLv3+ / LGPLv3+ -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License or as specified alternatively below. You may obtain a copy of -# the License at http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Initial Developer of the Original Code is -# Andras Timar <atimar@suse.com> -# Portions created by the Initial Developer are Copyright (C) 2011 the -# Initial Developer. All Rights Reserved. -# -# Major Contributor(s): -# -# For minor contributions see the git repository. -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 3 or later (the "GPLv3+"), or -# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), -# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable -# instead of those above. -# -# extracts strings from Java properties files -# - -use strict; -use File::Basename; -use Getopt::Std; -use Cwd; - -my %options=(); -getopts("ep:r:i:o:l:", \%options); - -unless ( $options{i} =~ m/en_US/ ) {exit 0;} - -$options{i} =~ s|\\|/|g; # fix path on Windows, Perl expects / separator -my ($unused1, $dir, $unused2) = File::Basename::fileparse($options{i}); -my $file = substr ( Cwd::abs_path($options{i}), length(Cwd::abs_path($dir . $options{r})) + 1 ); -$file =~ s|/|\\|g; - -open (INFILE, "<$options{i}") || die "propex: cannot open input file: $options{i}"; -open (OUTFILE, ">$options{o}") || die "propex: cannot open output file: $options{o}"; - -while (<INFILE>) { - chomp; - if (/=/) { - my ($id, $value) = split /=/; - $id =~ s/^\s+//; #remove leading spaces - $id =~ s/\s+$//; #remove trailing spaces - $value =~ s/^\s+//; #remove leading spaces - $value =~ s/\s+$//; #remove trailing spaces - $value =~ s/(\\u([0-9a-fA-F]{4}))/pack("C0U1",hex($2))/ge; #convert ascii escaped unicode to utf-8 - print OUTFILE "$options{p}\t$file\t0\tproperty\t$id\t\t\t\t0\ten-US\t$value\t\t\t\t20020202 02:02:02\n"; - } -} - -close (INFILE); -close (OUTFILE); - -exit 0; diff --git a/l10ntools/scripts/propex.bat b/l10ntools/scripts/propex.bat deleted file mode 100755 index 1174286920da..000000000000 --- a/l10ntools/scripts/propex.bat +++ /dev/null @@ -1,8 +0,0 @@ -@echo off
-
-if "x%PERL%x" EQU "xx" (
- echo ERROR: Perl not found. Environment is not set.
- exit /b 1
-)
-
-%PERL% %SOLARVER%\%INPATH%\bin\propex %*
\ No newline at end of file diff --git a/l10ntools/scripts/propmerge b/l10ntools/scripts/propmerge deleted file mode 100755 index 5ba420d5c858..000000000000 --- a/l10ntools/scripts/propmerge +++ /dev/null @@ -1,88 +0,0 @@ -: -eval 'exec perl -S $0 ${1+"$@"}' - if 0; -# Version: MPL 1.1 / GPLv3+ / LGPLv3+ -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License or as specified alternatively below. You may obtain a copy of -# the License at http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Initial Developer of the Original Code is -# Andras Timar <atimar@suse.com> -# Portions created by the Initial Developer are Copyright (C) 2011 the -# Initial Developer. All Rights Reserved. -# -# Major Contributor(s): -# -# For minor contributions see the git repository. -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 3 or later (the "GPLv3+"), or -# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), -# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable -# instead of those above. -# -# merges strings from SDF file to properties files -# - -use strict; -use Getopt::Std; - -my %options=(); -getopts("i:m:", \%options); - -my %translations = (); -my %languages = (); - # ( leftpart ) ( rightpart ) - # prj file dummy type gid lid helpid pform width lang text helptext qhelptext title -my $sdf_regex = "((([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t])*\t([^\t]*)\t([^\t]*))\t([^\t]*)\t(([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)))"; - -open (SDFFILE, "<$options{m}") || die "propmerge: cannot open sdf file: $options{m}"; - -while (<SDFFILE>) { - chomp; - if( /$sdf_regex/ ) { - my $gid = defined $7 ? $7 : ''; - my $lang = defined $12 ? $12 : ''; - my $text = defined $14 ? $14 : ''; - my $key = $lang . $gid; - $languages{$lang} = 1; - utf8::decode($text); - $text =~ s/([^\x{20}-\x{7E}])/sprintf("\\u%04X",ord($1))/ge; - $translations{$key} = $text; - } -} - -close (SDFFILE); - -foreach my $lang (keys %languages) { - my $locfilename = $options{i}; - $lang =~ s/-/_/; - $locfilename =~ s/en_US\.properties/$lang.properties/; - $lang =~ s/_/-/; - open (INFILE, "<$options{i}") || die "propmerge: cannot open source file: $options{i}"; - open (OUTFILE, ">$locfilename") || die "propmerge: cannot open output file: $locfilename"; - while (<INFILE>) { - if (/=/) { - chomp; - my ($id, $value) = split /=/; - $id =~ s/^\s+//; #remove leading spaces - $id =~ s/\s+$//; #remove trailing spaces - my $key = $lang . $id; - print OUTFILE "$id=$translations{$key}\n"; - } - else { - print OUTFILE "$_"; - } - } - close (INFILE); - close (OUTFILE); -} - -exit 0; diff --git a/l10ntools/scripts/update_tree.pl b/l10ntools/scripts/update_tree.pl deleted file mode 100644 index 02faf6a37c72..000000000000 --- a/l10ntools/scripts/update_tree.pl +++ /dev/null @@ -1,394 +0,0 @@ -: -eval 'exec perl -wS $0 ${1+"$@"}' - if 0; -#************************************************************************* -# -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# Copyright 2000, 2010 Oracle and/or its affiliates. -# -# OpenOffice.org - a multi-platform office productivity suite -# -# This file is part of OpenOffice.org. -# -# OpenOffice.org is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License version 3 -# only, as published by the Free Software Foundation. -# -# OpenOffice.org is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License version 3 for more details -# (a copy is included in the LICENSE file that accompanied this code). -# -# You should have received a copy of the GNU Lesser General Public License -# version 3 along with OpenOffice.org. If not, see -# <http://www.openoffice.org/license.html> -# for a copy of the LGPLv3 License. -# -#************************************************************************* - -use Cwd 'abs_path'; -use File::Find; -use File::Copy qw/cp mv/; -use File::Basename; - -# update the tree files in <platform>/misc/* - -$| = 1; - -my $prj = $ENV{PWD}; - -my $inpath = $ENV{WORKDIR}; -terminate() if ( ! defined $inpath ); - -my $destpath = $inpath; -my $with_lang = $ARGV[1]; -my $xmllint = $ENV{XMLLINT} || "$ENV{OUTDIR_FOR_BUILD}/bin/xmllint"; - -$tree_target_prefix = $ARGV[4]; - -# Always use / directory separators -$prj =~ s/\\/\//g if defined($prj); -$inpath =~ s/\\/\//g; -$destpath =~ s/\\/\//g; - -if ( ! defined $prj ) { -# do someting that works for manual call - ($scriptname = `pwd`) =~ s/\n/\/$0/; - ($tree_src = $scriptname) =~ s/\/update_tree.pl/\/..\/source\/auxiliary/; - ($tree_dest = $scriptname) =~ s/\/update_tree.pl/\/..\/$destpath\/misc/; - ($source_dir = $scriptname) =~ s/\/update_tree.pl/\/..\/source/; - ($source_dir_xhp = $scriptname) =~ s/\/update_tree.pl/\/..\/source/; - - if ( defined $ENV{TRYSDF} || defined $ENV{LOCALIZESDF} ) - { - if( defined $ENV{LOCALIZATION_FOUND} && $ENV{LOCALIZATION_FOUND} eq "YES" ) - { - $source_dir = $ENV{TRYSDF}; - } - elsif( defined $ENV{LOCALIZESDF} && $ENV{LOCALIZESDF} ne "" ) - { - $source_dir = $ENV{LOCALIZESDF}; - } - $source_dir =~ s/\/auxiliary\/localize.sdf$// ; - } - $treestrings = "$ARGV[0]"; - $treestrings=~ s/\/*.tree//g; -} else { - $source_dir_xhp = "$prj/source/presenter/help"; - $tree_src = "$ARGV[0]"; - $tree_src =~ s/\/help.tree//g; - $tree_dest = "$ARGV[3]"; - $tree_dest =~ s/\/help.tree//g; - $source_dir = "$ARGV[2]"; - $source_dir =~ s/\/localize.sdf//g; - $treestrings = "$ARGV[0]"; - $treestrings=~ s/\/help.tree/\/tree_strings.xhp/g; - - if( defined $ENV{LOCALIZATION_FOUND} && $ENV{LOCALIZATION_FOUND} eq "YES" ) - { - $source_dir = $ENV{TRYSDF}; - } - elsif ( defined $ENV{LOCALIZESDF} && $ENV{LOCALIZESDF} ne "" ) - { - $source_dir = $ENV{LOCALIZESDF}; - } - $source_dir =~ s/\/auxiliary\/localize.sdf$// ; -} - -# Get the English tree files as master -#------------------------------- -# Update English from xhp -#------------------------------- -&do_english; -#------------------------------- -# Update localizations from sdf -#------------------------------- - -if( defined $with_lang && $with_lang ne "" ) -{ - @langs = split /\s+/, $with_lang; - &read_loc; - for $l(@langs) - { - #if ($l ne "en-US") { - &do_lang($l); - #} - } -} -else -{ - print "\nNo WITH_LANG set, skipping l10n\n"; -} -#------------------------------- -# - -#################### -# SUBS -#################### -sub terminate { - $err = shift; - print "$err\n\n"; - $msg = <<"MSG"; - -update_tree.pl - all languages in WITH_LANG are processed. WITH_LANG=ALL is - not supported in manual calls. - - Updates the *.tree files. - At first, the English file is updated based on the English - help topic titles as read from the help files. Then, the - localized tree files are written based on the English tree - file and the localized help topic titles. - - Requires a valid LibreOffice build environment. -MSG - print "$msg\n"; - exit( -1 ); - # die "$msg\n"; -} - -#--------------------------------------------------- - -sub do_english { - undef %helpsection; undef %node; - &readtreestrings; - &gettreefiles; -} - -#--------------------------------------------------- -sub do_lang { - $lng = shift; - print "Processing $lng\n"; - &processtreefiles($lng); -} - -#--------------------------------------------------- -sub readtreestrings { - if (open TREE, $treestrings) { - print "Processing readtreestrings\n"; - while (<TREE>) { - chomp; - s/<\/*help:productname>//gis; - if (/help_section/) { - s/^\s*<.*help_section//; - s/<\/.*$//; - ($id = $_) =~ s/^.*id="(\d+)".*$/$1/; - ($title = $_) =~ s/^.*title="(.*)".*$/$1/; - $helpsection{$id} = $title; - } - - if (/node id=/) { - s/^\s*<.*node //; - s/<\/.*$//; - ($id = $_) =~ s/^.*id="(\d+)".*$/$1/; - ($title = $_) =~ s/^.*title="(.*)".*$/$1/; - $node{$id} = $title; - } - } - close TREE; - } else { - &terminate("Error opening $treestrings"); - } -} - -#------------------------------------ -sub gettreefiles { - # Read the tree files from the directory - # this list is also used for all foreign languages - if (opendir ENUS, "$tree_src") { - @treeviews = grep /\.tree/, readdir ENUS; - closedir ENUS; - } else { - &terminate("Cannot open directory $tree_src"); - } -} - -#------------------------------------ -sub processtreefiles { - $lng = shift; - use File::Temp qw/ tempfile /; - use File::Spec; - - for $tv(@treeviews) { - @lines = &readtv("$tree_src/$tv"); - for $l(@lines) { - if ($l =~ /topic/) { - ($id = $l) =~ s/^.*id="([^"]*)".*$/$1/gis; - ($module = $id) =~ s/^([^\/]*).*$/$1/; - $id =~ s/^.*?\///; - $file = "$source_dir_xhp/$lng/$id"; - - if ($lng eq 'en-US') { # english comes from the file - $temp = $l; - $temp =~ s/^.*<topic[^>]+id=".*"[^>]*>([^<]*)<\/topic>.*$/$1/gis; - $temp =~ s/'/\'/gis; $temp=~ s/&/+/gis; - $temp =~ s/"/\'/gis; $temp =~ s/&/+/gis; - - $id =~s/^.*\/(.*.xhp)/$1/; - $l = "<topic id=\"$module/$tree_target_prefix/$id\">$temp</topic>\n"; - } else { # localized comes from the localize sdf - if (defined($loc_title{$lng}->{$id})) { - $xhpname = $id; - $xhpname =~s/^.*\/(.*.xhp)/$1/; - $l = "<topic id=\"$module/$tree_target_prefix/$xhpname\">$loc_title{$lng}->{$id}</topic>\n"; - } else { - } - } - } - - if ($l =~/<node/) { - ($id = $l) =~ s/^.*id="(\d+)".*$/$1/gis; - if ($lng eq 'en-US') { - if (defined($node{$id})) { - $l =~ s/title="(.*)"/title="$node{$id}"/; - } else { - $l =~ s/title="(.*)"/title="NOTFOUND:$id"/; - } - } else { - if (defined($node{$lng}->{$id})) { - $l =~ s/title="(.*)"/title="$node{$lng}->{$id}"/; - } - } - } - - if ($l =~/<help_section/) { - ($id = $l) =~ s/^.*id="(\d+)".*$/$1/gis; - if ($lng eq 'en-US') { - if (defined($helpsection{$id})) { - $l =~ s/title="(.*)"/title="$helpsection{$id}"/; - } else { - $l =~ s/title="(.*)"/title="NOTFOUND:$id"/; - } - } else { - if (defined($helpsection{$lng}->{$id})) { - $l =~ s/title="(.*)"/title="$helpsection{$lng}->{$id}"/; - } - } - } - } - - - my $treeoutdir = "$tree_dest"; - my $tmpname_template=$tv."_XXXXX"; - my ( $treetmpfilehandle, $treetmpfile ) = tempfile($tmpname_template , DIR => File::Spec->tmpdir() ); - close $treetmpfilehandle ; - - if (open TV, ">$treetmpfile") { - for $line(@lines) { - $line =~ s/\$\[officename\]/%PRODUCTNAME/g; - $line =~ s/\$\[officeversion\]/%PRODUCTVERSION/g; - print TV $line; - } - close TV; - chmod 0664, $treetmpfile or &terminate("Cannot change rights on $treetmpfile"); - if( $^O eq 'MSWin32' ) - { - $tree_dest =~ s/\//\\/g ; - unlink "$tree_dest\\$tv" ; - mv $treetmpfile , "$tree_dest\\$tv" or &terminate("Cannot mv $treetmpfile to $tree_dest\\$tv" ); - } - else - { - unlink "$tree_dest/$tv" ; - my $ret=mv $treetmpfile , "$tree_dest/$tv" or &terminate("Cannot write to $tree_dest/$tv - Error $!"); - my $ret=mv "$tree_dest/$tv" , "$tree_dest/$tv" or &terminate("Cannot write to $tree_dest/$tv - Error $!"); - #xmllint is crashing on windows, fixme - if( $^O ne 'cygwin' ) - { - system("$xmllint --noout --noent $tree_dest/$tv") == 0 or &terminate("$tree_dest/$tv is illformed xml ($xmllint on $^O)" ); - } - } - } else { - &terminate("Cannot write to $tvout"); - } - } -} - -#------------------------------------ -sub readtv { - my $f = shift; - if (open TV, $f) { - $/ = "\n"; - my @l = <TV>; - close TV; - return @l; - } else { - &terminate("Error opening $f"); - } -} - -#------------------------------------- -# read entries from localize.sdf files -#------------------------------------- -sub read_loc { - $/ = "\n"; - my $path = "$source_dir"; - @files = `find $source_dir -name localize.sdf`; - for my $fname (@files) { - $FS = '\t'; - open(LOCALIZE_SDF, $fname) || die 'Cannot open "localize.sdf".'."$fname"; - while (<LOCALIZE_SDF>) { - my $sdf_line = $_; - my ($Fld1,$file,$Fld3,$Fld4,$id,$Fld6,$Fld7,$Fld8,$Fld9,$lang,$text) = split($FS, $sdf_line , 12); - next if ( $Fld1 =~ /^#/); - if ($id eq 'tit') { - #strip filename - $file =~ s/.*text\\/text\\/g; - #convert \ to / in filename - $file =~ s/\\/\//g; - $file =~ s/^.*\/(.*)\/(.*)$/$1\/$2/; - #fpe: i46823 - need to encode &s, added encoding - $text =~ s/&(?!amp;)/&/g; - #help xml tags are not allowed in .tree files - $text =~ s/\\<.*?\\>//g; - # add entry to the hash - - $loc_title{$lang}->{$file} = $text; - } - if ($file =~ /tree_strings.xhp/) { - #strip filename - $file =~ s/.*text/text/g; - #convert \ to / in filename - $file =~ s/\\/\//g; - if ($text =~ /^<help_section/) { - #example: <help_section application="scalc" id="08" title="表計算ドキュメント"> - my ($fld1,$app,$fld3,$id,$fld5,$sec_title) = split('"', $text, 7); - #fpe: i46823 - need to encode &s, added encoding - if( defined $sec_title ) - { - $sec_title =~ s/&(?!amp;)/&/g; - #help xml tags are not allowed in .tree files - $sec_title =~ s/\\<.*?\\>//g; - #unquot \<item ... /\> - terminate( "\n\nERROR: Bad string in file '$fname' will cause invalid xml tree file \n---\n'$sdf_line'\n---\nPlease remove or replace < = '<' and > = '>' within the title attribute '$sec_title'\n") , if( $sec_title =~ /[\<\>]/ ); - $helpsection{$lang}->{$id} = $sec_title; - } - } elsif ($text =~/<node id=/) { - # example: <node id="0205" title="Tabelas em documentos de texto"> - # BEWARE: title may contain escaped '"' so only match " not preceded by \ - # using a zero‐width negative look‐behind assertion. - my ($fld1,$id,$fld3,$node_title,$Fld5) = split(/(?<!\\)"/, $text, 5); - #fpe: i46823 - need to encode &s, added encoding - if( defined $node_title ) - { - $node_title =~ s/&(?!amp;)/&/g; - #help xml tags are not allowed in .tree files - $node_title =~ s/\\<.*?\\>//g; - terminate( "\n\nERROR: Bad string in '$fname' will cause invalid xml tree file \n---\n'$sdf_line'\n---\nPlease remove or replace < = '<' and > = '>' within the title attribute '$node_title'\n") , if( $node_title =~ /[\<\>]/ ); - } - $node{$lang}->{$id} = $node_title; - } - } - } - close LOCALIZE_SDF; - } - # statistics - $total_elements=0; - foreach $lang (keys %loc_title) { - $no_elements = scalar(keys(%{$loc_title{$lang}})); - push(@langstat, "$lang:\t ".$no_elements." matches\n"); - $total_elements += $no_elements; - } -} diff --git a/l10ntools/source/cfgmerge.cxx b/l10ntools/source/cfgmerge.cxx index 41db0973fb47..1d0a819b3d4c 100644 --- a/l10ntools/source/cfgmerge.cxx +++ b/l10ntools/source/cfgmerge.cxx @@ -38,105 +38,44 @@ namespace { namespace global { -bool mergeMode = false; -char const * prj = 0; -char const * prjRoot = 0; -char const * inputPathname = 0; -char const * outputPathname = 0; -char const * mergeSrc; +OString inputPathname; boost::scoped_ptr< CfgParser > parser; } - -void handleArguments(int argc, char ** argv) { - for (int i = 1; i != argc; ++i) { - if (std::strcmp(argv[i], "-e") == 0) { - // ignored, used to be "Disable writing errorlog" - } else if (std::strcmp(argv[i], "-i") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::inputPathname = argv[i]; - } else if (std::strcmp(argv[i], "-l") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - Export::sLanguages = argv[i]; - } else if (std::strcmp(argv[i], "-m") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::mergeSrc = argv[i]; - global::mergeMode = true; - } else if (std::strcmp(argv[i], "-o") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::outputPathname = argv[i]; - } else if (std::strcmp(argv[i], "-p") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::prj = argv[i]; - } else if (std::strcmp(argv[i], "-r") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::prjRoot = argv[i]; - } else { - global::inputPathname = 0; // no valid command line - break; - } - } - if (global::inputPathname == 0 || global::outputPathname == 0) { - std::fprintf( - stderr, - ("Syntax: cfgex [-p Prj] [-r PrjRoot] -i FileIn -o FileOut" - " [-m DataBase] [-e] [-l l1,l2,...]\n" - " Prj: Project\n" - " PrjRoot: Path to project root (../.. etc.)\n" - " FileIn: Source files (*.src)\n" - " FileOut: Destination file (*.*)\n" - " DataBase: Mergedata (*.sdf)\n" - " -e: ignored\n" - " -l: Restrict the handled languages; l1, l2, ... are elements of" - " (de, en-US, ...)\n")); - std::exit(EXIT_FAILURE); - } - Export::InitLanguages(); -} - } extern "C" { FILE * init(int argc, char ** argv) { - handleArguments(argc, argv); - FILE * pFile = std::fopen(global::inputPathname, "r"); + HandledArgs aArgs; + if ( !Export::handleArguments(argc, argv, aArgs) ) + { + Export::writeUsage("cfgex","xcu"); + std::exit(EXIT_FAILURE); + } + Export::InitLanguages(); + global::inputPathname = aArgs.m_sInputFile; + + FILE * pFile = std::fopen(global::inputPathname.getStr(), "r"); if (pFile == 0) { std::fprintf( stderr, "Error: Cannot open file \"%s\"\n", - global::inputPathname); + global::inputPathname.getStr() ); std::exit(EXIT_FAILURE); } - if (global::mergeMode) { + if (aArgs.m_bMergeMode) { global::parser.reset( new CfgMerge( - global::mergeSrc, global::outputPathname, + aArgs.m_sMergeSrc.getStr(), aArgs.m_sOutputFile.getStr(), global::inputPathname)); } else { global::parser.reset( new CfgExport( - global::outputPathname, global::prj, - common::pathnameToken(global::inputPathname, global::prjRoot))); + aArgs.m_sOutputFile.getStr(), aArgs.m_sPrj.getStr(), + common::pathnameToken(global::inputPathname.getStr(), + aArgs.m_sPrjRoot.getStr()))); } return pFile; diff --git a/l10ntools/source/export.cxx b/l10ntools/source/export.cxx index 8fe8057188c3..13870da558a2 100644 --- a/l10ntools/source/export.cxx +++ b/l10ntools/source/export.cxx @@ -42,102 +42,45 @@ MergeDataFile * pMergeDataFile = 0; //TODO namespace global { -bool mergeMode = false; -char const * prj = 0; -char const * prjRoot = 0; -char const * inputPathname = 0; -char const * outputPathname = 0; -char const * mergeSrc; +OString prj; +OString prjRoot; +OString inputPathname; boost::scoped_ptr< Export > exporter; } - -void handleArguments(int argc, char ** argv) { - for (int i = 1; i != argc; ++i) { - if (std::strcmp(argv[i], "-e") == 0) { - // ingored, used to be "Disable writing errorlog" - } else if (std::strcmp(argv[i], "-i") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::inputPathname = argv[i]; - } else if (std::strcmp(argv[i], "-l") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - Export::sLanguages = argv[i]; - } else if (std::strcmp(argv[i], "-m") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::mergeSrc = argv[i]; - global::mergeMode = true; - } else if (std::strcmp(argv[i], "-o") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::outputPathname = argv[i]; - } else if (std::strcmp(argv[i], "-p") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::prj = argv[i]; - } else if (std::strcmp(argv[i], "-r") == 0) { - if (++i == argc) { - global::inputPathname = 0; // no valid command line - break; - } - global::prjRoot = argv[i]; - } else { - global::inputPathname = 0; // no valid command line - break; - } - } - if (global::inputPathname == 0 || global::outputPathname == 0) { - std::fprintf( - stderr, - ("Syntax: transex3 [-p Prj] [-r PrjRoot] -i FileIn -o FileOut" - " [-m DataBase] [-e] [-l l1,l2,...]\n" - " Prj: Project\n" - " PrjRoot: Path to project root (../.. etc.)\n" - " FileIn: Source files (*.src)\n" - " FileOut: Destination file (*.*)\n" - " DataBase: Mergedata (*.sdf)\n" - " -e: ignored\n" - " -l: Restrict the handled languages; l1, l2, ... are elements of" - " (de, en-US, ...)\n")); - std::exit(EXIT_FAILURE); - } - Export::InitLanguages(); -} - } extern "C" { FILE * init(int argc, char ** argv) { - handleArguments(argc, argv); - FILE * pFile = std::fopen(global::inputPathname, "r"); + HandledArgs aArgs; + if ( !Export::handleArguments(argc, argv, aArgs) ) + { + Export::writeUsage("transex3","src/hrc"); + std::exit(EXIT_FAILURE); + } + Export::InitLanguages(); + global::prj = aArgs.m_sPrj; + global::prjRoot = aArgs.m_sPrjRoot; + global::inputPathname = aArgs.m_sInputFile; + + FILE * pFile = std::fopen(global::inputPathname.getStr(), "r"); if (pFile == 0) { std::fprintf( stderr, "Error: Cannot open file \"%s\"\n", - global::inputPathname); + global::inputPathname.getStr()); std::exit(EXIT_FAILURE); } - if (global::mergeMode) { + if (aArgs.m_bMergeMode) { global::exporter.reset( - new Export(global::mergeSrc, global::outputPathname)); + new Export(aArgs.m_sMergeSrc.getStr(), aArgs.m_sOutputFile.getStr())); } else { sActFileName = - common::pathnameToken(global::inputPathname, global::prjRoot); - global::exporter.reset(new Export(global::outputPathname)); + common::pathnameToken( + global::inputPathname.getStr(), global::prjRoot.getStr()); + global::exporter.reset(new Export(aArgs.m_sOutputFile.getStr())); } global::exporter->Init(); diff --git a/l10ntools/source/export2.cxx b/l10ntools/source/export2.cxx index 726f36a59541..5ef2231f6d6e 100644 --- a/l10ntools/source/export2.cxx +++ b/l10ntools/source/export2.cxx @@ -31,6 +31,15 @@ #include <time.h> #include <stdlib.h> +//flags for handleArguments() +#define STATE_NON 0x0001 +#define STATE_INPUT 0x0002 +#define STATE_OUTPUT 0x0003 +#define STATE_PRJ 0x0004 +#define STATE_ROOT 0x0005 +#define STATE_MERGESRC 0x0006 +#define STATE_LANGUAGES 0x0007 + // // class ResData(); // @@ -82,6 +91,108 @@ rtl::OString Export::sLanguages; rtl::OString Export::sForcedLanguages; /*****************************************************************************/ +bool Export::handleArguments( + int argc, char * argv[], HandledArgs& o_aHandledArgs) +{ + o_aHandledArgs = HandledArgs(); + sLanguages = ""; + sal_uInt16 nState = STATE_NON; + + for( int i = 1; i < argc; i++ ) + { + if ( OString( argv[ i ] ).toAsciiUpperCase() == "-I" ) + { + nState = STATE_INPUT; // next token specifies source file + } + else if ( OString( argv[ i ] ).toAsciiUpperCase() == "-O" ) + { + nState = STATE_OUTPUT; // next token specifies the dest file + } + else if ( OString( argv[ i ] ).toAsciiUpperCase() == "-P" ) + { + nState = STATE_PRJ; // next token specifies the cur. project + } + else if ( OString( argv[ i ] ).toAsciiUpperCase() == "-R" ) + { + nState = STATE_ROOT; // next token specifies path to project root + } + else if ( OString( argv[ i ] ).toAsciiUpperCase() == "-M" ) + { + nState = STATE_MERGESRC; // next token specifies the merge database + } + else if ( OString( argv[ i ] ).toAsciiUpperCase() == "-L" ) + { + nState = STATE_LANGUAGES; + } + else + { + switch ( nState ) + { + case STATE_NON: + { + return false; // no valid command line + } + case STATE_INPUT: + { + o_aHandledArgs.m_sInputFile = OString( argv[i] ); + } + break; + case STATE_OUTPUT: + { + o_aHandledArgs.m_sOutputFile = OString( argv[i] ); + } + break; + case STATE_PRJ: + { + o_aHandledArgs.m_sPrj = OString( argv[i] ); + } + break; + case STATE_ROOT: + { + o_aHandledArgs.m_sPrjRoot = OString( argv[i] ); + } + break; + case STATE_MERGESRC: + { + o_aHandledArgs.m_sMergeSrc = OString( argv[i] ); + o_aHandledArgs.m_bMergeMode = true; + } + break; + case STATE_LANGUAGES: + { + sLanguages = OString( argv[i] ); + } + break; + } + } + } + if( !o_aHandledArgs.m_sInputFile.isEmpty() && + !o_aHandledArgs.m_sOutputFile.isEmpty() ) + { + return true; + } + else + { + o_aHandledArgs = HandledArgs(); + return false; + } +} + +void Export::writeUsage(const OString& rName, const OString& rFileType) +{ + std::cout + << "Syntax: " << rName.getStr() + << " [-p Prj] [-r PrjRoot] -i FileIn -o FileOut" + << " [-m DataBase] [-l l1,l2,...]\n" + << " Prj: Project\n" + << " PrjRoot: Path to project root (../.. etc.)\n" + << " FileIn: Source files (*." << rFileType.getStr() << ")\n" + << " FileOut: Destination file (*.*)\n" + << " DataBase: Mergedata (*.po)\n" + << " -l: Restrict the handled languages; l1, l2, ... are elements of" + << " (de, en-US, ...)\n"; +} + /*****************************************************************************/ void Export::SetLanguages( std::vector<rtl::OString> val ){ /*****************************************************************************/ diff --git a/l10ntools/source/helpex.cxx b/l10ntools/source/helpex.cxx index 470b4f1383bc..8dca205cf36e 100644 --- a/l10ntools/source/helpex.cxx +++ b/l10ntools/source/helpex.cxx @@ -28,214 +28,31 @@ #include "helpmerge.hxx" -// defines to parse command line -#define STATE_NON 0x0001 -#define STATE_INPUT 0x0002 -#define STATE_OUTPUT 0x0003 -#define STATE_PRJ 0x0004 -#define STATE_ROOT 0x0005 -#define STATE_SDFFILE 0x0006 -#define STATE_ERRORLOG 0x0007 -#define STATE_BREAKHELP 0x0008 -#define STATE_UNMERGE 0x0009 -#define STATE_LANGUAGES 0x000A -#define STATE_FORCE_LANGUAGES 0x000B -#define STATE_OUTPUTX 0xfe -#define STATE_OUTPUTY 0xff - -// set of global variables -rtl::OString sInputFile; -sal_Bool bEnableExport; -sal_Bool bMergeMode; -rtl::OString sPrj; -rtl::OString sPrjRoot; -rtl::OString sOutputFile; -rtl::OString sOutputFileX; -rtl::OString sOutputFileY; -rtl::OString sSDFFile; - -/*****************************************************************************/ -sal_Bool ParseCommandLine( int argc, char* argv[]) -/*****************************************************************************/ -{ - bEnableExport = sal_False; - bMergeMode = sal_False; - sPrj = ""; - sPrjRoot = ""; - Export::sLanguages = ""; - Export::sForcedLanguages = ""; - - sal_uInt16 nState = STATE_NON; - sal_Bool bInput = sal_False; - - // parse command line - for( int i = 1; i < argc; i++ ) - { - rtl::OString aArg = rtl::OString(argv[i]).toAsciiUpperCase(); - if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-I"))) - nState = STATE_INPUT; // next tokens specifies source files - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-O"))) - nState = STATE_OUTPUT; // next token specifies the dest file - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-X"))) - nState = STATE_OUTPUTX; // next token specifies the dest file - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-Y" ))) - nState = STATE_OUTPUTY; // next token specifies the dest file - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-P" ))) - nState = STATE_PRJ; // next token specifies the cur. project - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-LF"))) - nState = STATE_FORCE_LANGUAGES; - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-R" ))) - nState = STATE_ROOT; // next token specifies path to project root - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-M" ))) - nState = STATE_SDFFILE; // next token specifies the merge database - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-E" ))) - { - nState = STATE_ERRORLOG; - } - else if (aArg.equalsL(RTL_CONSTASCII_STRINGPARAM("-L" ))) - nState = STATE_LANGUAGES; - else - { - switch ( nState ) - { - case STATE_NON: { - return sal_False; // no valid command line - } - //break; - case STATE_INPUT: { - sInputFile = argv[ i ]; - bInput = sal_True; // source file found - } - break; - case STATE_OUTPUT: { - sOutputFile = argv[ i ]; // the dest. file - } - break; - case STATE_OUTPUTX: { - sOutputFileX = argv[ i ]; // the dest. file - } - break; - case STATE_OUTPUTY: { - sOutputFileY = argv[ i ]; // the dest. file - } - break; - case STATE_PRJ: { - sPrj = argv[ i ]; - } - break; - case STATE_ROOT: { - sPrjRoot = argv[ i ]; // path to project root - } - break; - case STATE_SDFFILE: { - sSDFFile = argv[ i ]; - bMergeMode = sal_True; // activate merge mode, cause merge database found - } - break; - case STATE_LANGUAGES: { - Export::sLanguages = argv[ i ]; - } - case STATE_FORCE_LANGUAGES:{ - Export::sForcedLanguages = argv[ i ]; - } - break; - } - } - } - - if ( bInput ) { - // command line is valid - bEnableExport = sal_True; - return sal_True; - } - - // command line is not valid - return sal_False; -} - - -/*****************************************************************************/ -void Help() -/*****************************************************************************/ -{ - fprintf( stdout, "Syntax: HELPEX[-p Prj][-r PrjRoot]-i FileIn ( -o FileOut | -x path -y relfile )[-m DataBase][-e][-b][-u][-L l1,l2,...] -LF l1,l2 \n" ); - fprintf( stdout, " Prj: Project\n" ); - fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); - fprintf( stdout, " FileIn: Source file (*.lng)\n" ); - fprintf( stdout, " FileOut: Destination file (*.*)\n" ); - fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); - fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (en-US,fr,de...)\n" ); - fprintf( stdout, " -LF: Force the creation of that languages\n" ); - -} - -/*****************************************************************************/ #ifndef TESTDRIVER SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { - if ( !ParseCommandLine( argc, argv )) { - Help(); + HandledArgs aArgs; + if ( !Export::handleArguments( argc, argv, aArgs) ) { + Export::writeUsage("helpex","xhp"); return 1; } //sal_uInt32 startfull = Export::startMessure(); - - bool hasInputList = sInputFile[0]=='@'; bool hasNoError = true; - if ( sOutputFile.getLength() ){ // Merge single file ? - HelpParser aParser( sInputFile ); - - if ( bMergeMode ) - { - //sal_uInt64 startreadloc = Export::startMessure(); - MergeDataFile aMergeDataFile(sSDFFile, sInputFile, false); - - hasNoError = aParser.Merge( sSDFFile, sOutputFile , Export::sLanguages , aMergeDataFile ); - } - else - hasNoError = aParser.CreateSDF( sOutputFile, sPrj, sPrjRoot, sInputFile, new XMLFile( rtl::OUString('0') ), "help" ); - }else if ( sOutputFileX.getLength() && sOutputFileY.getLength() && hasInputList ) { // Merge multiple files ? - if ( bMergeMode ){ - - ifstream aFStream( sInputFile.copy( 1 ).getStr() , ios::in ); - - if( !aFStream ){ - std::cerr << "ERROR: - helpex - Can't open the file " << sInputFile.copy( 1 ).getStr() << "\n"; - std::exit(EXIT_FAILURE); - } - - vector<rtl::OString> filelist; - rtl::OStringBuffer filename; - sal_Char aChar; - while( aFStream.get( aChar ) ) - { - if( aChar == ' ' || aChar == '\n') - filelist.push_back(filename.makeStringAndClear()); - else - filename.append( aChar ); - } - if( filename.getLength() > 0 ) - filelist.push_back(filename.makeStringAndClear()); - - aFStream.close(); - rtl::OString sHelpFile; // dummy - MergeDataFile aMergeDataFile( sSDFFile, sHelpFile, false ); - - std::vector<rtl::OString> aLanguages; - HelpParser::parse_languages( aLanguages , aMergeDataFile ); - - bool bCreateDir = true; - for( vector<rtl::OString>::iterator pos = filelist.begin() ; pos != filelist.end() ; ++pos ) - { - sHelpFile = *pos; - - HelpParser aParser( sHelpFile ); - hasNoError = aParser.Merge( sSDFFile , sOutputFileX , sOutputFileY , true , aLanguages , aMergeDataFile , bCreateDir ); - bCreateDir = false; - } - } - } else - std::cerr << "helpex ERROR: Wrong input parameters!\n"; + HelpParser aParser( aArgs.m_sInputFile ); + if ( aArgs.m_bMergeMode ) + { + //sal_uInt64 startreadloc = Export::startMessure(); + MergeDataFile aMergeDataFile( aArgs.m_sMergeSrc, aArgs.m_sInputFile, false ); + hasNoError = aParser.Merge( aArgs.m_sMergeSrc, aArgs.m_sOutputFile , Export::sLanguages , aMergeDataFile ); + } + else + { + hasNoError = + aParser.CreateSDF( + aArgs.m_sOutputFile, aArgs.m_sPrj, aArgs.m_sPrjRoot, + aArgs.m_sInputFile, new XMLFile( OUString('0') ), "help" ); + } if( hasNoError ) return 0; diff --git a/l10ntools/source/lngex.cxx b/l10ntools/source/lngex.cxx index ab2f0afe0eb5..eb5cccc578fc 100644 --- a/l10ntools/source/lngex.cxx +++ b/l10ntools/source/lngex.cxx @@ -25,141 +25,21 @@ #include "lngmerge.hxx" -// defines to parse command line -#define STATE_NON 0x0001 -#define STATE_INPUT 0x0002 -#define STATE_OUTPUT 0x0003 -#define STATE_PRJ 0x0004 -#define STATE_ROOT 0x0005 -#define STATE_MERGESRC 0x0006 -#define STATE_ERRORLOG 0x0007 -#define STATE_BREAKHELP 0x0008 -#define STATE_UNMERGE 0x0009 -#define STATE_ULF 0x000A -#define STATE_LANGUAGES 0x000B - -// set of global variables -rtl::OString sInputFile; -sal_Bool bEnableExport; -sal_Bool bMergeMode; -sal_Bool bUTF8; -sal_Bool bULF; // ULF = Unicode Language File -rtl::OString sPrj; -rtl::OString sPrjRoot; -rtl::OString sOutputFile; -rtl::OString sMergeSrc; - -/*****************************************************************************/ -sal_Bool ParseCommandLine( int argc, char* argv[]) -/*****************************************************************************/ -{ - bEnableExport = sal_False; - bMergeMode = sal_False; - bUTF8 = sal_True; - bULF = sal_False; - sPrj = ""; - sPrjRoot = ""; - Export::sLanguages = ""; - - sal_uInt16 nState = STATE_NON; - sal_Bool bInput = sal_False; - - // parse command line - for( int i = 1; i < argc; i++ ) { - rtl::OString sSwitch = rtl::OString(argv[i]).toAsciiUpperCase(); - if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-I"))) - nState = STATE_INPUT; // next tokens specifies source files - else if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-O"))) - nState = STATE_OUTPUT; // next token specifies the dest file - else if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-P"))) - nState = STATE_PRJ; // next token specifies the cur. project - else if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-R"))) - nState = STATE_ROOT; // next token specifies path to project root - else if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-M"))) - nState = STATE_MERGESRC; // next token specifies the merge database - else if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-E"))) - { - nState = STATE_ERRORLOG; - } - else if (sSwitch.equalsL(RTL_CONSTASCII_STRINGPARAM("-L"))) - nState = STATE_LANGUAGES; - else - { - switch ( nState ) { - case STATE_NON: { - return sal_False; // no valid command line - } - //break; - case STATE_INPUT: { - sInputFile = argv[ i ]; - bInput = sal_True; // source file found - } - break; - case STATE_OUTPUT: { - sOutputFile = argv[ i ]; // the dest. file - } - break; - case STATE_PRJ: { - sPrj = argv[ i ]; - } - break; - case STATE_ROOT: { - sPrjRoot = argv[ i ]; // path to project root - } - break; - case STATE_MERGESRC: { - sMergeSrc = argv[ i ]; - bMergeMode = sal_True; // activate merge mode, cause merge database found - } - break; - case STATE_LANGUAGES: { - Export::sLanguages = argv[ i ]; - } - break; - } - } - } - - if ( bInput ) { - // command line is valid - bULF = sal_True; - bEnableExport = sal_True; - return sal_True; - } - - // command line is not valid - return sal_False; -} - - -/*****************************************************************************/ -void Help() -/*****************************************************************************/ -{ - fprintf( stdout, "Syntax:ULFEX[-p Prj][-r PrjRoot]-i FileIn -o FileOut[-m DataBase][-L l1,l2,...]\n" ); - fprintf( stdout, " Prj: Project\n" ); - fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); - fprintf( stdout, " FileIn: Source file (*.lng)\n" ); - fprintf( stdout, " FileOut: Destination file (*.*)\n" ); - fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); - fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US...)\n" ); -} - SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { - if ( !ParseCommandLine( argc, argv )) + + HandledArgs aArgs; + if ( !Export::handleArguments(argc, argv, aArgs) ) { - Help(); + Export::writeUsage("ulfex","ulf"); return 1; } - if (!sOutputFile.isEmpty()) - { - LngParser aParser( sInputFile, bULF ); - if ( bMergeMode ) - aParser.Merge(sMergeSrc, sOutputFile); - else - aParser.CreateSDF( sOutputFile, sPrj, sPrjRoot ); - } + LngParser aParser( aArgs.m_sInputFile, true ); + if ( aArgs.m_bMergeMode ) + aParser.Merge(aArgs.m_sMergeSrc, aArgs.m_sOutputFile); + else + aParser.CreateSDF( + aArgs.m_sOutputFile, aArgs.m_sPrj, aArgs.m_sPrjRoot ); return 0; } diff --git a/l10ntools/source/lngmerge.cxx b/l10ntools/source/lngmerge.cxx index 00a58d25a0ad..7294e27339f6 100644 --- a/l10ntools/source/lngmerge.cxx +++ b/l10ntools/source/lngmerge.cxx @@ -50,10 +50,10 @@ LngParser::LngParser(const rtl::OString &rLngFile, if (aStream.is_open()) { bool bFirstLine = true; + std::string s; + std::getline(aStream, s); while (!aStream.eof()) { - std::string s; - std::getline(aStream, s); rtl::OString sLine(s.data(), s.length()); if( bFirstLine ) @@ -64,7 +64,9 @@ LngParser::LngParser(const rtl::OString &rLngFile, } pLines->push_back( new rtl::OString(sLine) ); + std::getline(aStream, s); } + pLines->push_back( new rtl::OString() ); } else nError = LNG_COULD_NOT_OPEN; diff --git a/l10ntools/source/localize.cxx b/l10ntools/source/localize.cxx index 8dfb8ec4835d..107d516cd354 100644 --- a/l10ntools/source/localize.cxx +++ b/l10ntools/source/localize.cxx @@ -40,16 +40,12 @@ #include "sal/main.h" #include "sal/types.h" +#include "po.hxx" + using namespace std; namespace { -namespace global { - -std::ofstream output; - -} - rtl::OUString getEnvironment(rtl::OUString const & variable) { rtl::OUString value; if (osl_getEnvironment(variable.pData, &value.pData) != osl_Process_E_None) @@ -164,7 +160,8 @@ bool passesPositiveList(rtl::OUString const & url) { void handleCommand( rtl::OUString const & project, rtl::OUString const & projectRoot, - rtl::OUString const & url, rtl::OUString const & executable, bool positive) + rtl::OUString const & url, rtl::OUString const & actualDir, + PoOfstream & rPoOutPut, rtl::OUString const & executable, bool positive) { if (positive ? passesPositiveList(url) : passesNegativeList(url)) { rtl::OUString inPath; @@ -196,7 +193,7 @@ void handleCommand( RTL_CONSTASCII_USTRINGPARAM("INPATH_FOR_BUILD")))); buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("/bin/")); buf.append(executable); - buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -e -p ")); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -p ")); buf.append(project); buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(" -r ")); buf.append(projectRoot); @@ -229,23 +226,94 @@ void handleCommand( } std::ifstream in(outPath8.getStr()); if (!in.is_open()) { - std::cerr << "Error: Cannot open " << outPath.getStr() << "\n"; + std::cerr << "Error: Cannot open " << outPath8.getStr() << "\n"; throw false; //TODO } + + std::string s; + std::getline(in, s); + if (!in.eof() && !rPoOutPut.isOpen()) + { + rtl::OUString outDirUrl; + if (osl::FileBase::getFileURLFromSystemPath(actualDir. + copy(0,actualDir.lastIndexOf('/')), outDirUrl) + != osl::FileBase::E_None) + { + std::cerr << "Error: Cannot convert pathname to URL\n"; + throw false; //TODO + } + osl::Directory::createPath(outDirUrl); + + rtl::OString outFilePath; + if (!actualDir.concat(".pot"). + convertToString( + &outFilePath, osl_getThreadTextEncoding(), + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) + { + std::cerr << "Error: Cannot convert pathname from UTF-16\n"; + throw false; //TODO + } + rPoOutPut.open(outFilePath.getStr()); + if (!rPoOutPut.isOpen()) + { + std::cerr + << "Error: Cannot open po file " + << outFilePath.getStr() << "\n"; + throw false; //TODO + } + + //Add header to actual po file + { + const sal_Int32 nProjectInd = inPath.indexOf(project); + const OString relativPath = + project == OUString("dictionaries") ? + OUStringToOString( + inPath.copy( nProjectInd + 13, + inPath.lastIndexOf('/')- nProjectInd - 13), + RTL_TEXTENCODING_UTF8 ) : + OUStringToOString( + inPath.copy( nProjectInd, + inPath.lastIndexOf('/')- nProjectInd), + RTL_TEXTENCODING_UTF8 ); + + rPoOutPut.writeHeader(PoHeader(relativPath)); + } + } while (!in.eof()) { - std::string s; + OString sLine = OString(s.data(),s.length()); + try + { + if (!sLine.getToken(PoEntry::TEXT,'\t').isEmpty()) + rPoOutPut.writeEntry(PoEntry(sLine)); + if (!sLine.getToken(PoEntry::QUICKHELPTEXT,'\t').isEmpty()) + rPoOutPut.writeEntry(PoEntry(sLine,PoEntry::TQUICKHELPTEXT)); + if (!sLine.getToken(PoEntry::TITLE,'\t').isEmpty()) + rPoOutPut.writeEntry(PoEntry(sLine,PoEntry::TTITLE)); + } + catch(PoEntry::Exception& aException) + { + if(aException == PoEntry::INVALIDSDFLINE) + { + std::cerr + << executable + << "'s output is invalid:\n" + << sLine.replaceAll("\t","\\t").getStr() + << std::endl; + throw false; //TODO + } + } std::getline(in, s); - if (!s.empty()) - global::output << s << '\n'; - } + }; in.close(); } } void handleFile( rtl::OUString const & project, rtl::OUString const & projectRoot, - rtl::OUString const & url) + rtl::OUString const & url, rtl::OUString const & actualDir, + PoOfstream & rPoOutPut) { struct Command { char const * extension; @@ -262,13 +330,14 @@ 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)) { handleCommand( - project, projectRoot, url, + project, projectRoot, url, actualDir, rPoOutPut, rtl::OUString::createFromAscii(commands[i].executable), commands[i].positive); break; @@ -378,8 +447,9 @@ bool excludeDirectory(rtl::OUString const & directory) { /// level <= 0) void handleDirectory( rtl::OUString const & url, int level, rtl::OUString const & project, - rtl::OUString const & projectRoot) + rtl::OUString const & projectRoot, rtl::OUString const & actualDir) { + PoOfstream aPoOutPut; osl::Directory dir(url); if (dir.open() != osl::FileBase::E_None) { std::cerr @@ -409,7 +479,8 @@ void handleDirectory( case -1: // the clone or src directory if (stat.getFileType() == osl::FileStatus::Directory) { handleDirectory( - stat.getFileURL(), 0, rtl::OUString(), rtl::OUString()); + stat.getFileURL(), 0, rtl::OUString(), + rtl::OUString(), actualDir); } break; case 0: // a root directory @@ -417,12 +488,14 @@ void handleDirectory( if (includeProject(stat.getFileName())) { handleDirectory( stat.getFileURL(), 1, stat.getFileName(), - rtl::OUString()); - } else if ( stat.getFileName() == "clone" || stat.getFileName() == "src" ) + rtl::OUString(), actualDir.concat("/"). + concat(stat.getFileName())); + } else if ( stat.getFileName() == "clone" || + stat.getFileName() == "src" ) { handleDirectory( stat.getFileURL(), -1, rtl::OUString(), - rtl::OUString()); + rtl::OUString(), actualDir); } } break; @@ -434,24 +507,29 @@ void handleDirectory( pr += rtl::OUString('/'); } pr += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("..")); - handleDirectory(stat.getFileURL(), 2, project, pr); + handleDirectory(stat.getFileURL(), 2, project, pr, + actualDir.concat("/"). + concat(stat.getFileName())); } } else { - handleFile(project, projectRoot, stat.getFileURL()); + handleFile(project, projectRoot, + stat.getFileURL(), actualDir, aPoOutPut); } break; } } + if (aPoOutPut.isOpen()) + aPoOutPut.close(); if (dir.close() != osl::FileBase::E_None) { std::cerr << "Error: Cannot close directory\n"; throw false; //TODO } } -void handleProjects(char const * root) { +void handleProjects(char const * sourceRoot, char const * destRoot) { rtl::OUString root16; if (!rtl_convertStringToUString( - &root16.pData, root, rtl_str_getLength(root), + &root16.pData, sourceRoot, rtl_str_getLength(sourceRoot), osl_getThreadTextEncoding(), (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR @@ -467,9 +545,19 @@ void handleProjects(char const * root) { std::cerr << "Error: Cannot convert pathname to URL\n"; throw false; //TODO } - handleDirectory(rootUrl, 0, rtl::OUString(), rtl::OUString()); + rtl::OUString outPutRoot; + if (!rtl_convertStringToUString( + &outPutRoot.pData, destRoot, rtl_str_getLength(destRoot), + osl_getThreadTextEncoding(), + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + std::cerr << "Error: Cannot convert pathname to UTF-16\n"; + throw false; //TODO + } + handleDirectory(rootUrl, 0, rtl::OUString(), rtl::OUString(), outPutRoot); } - } SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { @@ -482,17 +570,11 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { "Syntax: localize <source-root> <outfile>\n"); std::exit(EXIT_FAILURE); } - global::output.open(argv[2], std::ios_base::out | std::ios_base::trunc); - if (!global::output.is_open()) { - std::cerr << "Error: Cannot append to " << argv[2] << '\n'; - std::exit(EXIT_FAILURE); - } try { - handleProjects(argv[1]); + handleProjects(argv[1],argv[2]); } catch (bool) { //TODO return EXIT_FAILURE; } - global::output.close(); return EXIT_SUCCESS; } diff --git a/l10ntools/source/merge.cxx b/l10ntools/source/merge.cxx index e4fc598322a3..80188f53fb87 100644 --- a/l10ntools/source/merge.cxx +++ b/l10ntools/source/merge.cxx @@ -25,6 +25,7 @@ #include <vector> #include "export.hxx" +#include "po.hxx" namespace { @@ -35,6 +36,27 @@ namespace rFilename.lastIndexOf( '\\' ), rFilename.lastIndexOf( '/' ))+1); }; + + static bool lcl_ReadPoChecked( + PoEntry& o_rPoEntry, PoIfstream& rPoFile, + const std::string& rFileName) + { + try + { + rPoFile.readEntry( o_rPoEntry ); + } + catch( PoIfstream::Exception& aException ) + { + if( aException == PoIfstream::INVALIDENTRY ) + { + printf( + "Warning : %s contains invalid entry\n", + rFileName.c_str() ); + return false; + } + } + return true; + } } // @@ -132,43 +154,129 @@ MergeDataFile::MergeDataFile( const rtl::OString &rFile, bool bCaseSensitive) { - std::ifstream aInputStream(rFileName.getStr()); - const ::rtl::OString sHACK(RTL_CONSTASCII_STRINGPARAM("HACK")); - const ::rtl::OString sFileNormalized(lcl_NormalizeFilename(rFile)); - const bool isFileEmpty = sFileNormalized.isEmpty(); - - if (!aInputStream.is_open()) + std::ifstream aInputStream( rFileName.getStr() ); + if ( !aInputStream.is_open() ) { - printf("Warning : Can't open %s\n", rFileName.getStr()); + printf("Warning : Can't open po path container file"); return; } - while (!aInputStream.eof()) + std::string sPoFileName; + aInputStream >> sPoFileName; + bool bFirstLang = true; + while( !aInputStream.eof() ) { - std::string buf; - std::getline(aInputStream, buf); - rtl::OString sLine(buf.data(), buf.length()); - sal_Int32 n = 0; - // Skip all wrong filenames - const ::rtl::OString filename = lcl_NormalizeFilename(sLine.getToken(1, '\t', n)); // token 1 - if (isFileEmpty || (!isFileEmpty && filename.equals(sFileNormalized)) ) + const OString sHack("HACK"); + const OString sFileName( lcl_NormalizeFilename(rFile) ); + PoIfstream aPoInput; + aPoInput.open( OString(sPoFileName.data(), sPoFileName.length()) ); + if ( !aPoInput.isOpen() ) + { + printf( "Warning : Can't open %s\n", sPoFileName.c_str() ); + return; + } + PoHeader aPoHeader; + try + { + aPoInput.readHeader( aPoHeader ); + } + catch( PoIfstream::Exception& aException ) { - const rtl::OString sTYP = sLine.getToken( 1, '\t', n ); // token 3 - const rtl::OString sGID = sLine.getToken( 0, '\t', n ); // token 4 - const rtl::OString sLID = sLine.getToken( 0, '\t', n ); // token 5 - rtl::OString sPFO = sLine.getToken( 1, '\t', n ); // token 7 - sPFO = sHACK; - rtl::OString nLANG = sLine.getToken( 1, '\t', n ); // token 9 - nLANG = nLANG.trim(); - const rtl::OString sTEXT = sLine.getToken( 0, '\t', n ); // token 10 - const rtl::OString sQHTEXT = sLine.getToken( 1, '\t', n ); // token 12 - const rtl::OString sTITLE = sLine.getToken( 0, '\t', n ); // token 13 - - if (!nLANG.equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("en-US"))) + if( aException == PoIfstream::INVALIDHEADER ) + { + printf( + "Warning : %s has invalid header\n", + sPoFileName.c_str() ); + return; + } + } + OString sLang; + try + { + sLang = aPoHeader.getLanguage(); + } + catch( PoHeader::Exception& aException ) + { + if( aException == PoHeader::NOLANG ) + { + printf( + "Warning : %s' header not has language specification\n", + sPoFileName.c_str() ); + return; + } + } + aLanguageSet.insert( sLang ); + PoEntry aNextPo; + do + { + if( !lcl_ReadPoChecked(aNextPo, aPoInput, sPoFileName) ) + { + return; + } + } while( !aPoInput.eof() && aNextPo.getSourceFile() != sFileName ); + while( !aPoInput.eof() && aNextPo.getSourceFile() == sFileName ) + { + PoEntry aActPo( aNextPo ); + + bool bInSameComp = false; + OString sText; + OString sQHText; + OString sTitle; + OString sExText; + OString sExQHText; + OString sExTitle; + OString sQTZText; + OString sQTZQHText; + OString sQTZTitle; + do + { + if( bInSameComp ) + aActPo = aNextPo; + OString sTemp = aActPo.getMsgStr(); + if( aActPo.isFuzzy() || sTemp.isEmpty() ) + sTemp = aActPo.getMsgId(); + switch( aActPo.getType() ) + { + case PoEntry::TTEXT: + sText = sTemp; + sExText = aActPo.getMsgId(); + sQTZText = aActPo.getKeyId(); + break; + case PoEntry::TQUICKHELPTEXT: + sQHText = sTemp; + sExQHText = aActPo.getMsgId(); + sQTZQHText = aActPo.getKeyId(); + break; + case PoEntry::TTITLE: + sTitle = sTemp; + sExTitle = aActPo.getMsgId(); + sQTZTitle = aActPo.getKeyId(); + break; + } + if( !lcl_ReadPoChecked(aNextPo, aPoInput, sPoFileName) ) + { + return; + } + } while( !aPoInput.eof() && + ( bInSameComp = PoEntry::IsInSameComp(aActPo, aNextPo) ) ); + + InsertEntry( + aActPo.getResourceType(), aActPo.getGroupId(), + aActPo.getLocalId(), sHack, sLang, sText, + sQHText, sTitle, sFileName, bCaseSensitive ); + + if( bFirstLang ) { - aLanguageSet.insert(nLANG); - InsertEntry( sTYP, sGID, sLID, sPFO, nLANG, sTEXT, sQHTEXT, sTITLE, filename, bCaseSensitive ); + aLanguageSet.insert("qtz"); + InsertEntry( + aActPo.getResourceType(), aActPo.getGroupId(), + aActPo.getLocalId(), sHack, "qtz", + sQTZText + "||" + sExText, sQTZQHText + "||" + sExQHText, + sQTZTitle + "||" + sExTitle, sFileName, bCaseSensitive ); } } + aPoInput.close(); + aInputStream >> sPoFileName; + bFirstLang = false; } aInputStream.close(); } diff --git a/l10ntools/source/po.cxx b/l10ntools/source/po.cxx new file mode 100644 index 000000000000..18c0ef1042d4 --- /dev/null +++ b/l10ntools/source/po.cxx @@ -0,0 +1,890 @@ +/* -*- 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 <com/sun/star/util/SearchOptions.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/i18n/XExtendedTransliteration.hpp> +#include <regexp/reclass.hxx> +#include <rtl/ustring.hxx> + +#include <cstring> +#include <ctime> +#include <cassert> + +#include <vector> +#include <string> + +#include <boost/crc.hpp> + +#include "po.hxx" + +#define POESCAPED OString("\\n\\t\\r\\\\\\\"") +#define POUNESCAPED OString("\n\t\r\\\"") + +//Class GenPoEntry + +class GenPoEntry +{ +private: + + OString m_sExtractCom; + OString m_sReference; + OString m_sMsgCtxt; + OString m_sMsgId; + OString m_sMsgStr; + bool m_bFuzzy; + bool m_bNull; + +public: + + GenPoEntry(); + virtual ~GenPoEntry(); + //Default copy constructor and copy operator work well + + virtual OString getExtractCom() const { return m_sExtractCom; } + virtual OString getReference() const { return m_sReference; } + virtual OString getMsgCtxt() const { return m_sMsgCtxt; } + virtual OString getMsgId() const { return m_sMsgId; } + virtual OString getMsgStr() const { return m_sMsgStr; } + virtual bool isFuzzy() const { return m_bFuzzy; } + virtual bool isNull() const { return m_bNull; } + + virtual void setExtractCom(const OString& rExtractCom); + virtual void setReference(const OString& rReference); + virtual void setMsgCtxt(const OString& rMsgCtxt); + virtual void setMsgId(const OString& rMsgId); + virtual void setMsgStr(const OString& rMsgStr); + virtual void setFuzzy(const bool bFuzzy); + + virtual void writeToFile(std::ofstream& rOFStream) const; + virtual void readFromFile(std::ifstream& rIFStream); +}; + +namespace +{ + //Escape text + static OString lcl_EscapeText(const OString& rText, + const OString& rUnEscaped= POUNESCAPED, + const OString& rEscaped = POESCAPED) + { + assert( rEscaped.getLength() == 2*rUnEscaped.getLength() ); + OString sResult = rText; + int nCount = 0; + for(sal_Int32 nIndex=0; nIndex<rText.getLength(); ++nIndex) + { + sal_Int32 nActChar = rUnEscaped.indexOf(rText[nIndex]); + if(nActChar!=-1) + sResult = sResult.replaceAt((nIndex)+(nCount++),1, + rEscaped.copy(2*nActChar,2)); + } + return sResult; + } + + //Unescape text + static OString lcl_UnEscapeText(const OString& rText, + const OString& rEscaped = POESCAPED, + const OString& rUnEscaped = POUNESCAPED) + { + assert( rEscaped.getLength() == 2*rUnEscaped.getLength() ); + OString sResult = rText; + int nCount = 0; + for(sal_Int32 nIndex=0; nIndex<rText.getLength()-1; ++nIndex) + { + sal_Int32 nActChar = rEscaped.indexOf(rText.copy(nIndex,2)); + if(nActChar % 2 == 0) + sResult = sResult.replaceAt((nIndex++)-(nCount++),2, + rUnEscaped.copy(nActChar/2,1)); + } + return sResult; + } + + //Convert a normal string to msg/po output string + static OString lcl_GenMsgString(const OString& rString) + { + if ( rString.isEmpty() ) + return "\"\""; + + OString sResult = "\"" + lcl_EscapeText(rString) + "\""; + sal_Int32 nIndex = 0; + while((nIndex=sResult.indexOf("\\n",nIndex))!=-1) + { + if( sResult.copy(nIndex-1,3)!="\\\\n" && + nIndex!=sResult.getLength()-3) + { + sResult = sResult.replaceAt(nIndex,2,"\\n\"\n\""); + } + ++nIndex; + } + + if ( sResult.indexOf('\n') != -1 ) + return "\"\"\n" + sResult; + + return sResult; + } + + //Convert msg string to normal form + static OString lcl_GenNormString(const OString& rString) + { + return lcl_UnEscapeText(rString.copy(1,rString.getLength()-2)); + } +} + +//Default constructor +GenPoEntry::GenPoEntry() + : m_sExtractCom( OString() ) + , m_sReference( OString() ) + , m_sMsgCtxt( OString() ) + , m_sMsgId( OString() ) + , m_sMsgStr( OString() ) + , m_bFuzzy( false ) + , m_bNull( false ) +{ +} + +//Destructor +GenPoEntry::~GenPoEntry() +{ +} + +//Set class members +void GenPoEntry::setExtractCom(const OString& rExtractCom) +{ + m_sExtractCom = rExtractCom; +} + +void GenPoEntry::setReference(const OString& rReference) +{ + m_sReference = rReference; +} + +void GenPoEntry::setMsgCtxt(const OString& rMsgCtxt) +{ + m_sMsgCtxt = rMsgCtxt; +} + +void GenPoEntry::setMsgId(const OString& rMsgId) +{ + m_sMsgId = rMsgId; +} + +void GenPoEntry::setMsgStr(const OString& rMsgStr) +{ + m_sMsgStr = rMsgStr; +} + +void GenPoEntry::setFuzzy(const bool bFuzzy) +{ + m_bFuzzy = bFuzzy; +} + +//Write to file +void GenPoEntry::writeToFile(std::ofstream& rOFStream) const +{ + if ( rOFStream.tellp() != 0 ) + rOFStream << std::endl; + if ( !m_sExtractCom.isEmpty() ) + rOFStream + << "#. " + << m_sExtractCom.replaceAll("\n","\n#. ").getStr() << std::endl; + if ( !m_sReference.isEmpty() ) + rOFStream << "#: " << m_sReference.getStr() << std::endl; + if ( m_bFuzzy ) + rOFStream << "#, fuzzy" << std::endl; + if ( !m_sMsgCtxt.isEmpty() ) + rOFStream << "msgctxt " + << lcl_GenMsgString(m_sMsgCtxt).getStr() << std::endl; + rOFStream << "msgid " + << lcl_GenMsgString(m_sMsgId).getStr() << std::endl; + rOFStream << "msgstr " + << lcl_GenMsgString(m_sMsgStr).getStr() << std::endl; +} + +//Read from file +void GenPoEntry::readFromFile(std::ifstream& rIFStream) +{ + *this = GenPoEntry(); + if( rIFStream.eof() ) + { + m_bNull = true; + return; + } + OString* pLastMsg = 0; + std::string sTemp; + getline(rIFStream,sTemp); + while(!rIFStream.eof()) + { + OString sLine = OString(sTemp.data(),sTemp.length()); + if (sLine.startsWith("#. ")) + { + if( !m_sExtractCom.isEmpty() ) + { + m_sExtractCom += "\n"; + } + m_sExtractCom += sLine.copy(3); + } + else if (sLine.startsWith("#: ")) + { + m_sReference = sLine.copy(3); + } + else if (sLine.startsWith("#, fuzzy")) + { + m_bFuzzy = true; + } + else if (sLine.startsWith("msgctxt ")) + { + m_sMsgCtxt = lcl_GenNormString(sLine.copy(8)); + pLastMsg = &m_sMsgCtxt; + } + else if (sLine.startsWith("msgid ")) + { + m_sMsgId = lcl_GenNormString(sLine.copy(6)); + pLastMsg = &m_sMsgId; + } + else if (sLine.startsWith("msgstr ")) + { + m_sMsgStr = lcl_GenNormString(sLine.copy(7)); + pLastMsg = &m_sMsgStr; + } + else if (sLine.startsWith("\"") && pLastMsg) + { + *pLastMsg += lcl_GenNormString(sLine); + } + else + break; + getline(rIFStream,sTemp); + } + } + +//Class PoEntry + +namespace +{ + //Generate KeyId + static OString lcl_GenKeyId(const OString& rGenerator) + { + boost::crc_32_type aCRC32; + aCRC32.process_bytes(rGenerator.getStr(), rGenerator.getLength()); + sal_uInt32 nCRC = aCRC32.checksum(); + //Use all readable ASCII charachter exclude xml special tags: ",',&,<,> + const OString sSymbols = "!#$%()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + char sKeyId[5]; + for( short nKeyInd = 0; nKeyInd < 4; ++nKeyInd ) + { + sKeyId[nKeyInd] = sSymbols[(nCRC & 255) % 89]; + nCRC >>= 8; + } + sKeyId[4] = '\0'; + return OString(sKeyId); + } + + //Split string at the delimiter char + static void lcl_SplitAt(const OString& rSource, const sal_Char nDelimiter, + std::vector<OString>& o_vParts) + { + o_vParts.resize( 0 ); + sal_Int32 nActIndex = 0; + sal_Int32 nLastSplit = 0; + while( nActIndex < rSource.getLength() ) + { + if ( rSource[nActIndex] == nDelimiter ) + { + o_vParts.push_back( + rSource.copy(nLastSplit,nActIndex-nLastSplit)); + nLastSplit = nActIndex+1; + } + ++nActIndex; + } + o_vParts.push_back(rSource.copy(nLastSplit)); + } + + //Unescape sdf string + static OString lcl_UnEscapeSDFText( + const OString& rText,const bool bHelpText = false ) + { + if ( bHelpText ) + return lcl_UnEscapeText(rText,"\\<\\>\\\"\\\\","<>\"\\"); + else + return lcl_UnEscapeText(rText,"\\n\\t\\r","\n\t\r"); + } + + //Miminize the length of the regular expression result + static void lcl_Minimize( + const OUString& rText, Regexpr& io_rRegExp, re_registers& io_rRegs ) + { + re_registers aPrevRegs; + const sal_Int32 nStart = io_rRegs.start[0]; + do + { + const OUString sTemp = rText.copy(0,io_rRegs.end[0]-1); + memcpy( + static_cast<void*>(&aPrevRegs), + static_cast<void*>(&io_rRegs), + sizeof(re_registers)); + memset(static_cast<void*>(&io_rRegs), 0, sizeof(re_registers)); + io_rRegExp.set_line(sTemp.getStr(),sTemp.getLength()); + io_rRegExp.re_search(&io_rRegs,nStart); + } while(io_rRegs.num_of_match); + + memcpy(static_cast<void*>(&io_rRegs),static_cast<void*>(&aPrevRegs), + sizeof(re_registers)); + io_rRegExp.set_line(rText.getStr(),rText.getLength()); + } + + //Find all special tag in a string using a regular expression + static void lcl_FindAllTag( + const OString& rText,std::vector<OString>& o_vFoundTags ) + { + ::com::sun::star::util::SearchOptions aOptions; + aOptions.algorithmType = + ::com::sun::star::util::SearchAlgorithms_REGEXP; + aOptions.searchFlag = + ::com::sun::star::util::SearchFlags::NORM_WORD_ONLY; + aOptions.searchString = "<[/]?[a-z_\\-]+(| +[a-z]+=\".*\") *[/]?>"; + ::com::sun::star::uno::Reference< + ::com::sun::star::i18n::XExtendedTransliteration > xTrans; + + Regexpr aRegExp(aOptions,xTrans); + const OUString sTemp(OStringToOUString(rText,RTL_TEXTENCODING_UTF8)); + aRegExp.set_line(sTemp.getStr(),sTemp.getLength()); + + re_registers aRegs; + memset(static_cast<void*>(&aRegs), 0, sizeof(re_registers)); + sal_Int32 nStart = 0; + o_vFoundTags.resize(0); + aRegExp.re_search(&aRegs,nStart); + while(aRegs.num_of_match) + { + lcl_Minimize(sTemp,aRegExp,aRegs); + o_vFoundTags.push_back( + OUStringToOString( + sTemp.copy(aRegs.start[0],aRegs.end[0]-aRegs.start[0]), + RTL_TEXTENCODING_UTF8)); + nStart = aRegs.end[0]; + memset(static_cast<void*>(&aRegs), 0, sizeof(re_registers)); + aRegExp.re_search(&aRegs,nStart); + } + } + + //Escape special tags + static OString lcl_EscapeTags( const OString& rText ) + { + typedef std::vector<OString> StrVec_t; + const OString vInitializer[] = { + "ahelp", "link", "item", "emph", "defaultinline", + "switchinline", "caseinline", "variable", + "bookmark_value", "image", "embedvar", "alt" }; + const StrVec_t vTagsForEscape( vInitializer, + vInitializer + sizeof(vInitializer) / sizeof(vInitializer[0]) ); + StrVec_t vFoundTags; + lcl_FindAllTag(rText,vFoundTags); + OString sResult = rText; + for(StrVec_t::const_iterator pFound = vFoundTags.begin(); + pFound != vFoundTags.end(); ++pFound) + { + bool bEscapeThis = false; + for(StrVec_t::const_iterator pEscape = vTagsForEscape.begin(); + pEscape != vTagsForEscape.end(); ++pEscape) + { + if (pFound->startsWith("<" + *pEscape) || + *pFound == "</" + *pEscape + ">") + { + bEscapeThis = true; + break; + } + } + if( bEscapeThis || *pFound=="<br/>" || + *pFound =="<help-id-missing/>") + { + OString sToReplace = "\\<" + + pFound->copy(1,pFound->getLength()-2). + replaceAll("\"","\\\"") + "\\>"; + sResult = sResult.replaceAll(*pFound, sToReplace); + } + } + return sResult; + } + + //Escape to get sdf/merge string + static OString lcl_EscapeSDFText( + const OString& rText,const bool bHelpText = false ) + { + if ( bHelpText ) + return lcl_EscapeTags(rText.replaceAll("\\","\\\\")); + else + return lcl_EscapeText(rText,"\n\t\r","\\n\\t\\r"); + } +} + +//Default constructor +PoEntry::PoEntry() + : m_pGenPo( 0 ) + , m_bIsInitialized( false ) +{ +} + +//Construct PoEntry from sdfline +PoEntry::PoEntry(const OString& rSDFLine, const TYPE eType) + : m_pGenPo( 0 ) + , m_bIsInitialized( false ) +{ + std::vector<OString> vParts; + lcl_SplitAt(rSDFLine,'\t',vParts); + if( vParts.size()!=15 || + vParts[SOURCEFILE].isEmpty() || + vParts[GROUPID].isEmpty() || + vParts[RESOURCETYPE].isEmpty() || + vParts[eType].isEmpty() || + vParts[HELPTEXT].getLength() == 4 ) + { + throw INVALIDSDFLINE; + } + + m_pGenPo = new GenPoEntry(); + m_pGenPo->setReference(vParts[SOURCEFILE]. + copy(vParts[SOURCEFILE].lastIndexOf("\\")+1)); + + OString sMsgCtxt = + vParts[GROUPID] + "\n" + + (vParts[LOCALID].isEmpty() ? "" : vParts[LOCALID] + "\n") + + vParts[RESOURCETYPE]; + switch(eType){ + case TTEXT: + sMsgCtxt += ".text"; break; + case TQUICKHELPTEXT: + sMsgCtxt += ".quickhelptext"; break; + case TTITLE: + sMsgCtxt += ".title"; break; + /*Default case is unneeded because the type of eType has + only three element*/ + } + m_pGenPo->setExtractCom( + ( !vParts[HELPTEXT].isEmpty() ? vParts[HELPTEXT] + "\n" : "" ) + + lcl_GenKeyId( + vParts[SOURCEFILE] + sMsgCtxt + vParts[eType] ) ); + m_pGenPo->setMsgCtxt(sMsgCtxt); + m_pGenPo->setMsgId( + lcl_UnEscapeSDFText( + vParts[eType],vParts[SOURCEFILE].endsWith(".xhp"))); + m_bIsInitialized = true; +} + +//Destructor +PoEntry::~PoEntry() +{ + delete m_pGenPo; +} + +//Copy constructor +PoEntry::PoEntry( const PoEntry& rPo ) + : m_pGenPo( rPo.m_pGenPo ? new GenPoEntry( *(rPo.m_pGenPo) ) : 0 ) + , m_bIsInitialized( rPo.m_bIsInitialized ) +{ +} + +//Copy operator +PoEntry& PoEntry::operator=(const PoEntry& rPo) +{ + if( this == &rPo ) + { + return *this; + } + if( rPo.m_pGenPo ) + { + if( m_pGenPo ) + { + *m_pGenPo = *(rPo.m_pGenPo); + } + else + { + m_pGenPo = new GenPoEntry( *(rPo.m_pGenPo) ); + } + } + else + { + delete m_pGenPo; + m_pGenPo = 0; + } + m_bIsInitialized = rPo.m_bIsInitialized; + return *this; +} + +//Get name of file from which entry is extracted +OString PoEntry::getSourceFile() const +{ + assert( m_bIsInitialized ); + return m_pGenPo->getReference(); +} + +//Get groupid +OString PoEntry::getGroupId() const +{ + assert( m_bIsInitialized ); + return m_pGenPo->getMsgCtxt().getToken(0,'\n'); +} + +//Get localid +OString PoEntry::getLocalId() const +{ + assert( m_bIsInitialized ); + const OString sMsgCtxt = m_pGenPo->getMsgCtxt(); + if (sMsgCtxt.indexOf('\n')==sMsgCtxt.lastIndexOf('\n')) + return OString(); + else + return sMsgCtxt.getToken(1,'\n'); +} + +//Get the type of component from which entry is extracted +OString PoEntry::getResourceType() const +{ + assert( m_bIsInitialized ); + const OString sMsgCtxt = m_pGenPo->getMsgCtxt(); + if (sMsgCtxt.indexOf('\n')==sMsgCtxt.lastIndexOf('\n')) + return sMsgCtxt.getToken(1,'\n').getToken(0,'.'); + else + return sMsgCtxt.getToken(2,'\n').getToken(0,'.'); +} + +//Get the type of entry +PoEntry::TYPE PoEntry::getType() const +{ + assert( m_bIsInitialized ); + const OString sMsgCtxt = m_pGenPo->getMsgCtxt(); + const OString sType = sMsgCtxt.copy( sMsgCtxt.lastIndexOf('.') + 1 ); + assert( + (sType == "text" || sType == "quickhelptext" || sType == "title") ); + if ( sType == "text" ) + return TTEXT; + else if ( sType == "quickhelptext" ) + return TQUICKHELPTEXT; + else + return TTITLE; +} + +//Check wheather entry is fuzzy +bool PoEntry::isFuzzy() const +{ + assert( m_bIsInitialized ); + return m_pGenPo->isFuzzy(); +} + +//Get keyid +OString PoEntry::getKeyId() const +{ + assert( m_bIsInitialized ); + const OString sExtractCom = m_pGenPo->getExtractCom(); + if( sExtractCom.indexOf("\n") == -1 ) + { + return sExtractCom; + } + else + { + return sExtractCom.getToken(1,'\n'); + } +} + + +//Get translation string in sdf/merge format +OString PoEntry::getMsgId() const +{ + assert( m_bIsInitialized ); + return + lcl_EscapeSDFText( + m_pGenPo->getMsgId(), getSourceFile().endsWith(".xhp") ); +} + +//Get translated string in sdf/merge format +OString PoEntry::getMsgStr() const +{ + assert( m_bIsInitialized ); + return + lcl_EscapeSDFText( + m_pGenPo->getMsgStr(), getSourceFile().endsWith(".xhp") ); + +} + +//Set translated string when input is in sdf format +void PoEntry::setMsgStr(const OString& rMsgStr) +{ + assert( m_bIsInitialized ); + m_pGenPo->setMsgStr( + lcl_UnEscapeSDFText( + rMsgStr,getSourceFile().endsWith(".xhp"))); +} + +//Set fuzzy flag +void PoEntry::setFuzzy(const bool bFuzzy) +{ + assert( m_bIsInitialized ); + m_pGenPo->setFuzzy(bFuzzy); +} + +//Check whether po-s belong to the same localization component +bool PoEntry::IsInSameComp(const PoEntry& rPo1,const PoEntry& rPo2) +{ + assert( rPo1.m_bIsInitialized && rPo2.m_bIsInitialized ); + return ( rPo1.getSourceFile() == rPo2.getSourceFile() && + rPo1.getGroupId() == rPo2.getGroupId() && + rPo1.getLocalId() == rPo2.getLocalId() && + rPo1.getResourceType() == rPo2.getResourceType() ); +} + +//Class PoHeader + +namespace +{ + //Get actual time in "YEAR-MO-DA HO:MI+ZONE" form + static OString lcl_GetTime() + { + time_t aNow = time(NULL); + struct tm* pNow = localtime(&aNow); + char pBuff[50]; + strftime( pBuff, sizeof pBuff, "%Y-%m-%d %H:%M%z", pNow ); + return pBuff; + } + + static OString lcl_ReplaceAttribute( + const OString& rSource, const OString& rOld, const OString& rNew ) + { + const sal_Int32 nFirstIndex = + rSource.indexOf( rOld ) + rOld.getLength()+2; + const sal_Int32 nCount = + rSource.indexOf( "\n", nFirstIndex ) - nFirstIndex; + return rSource.replaceFirst( rSource.copy(nFirstIndex, nCount), rNew ); + } +} + +//Default Constructor +PoHeader::PoHeader() + : m_pGenPo( 0 ) + , m_bIsInitialized( false ) +{ +} + +//Template Constructor +PoHeader::PoHeader( const OString& rExtSrc ) + : m_pGenPo( new GenPoEntry() ) + , m_bIsInitialized( false ) +{ + m_pGenPo->setExtractCom("extracted from " + rExtSrc); + m_pGenPo->setMsgStr( + OString("Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?" + "product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n" + "POT-Creation-Date: ") + lcl_GetTime() + + OString("\nPO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" + "Language-Team: LANGUAGE <LL@li.org>\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "X-Generator: LibreOffice\n" + "X-Accelerator-Marker: ~\n")); + m_bIsInitialized = true; +} + + +//Constructor for old headers to renew po files +PoHeader::PoHeader( std::ifstream& rOldPo ) + : m_pGenPo( new GenPoEntry() ) + , m_bIsInitialized( false ) +{ + assert( rOldPo.is_open() ); + m_pGenPo->readFromFile( rOldPo ); + + const OString sExtractCom = m_pGenPo->getExtractCom(); + m_pGenPo->setExtractCom( + sExtractCom.copy( 0, sExtractCom.getLength() - 3 ) ); + + OString sMsgStr = m_pGenPo->getMsgStr(); + sMsgStr = + lcl_ReplaceAttribute( sMsgStr, "Report-Msgid-Bugs-To", + "https://bugs.freedesktop.org/enter_bug.cgi?product=" + "LibreOffice&bug_status=UNCONFIRMED&component=UI" ); + sMsgStr = + lcl_ReplaceAttribute( sMsgStr, "X-Generator", "LibreOffice" ); + sMsgStr = + lcl_ReplaceAttribute( sMsgStr, "X-Accelerator-Marker", "~" ); + m_pGenPo->setMsgStr( sMsgStr ); + m_bIsInitialized = true; +} + +PoHeader::~PoHeader() +{ + delete m_pGenPo; +} + +//Get the language of header +OString PoHeader::getLanguage() const +{ + assert( m_bIsInitialized ); + const OString sLang = "Language: "; + const OString sMsgStr = m_pGenPo->getMsgStr(); + const sal_Int32 nFirstIndex = sMsgStr.indexOf(sLang)+sLang.getLength(); + const sal_Int32 nCount = sMsgStr.indexOf('\n',nFirstIndex)-nFirstIndex; + if( nFirstIndex == sLang.getLength()-1 || nCount == -nFirstIndex-1 ) + { + throw NOLANG; + } + return sMsgStr.copy( nFirstIndex, nCount ); +} + +//Class PoOfstream + +PoOfstream::PoOfstream() + : m_aOutPut() + , m_bIsAfterHeader( false ) +{ +} + +PoOfstream::~PoOfstream() +{ + if( isOpen() ) + { + close(); + } +} + +void PoOfstream::open(const OString& rFileName) +{ + assert( !isOpen() ); + m_aOutPut.open( rFileName.getStr(), + std::ios_base::out | std::ios_base::trunc ); + m_bIsAfterHeader = false; +} + +void PoOfstream::close() +{ + assert( isOpen() ); + m_aOutPut.close(); +} + +void PoOfstream::writeHeader(const PoHeader& rPoHeader) +{ + assert( isOpen() && !m_bIsAfterHeader && rPoHeader.m_bIsInitialized ); + rPoHeader.m_pGenPo->writeToFile( m_aOutPut ); + m_bIsAfterHeader = true; +} + +void PoOfstream::writeEntry( const PoEntry& rPoEntry ) +{ + assert( isOpen() && m_bIsAfterHeader && rPoEntry.m_bIsInitialized ); + rPoEntry.m_pGenPo->writeToFile( m_aOutPut ); +} + +//Class PoIfstream + +PoIfstream::PoIfstream() + : m_aInPut() + , m_bIsAfterHeader( false ) + , m_bEof( false ) +{ +} + +PoIfstream::~PoIfstream() +{ + if( isOpen() ) + { + close(); + } +} + +void PoIfstream::open( const OString& rFileName ) +{ + assert( !isOpen() ); + m_aInPut.open( rFileName.getStr(), std::ios_base::in ); + m_bIsAfterHeader = false; + m_bEof = false; +} + +void PoIfstream::close() +{ + assert( isOpen() ); + m_aInPut.close(); +} + +void PoIfstream::readHeader( PoHeader& rPoHeader ) +{ + assert( isOpen() && !eof() && !m_bIsAfterHeader ); + GenPoEntry aGenPo; + aGenPo.readFromFile( m_aInPut ); + if( !aGenPo.getExtractCom().isEmpty() && + aGenPo.getMsgId().isEmpty() && + !aGenPo.getMsgStr().isEmpty() ) + { + if( rPoHeader.m_pGenPo ) + { + *(rPoHeader.m_pGenPo) = aGenPo; + } + else + { + rPoHeader.m_pGenPo = new GenPoEntry( aGenPo ); + } + rPoHeader.m_bIsInitialized = true; + m_bIsAfterHeader = true; + } + else + { + throw INVALIDHEADER; + } +} + +void PoIfstream::readEntry( PoEntry& rPoEntry ) +{ + assert( isOpen() && !eof() && m_bIsAfterHeader ); + GenPoEntry aGenPo; + aGenPo.readFromFile( m_aInPut ); + if( aGenPo.isNull() ) + { + m_bEof = true; + rPoEntry = PoEntry(); + } + else + { + const OString sMsgCtxt = aGenPo.getMsgCtxt(); + const sal_Int32 nFirstEndLine = sMsgCtxt.indexOf('\n'); + const sal_Int32 nLastEndLine = sMsgCtxt.lastIndexOf('\n'); + const sal_Int32 nLastDot = sMsgCtxt.lastIndexOf('.'); + const OString sType = sMsgCtxt.copy( nLastDot + 1 ); + if( !aGenPo.getReference().isEmpty() && + nFirstEndLine > 0 && + (nLastEndLine == nFirstEndLine || + nLastEndLine == sMsgCtxt.indexOf('\n',nFirstEndLine+1)) && + nLastDot - nLastEndLine > 1 && + (sType == "text" || sType == "quickhelptext" || sType == "title")&& + !aGenPo.getMsgId().isEmpty() ) + { + if( rPoEntry.m_pGenPo ) + { + *(rPoEntry.m_pGenPo) = aGenPo; + } + else + { + rPoEntry.m_pGenPo = new GenPoEntry( aGenPo ); + } + const OString sExtractCom = aGenPo.getExtractCom(); + if( sExtractCom.isEmpty() || + ( sExtractCom.getLength() != 4 && + sExtractCom.indexOf("\n") == -1 ) ) + { + aGenPo.setExtractCom( + ( !sExtractCom.isEmpty() ? sExtractCom + "\n" : "" ) + + lcl_GenKeyId( + aGenPo.getReference() + sMsgCtxt + + aGenPo.getMsgId() ) ); + } + rPoEntry.m_bIsInitialized = true; + } + else + { + throw INVALIDENTRY; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/propex.cxx b/l10ntools/source/propex.cxx new file mode 100644 index 000000000000..2977cb158874 --- /dev/null +++ b/l10ntools/source/propex.cxx @@ -0,0 +1,45 @@ +/* -*- 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 "sal/main.h" + +#include "export.hxx" +#include "propmerge.hxx" + +SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) +{ + HandledArgs aArgs; + if( !Export::handleArguments(argc, argv, aArgs) ) + { + Export::writeUsage("propex","properties"); + return 1; + } + + if( aArgs.m_sInputFile.indexOf("en_US") != -1 ) + { + PropParser aParser( + aArgs.m_sInputFile, Export::sLanguages, aArgs.m_bMergeMode ); + if( !aParser.isInitialized() ) + { + return 1; + } + if( aArgs.m_bMergeMode ) + { + aParser.Merge(aArgs.m_sMergeSrc, aArgs.m_sOutputFile); + } + else + { + aParser.Extract( + aArgs.m_sOutputFile, aArgs.m_sPrj, aArgs.m_sPrjRoot ); + } + } + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/propmerge.cxx b/l10ntools/source/propmerge.cxx new file mode 100644 index 000000000000..a858f44d8210 --- /dev/null +++ b/l10ntools/source/propmerge.cxx @@ -0,0 +1,226 @@ +/* -*- 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 <cstdlib> +#include <cassert> +#include <iostream> +#include <fstream> +#include <iomanip> + +#include "export.hxx" +#include "common.hxx" +#include "propmerge.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 ) + { + OString sOutput( rPrj ); sOutput += "\t"; + sOutput += rActFileName; + sOutput += "\t0\tproperty\t"; + sOutput += rID; sOutput += "\t\t\t\t0\ten-US\t"; + sOutput += rText; sOutput += "\t\t\t\t"; + aSDFStream << sOutput.getStr() << std::endl; + } + + //Find ascii escaped unicode + static sal_Int32 lcl_IndexOfUnicode( + const OString& rSource, const sal_Int32 nFrom = 0 ) + { + const OString sHexDigits = "0123456789abcdefABCDEF"; + sal_Int32 nIndex = rSource.indexOf( "\\u", nFrom ); + if( nIndex == -1 ) + { + return -1; + } + bool bIsUnicode = true; + for( short nDist = 2; nDist <= 5; ++nDist ) + { + if( sHexDigits.indexOf( rSource[nIndex + nDist] ) == -1 ) + { + bIsUnicode = false; + } + } + return bIsUnicode ? nIndex : -1; + } + + //Convert ascii escaped unicode to utf-8 + static OString lcl_ConvertToUTF8( const OString& rText ) + { + OString sResult = rText; + sal_Int32 nIndex = lcl_IndexOfUnicode( sResult ); + while( nIndex != -1 && nIndex < rText.getLength() ) + { + const OString sHex = sResult.copy( nIndex + 2, 4 ); + const sal_Unicode cDec = + static_cast<sal_Unicode>( strtol( sHex.getStr(), NULL, 16 ) ); + const OString sNewChar = + OString( &cDec, 1, RTL_TEXTENCODING_UTF8 ); + sResult = sResult.replaceAll( "\\u" + sHex, sNewChar ); + nIndex = lcl_IndexOfUnicode( sResult, nIndex ); + } + return sResult; + } + + //Escape unicode characters + static void lcl_PrintJavaStyle( const OString& rText, std::ofstream &rOfstream ) + { + const OUString sTemp = + OStringToOUString( rText, RTL_TEXTENCODING_UTF8 ); + for ( sal_Int32 nIndex = 0; nIndex < sTemp.getLength(); ++nIndex ) + { + sal_Unicode cUniCode = sTemp[nIndex]; + if( cUniCode < 128 ) + { + rOfstream << static_cast<char>( cUniCode ); + } + else + { + rOfstream + << "\\u" + << std::setfill('0') << std::setw(2) << std::uppercase + << std::hex << (cUniCode >> 8) << (cUniCode & 0xFF); + } + } + } +} + +//Open source file and store its lines +PropParser::PropParser( + const OString& rInputFile, const OString& rLang, + const bool bMergeMode ) + : m_vLines( std::vector<OString>() ) + , m_sSource( rInputFile ) + , m_sLang( rLang ) + , m_bIsInitialized( false ) +{ + std::ifstream aIfstream( m_sSource.getStr() ); + if( aIfstream.is_open() ) + { + std::string s; + std::getline( aIfstream, s ); + while( !aIfstream.eof() ) + { + OString sLine( s.data(), s.length() ); + if( bMergeMode || + ( !sLine.startsWith(" *") && !sLine.startsWith("/*") ) ) + { + m_vLines.push_back( sLine ); + } + std::getline( aIfstream, s ); + } + } + else + { + std::cerr + << "Propex error: Cannot open source file: " + << m_sSource.getStr() << std::endl; + return; + } + m_bIsInitialized = true; +} + +PropParser::~PropParser() +{ +} + +//Extract strings form source file +void PropParser::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 + << "Propex error: Cannot open sdffile for extract: " + << rSDFFile.getStr() << std::endl; + return; + } + + for( unsigned nIndex = 0; nIndex < m_vLines.size(); ++nIndex ) + { + const OString sLine = m_vLines[nIndex]; + const sal_Int32 nEqualSign = sLine.indexOf('='); + if( nEqualSign != -1 ) + { + lcl_WriteSDF( + aSDFStream, + lcl_ConvertToUTF8( sLine.copy( nEqualSign + 1 ).trim() ),//Text + rPrj, + common::pathnameToken( + m_sSource.getStr(), rRoot.getStr()), //FileName + sLine.copy( 0, nEqualSign ).trim() ); //ID + } + } + + aSDFStream.close(); +} + +//Merge strings to source file +void PropParser::Merge( const OString &rMergeSrc, const OString &rDestinationFile ) +{ + assert( m_bIsInitialized ); + std::ofstream aDestination( + rDestinationFile.getStr(), std::ios_base::out | std::ios_base::trunc ); + if( !aDestination.is_open() ) { + std::cerr + << "Propex error: Cannot open source file for merge: " + << rDestinationFile.getStr() << std::endl; + return; + } + + MergeDataFile aMergeDataFile( rMergeSrc, m_sSource, false ); + + if( aMergeDataFile.GetLanguages()[0] != m_sLang ) + { + std::cerr + << "Propex error: given language conflicts with " + << "language of Mergedata file: " + << m_sLang.getStr() << " - " << rMergeSrc.getStr() << std::endl; + return; + } + + for( unsigned nIndex = 0; nIndex < m_vLines.size(); ++nIndex ) + { + const OString sLine = m_vLines[nIndex]; + const sal_Int32 nEqualSign = sLine.indexOf('='); + if( !sLine.startsWith(" *") && !sLine.startsWith("/*") && + nEqualSign != -1 ) + { + const OString sID( sLine.copy( 0, sLine.indexOf("=") ).trim() ); + ResData aResData( "", sID , m_sSource ); + aResData.sResTyp = "property"; + PFormEntrys* pEntrys = aMergeDataFile.GetPFormEntrys( &aResData ); + if( pEntrys ) + { + OString sNewText; + pEntrys->GetText( sNewText, STRING_TYP_TEXT, m_sLang ); + aDestination << (sID + OString("=")).getStr(); + lcl_PrintJavaStyle( sNewText, aDestination ); + aDestination << std::endl; + } + else + { + aDestination << sLine.getStr() << std::endl; + } + } + else + { + aDestination << sLine.getStr() << std::endl; + } + } + aDestination.close(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/l10ntools/source/renewpo.cxx b/l10ntools/source/renewpo.cxx new file mode 100644 index 000000000000..32d19d594c09 --- /dev/null +++ b/l10ntools/source/renewpo.cxx @@ -0,0 +1,224 @@ +/* -*- 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 <iostream> +#include <fstream> +#include <dirent.h> +#include <string> +#include <vector> + +#include <osl/file.hxx> +#include <rtl/string.hxx> + +#include "po.hxx" + +using namespace std; + +//Check wheather the two entry are the same but in different languages +bool IsSameEntry(const OString& rFirstEntry,const OString& rSecEntry) +{ + for(int i = PoEntry::PROJECT; i<=PoEntry::LOCALID;++i) + { + if ( rFirstEntry.getToken(i,'\t') != rSecEntry.getToken(i,'\t') && + i != PoEntry::DUMMY) + return false; + } + return true; +} + +//Get path of po file +OString GetPath(const OString& rPath, const OString& rLine) +{ + OString sSourceFile = rLine.getToken(PoEntry::SOURCEFILE,'\t'); + OString sSourcePath = rPath + "/" + + rLine.getToken(PoEntry::PROJECT,'\t') + "/" + + sSourceFile.copy(0,sSourceFile.lastIndexOf("\\")). + replaceAll("\\","/"); + return sSourcePath; +} + +OString DelLocalId(const OString& rLine) +{ + unsigned nTabIndex = 0; + for(unsigned nComponent=0; nComponent<PoEntry::LOCALID; ++nComponent) + { + nTabIndex = rLine.indexOf('\t',nTabIndex); + ++nTabIndex; + } + return rLine.replaceAt(nTabIndex, + rLine.indexOf('\t',nTabIndex)-nTabIndex, + ""); +} + +//Renew po files of the actual language +void HandleLanguage(struct dirent* pLangEntry, const OString& rPath, + const OString& rpo2loPath, const OString& rSDFPath) +{ + const OString LangEntryName = pLangEntry->d_name; + + //Generate and open sdf + cout << "Process start with language: " << LangEntryName.getStr() << endl; + OUString aTempUrl; + if (osl::FileBase::createTempFile(0, 0, &aTempUrl) + != osl::FileBase::E_None) + { + cerr << "osl::FileBase::createTempFile() failed\n"; + return; + } + OUString aTempPath; + if (osl::FileBase::getSystemPathFromFileURL(aTempUrl, aTempPath) + != osl::FileBase::E_None) + { + cerr + << "osl::FileBase::getSystemPathFromFileURL(" << aTempUrl + << ") failed\n"; + return; + } + const OString SDFFileName = + OUStringToOString(aTempPath, RTL_TEXTENCODING_UTF8); + system( (rpo2loPath + + " -i " + rPath + "/" + LangEntryName + + " -o " + SDFFileName + + " -l " + LangEntryName + + " -t " + rSDFPath).getStr()); + cout << "Language sdf is ready!" << endl; + + PoOfstream aNewPo; + ifstream aSDFInput(SDFFileName.getStr()); + string s; + getline(aSDFInput,s); + OString sLine = OString(s.data(),s.length()); + while(!aSDFInput.eof()) + { + OString sActUnTrans = sLine; + const OString sPath = rPath + "/"+ LangEntryName; + const OString sActSourcePath = GetPath(sPath,sActUnTrans); + //Make new po file and add header + if (!aNewPo.isOpen()) + { + const OString sNewPoFileName = sActSourcePath + ".po_tmp"; + aNewPo.open(sNewPoFileName); + if (!aNewPo.isOpen()) + { + cerr + << "Cannot open temp file for new po: " + << sNewPoFileName.getStr() << endl; + return; + } + const OString sOldPoFileName = sActSourcePath + ".po"; + ifstream aOldPo(sOldPoFileName.getStr()); + if (!aOldPo.is_open()) + { + cerr + << "Cannot open old po file: " + << sOldPoFileName.getStr() << endl; + return; + } + aNewPo.writeHeader(PoHeader(aOldPo)); + aOldPo.close(); + } + + //Set PoEntry and write out + getline(aSDFInput,s); + OString sActTrans; + if (!aSDFInput.eof() && + IsSameEntry(sActUnTrans,sLine = OString(s.data(),s.length()))) + { + sActTrans = sLine; + getline(aSDFInput,s); + } + else + { + sActTrans =""; + } + const PoEntry::TYPE vInitializer[] = + { PoEntry::TTEXT, PoEntry::TQUICKHELPTEXT, PoEntry::TTITLE }; + const vector<PoEntry::TYPE> vTypes( vInitializer, + vInitializer + sizeof(vInitializer) / sizeof(vInitializer[0]) ); + unsigned short nDummyBit = 0; + for( unsigned short nIndex=0; nIndex<vTypes.size(); ++nIndex ) + { + if (!sActUnTrans.getToken(vTypes[nIndex],'\t').isEmpty()) + { + /**Because of xrmex there are duplicated id's, + only use this if xrmex have already fixed*/ + const OString sSource = + sActUnTrans.getToken(PoEntry::SOURCEFILE,'\t'); + const OString sEnding = + sSource.copy(sSource.getLength()-4, 4); + if (sActUnTrans.getToken(PoEntry::GROUPID,'\t')== + sActUnTrans.getToken(PoEntry::LOCALID,'\t') && + ( sEnding == ".xrm" || sEnding == ".xml" )) + { + sActUnTrans = DelLocalId(sActUnTrans); + } + try + { + PoEntry aPE(sActUnTrans, vTypes[nIndex]); + const OString sActStr = + sActTrans.getToken(vTypes[nIndex],'\t'); + aPE.setMsgStr(sActStr); + aPE.setFuzzy( sActStr.isEmpty() ? false : + static_cast<bool>(sActTrans.getToken(PoEntry::DUMMY,'\t'). + copy(nDummyBit++,1).toBoolean())); + aNewPo.writeEntry(aPE); + } + catch( PoEntry::Exception& ) + { + cerr + << "Invalid sdf line " + << sActUnTrans.replaceAll("\t","\\t").getStr() << '\n'; + } + } + } + //Check wheather next entry is in the same po file + OString sNextSourcePath = aSDFInput.eof() ? "" : + GetPath(sPath,sLine = OString(s.data(),s.length())); + if (sNextSourcePath!=sActSourcePath) + { + aNewPo.close(); + system(("rm " + sActSourcePath +".po").getStr()); + system(("mv "+ sActSourcePath +".po_tmp " + + sActSourcePath +".po").getStr()); + } + } + + //Close and remove sdf file + aSDFInput.close(); + if (osl::File::remove(aTempUrl) != osl::FileBase::E_None) + { + cerr << "Warning: failure removing temporary " << aTempUrl << '\n'; + } +} + + +int main(int argc, char* argv[]) +{ + //Usage + if (argc < 4) + { + cout << "Use: renewpot translationsdir po2lo en-US.sdf" << endl; + cout << "translationsdir: this directory contains the po" << endl; + cout << "files of all languages. Every language has a" << endl; + cout << "directory named with language id." << endl; + return 1; + } + + //Call processing function with all language directories + DIR* pTranslations = opendir(argv[1]); + while ( struct dirent* pActEntry = readdir(pTranslations) ) + { + if ( OString(pActEntry->d_name).indexOf('.')==-1 ) + HandleLanguage(pActEntry,OString(argv[1]), + OString(argv[2]),OString(argv[3])); + } + closedir(pTranslations); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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 <iostream> +#include <fstream> +#include <cassert> +#include <cstring> + +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xmlmemory.h> +#include <libxml/xmlstring.h> + +#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<OString>(reinterpret_cast<sal_Char*>( 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<const xmlChar*>(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<const xmlChar*>( 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<OString>(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<OString>( 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 <iostream> +#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: */ diff --git a/l10ntools/source/uimerge.cxx b/l10ntools/source/uimerge.cxx index bdf536a238dc..4192ed73d6be 100644 --- a/l10ntools/source/uimerge.cxx +++ b/l10ntools/source/uimerge.cxx @@ -26,100 +26,10 @@ #include <fstream> #include <vector> -#define STATE_NON 0x0001 -#define STATE_INPUT 0x0002 -#define STATE_OUTPUT 0x0003 -#define STATE_PRJ 0x0004 -#define STATE_ROOT 0x0005 -#define STATE_MERGESRC 0x0006 -#define STATE_ERRORLOG 0x0007 -#define STATE_LANGUAGES 0x000C - -sal_Bool bMergeMode; -sal_Bool bErrorLog; -sal_Bool bUTF8; -sal_Bool bDisplayName; -sal_Bool bExtensionDescription; rtl::OString sPrj; rtl::OString sPrjRoot; rtl::OString sInputFileName; rtl::OString sOutputFile; -rtl::OString sMergeSrc; -rtl::OString sLangAttribute; -rtl::OString sResourceType; -XRMResParser *pParser = NULL; - -void GetOutputFile( int argc, char* argv[]) -{ - bMergeMode = sal_False; - bErrorLog = sal_True; - bUTF8 = sal_True; - bDisplayName = sal_False; - bExtensionDescription = sal_False; - sPrj = ""; - sPrjRoot = ""; - sInputFileName = ""; - Export::sLanguages = ""; - sal_uInt16 nState = STATE_NON; - - // parse command line - for( int i = 1; i < argc; i++ ) { - if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-I" ) { - nState = STATE_INPUT; // next token specifies source file - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-O" ) { - nState = STATE_OUTPUT; // next token specifies the dest file - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-P" ) { - nState = STATE_PRJ; // next token specifies the cur. project - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-R" ) { - nState = STATE_ROOT; // next token specifies path to project root - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-M" ) { - nState = STATE_MERGESRC; // next token specifies the merge database - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-E" ) { - nState = STATE_ERRORLOG; - bErrorLog = sal_False; - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-L" ) { - nState = STATE_LANGUAGES; - } - else { - switch ( nState ) { - case STATE_NON: { - return; // no valid command line - } - case STATE_INPUT: { - sInputFileName = argv[ i ]; - } - break; - case STATE_OUTPUT: { - sOutputFile = argv[ i ]; // the dest. file - } - break; - case STATE_PRJ: { - sPrj = rtl::OString( argv[ i ]); - } - break; - case STATE_ROOT: { - sPrjRoot = rtl::OString( argv[ i ]); // path to project root - } - break; - case STATE_MERGESRC: { - sMergeSrc = rtl::OString( argv[ i ]); - bMergeMode = sal_True; // activate merge mode, cause merge database found - } - break; - case STATE_LANGUAGES: { - Export::sLanguages = rtl::OString( argv[ i ]); - } - break; - } - } - } -} int extractTranslations() { @@ -275,22 +185,19 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { int nRetValue = 0; - GetOutputFile( argc, argv ); - - if (sOutputFile.isEmpty()) + HandledArgs aArgs; + if ( !Export::handleArguments(argc, argv, aArgs) ) { - fprintf( stdout, "Syntax: UIEX[-p Prj][-r PrjRoot]-i FileIn [-o FileOut][-m DataBase][-e][-L l1,l2,...]\n" ); - fprintf( stdout, " Prj: Project\n" ); - fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); - fprintf( stdout, " FileIn: Source files (*.src)\n" ); - fprintf( stdout, " FileOut: Destination file (*.*)\n" ); - fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); - fprintf( stdout, " -e: Disable writing errorlog\n" ); - fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US,es...)\n" ); + Export::writeUsage("uiex","ui"); return 1; } - if (!bMergeMode) + sPrj = aArgs.m_sPrj; + sPrjRoot = aArgs.m_sPrjRoot; + sInputFileName = aArgs.m_sInputFile; + sOutputFile = aArgs.m_sOutputFile; + + if (!aArgs.m_bMergeMode) { if (Export::sLanguages != "en-US") { @@ -302,7 +209,7 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) } else { - Merge(sMergeSrc, sInputFileName, sOutputFile); + Merge(aArgs.m_sMergeSrc, sInputFileName, sOutputFile); } return nRetValue; diff --git a/l10ntools/source/xrmlex.l b/l10ntools/source/xrmlex.l index dfe74d7c1a56..8d6094c18d06 100644 --- a/l10ntools/source/xrmlex.l +++ b/l10ntools/source/xrmlex.l @@ -221,18 +221,8 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { pOutput = GetOutputFile( argc, argv ); - if ( !pOutput ) { - fprintf( stdout, "Syntax: XRMEX[-p Prj][-r PrjRoot]-i FileIn [-o FileOut][-m DataBase][-e][-b][-u][-NOUTF8][-L l1,l2,...]\n" ); - fprintf( stdout, " Prj: Project\n" ); - fprintf( stdout, " PrjRoot: Path to project root (..\\.. etc.)\n" ); - fprintf( stdout, " FileIn: Source files (*.src)\n" ); - fprintf( stdout, " FileOut: Destination file (*.*)\n" ); - fprintf( stdout, " DataBase: Mergedata (*.sdf)\n" ); - fprintf( stdout, " -e: Disable writing errorlog\n" ); - fprintf( stdout, " -b: Break when Token \"HelpText\" found in source\n" ); - fprintf( stdout, " -u: [english] and [german] are allowed, Id is Taken from DataBase \n" ); - fprintf( stdout, " -NOUTF8: disable UTF8 as language independent encoding\n" ); - fprintf( stdout, " -L: Restrict the handled languages. l1,l2,... are elements of (de,en-US,es...)\n" ); + if ( !pOutput ) + { return 1; } pFile = GetXrmFile(); diff --git a/l10ntools/source/xrmmerge.cxx b/l10ntools/source/xrmmerge.cxx index a22996d8db43..a3eb0e5418ee 100644 --- a/l10ntools/source/xrmmerge.cxx +++ b/l10ntools/source/xrmmerge.cxx @@ -36,20 +36,8 @@ using namespace std; void yyerror( const char * ); void YYWarning( const char * ); -// defines to parse command line -#define STATE_NON 0x0001 -#define STATE_INPUT 0x0002 -#define STATE_OUTPUT 0x0003 -#define STATE_PRJ 0x0004 -#define STATE_ROOT 0x0005 -#define STATE_MERGESRC 0x0006 -#define STATE_ERRORLOG 0x0007 -#define STATE_LANGUAGES 0x000C - // set of global variables -sal_Bool bEnableExport; -sal_Bool bMergeMode; -sal_Bool bUTF8; +bool bMergeMode; sal_Bool bDisplayName; sal_Bool bExtensionDescription; rtl::OString sPrj; @@ -69,87 +57,30 @@ extern "C" { extern char *GetOutputFile( int argc, char* argv[]) /*****************************************************************************/ { - bEnableExport = sal_False; - bMergeMode = sal_False; - bUTF8 = sal_True; bDisplayName = sal_False; bExtensionDescription = sal_False; - sPrj = ""; - sPrjRoot = ""; - sInputFileName = ""; sActFileName = ""; - Export::sLanguages = ""; - sal_uInt16 nState = STATE_NON; - sal_Bool bInput = sal_False; - - // parse command line - for( int i = 1; i < argc; i++ ) { - if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-I" ) { - nState = STATE_INPUT; // next token specifies source file - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-O" ) { - nState = STATE_OUTPUT; // next token specifies the dest file - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-P" ) { - nState = STATE_PRJ; // next token specifies the cur. project - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-R" ) { - nState = STATE_ROOT; // next token specifies path to project root - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-M" ) { - nState = STATE_MERGESRC; // next token specifies the merge database - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-E" ) { - nState = STATE_ERRORLOG; - } - else if ( rtl::OString( argv[ i ] ).toAsciiUpperCase() == "-L" ) { - nState = STATE_LANGUAGES; - } - else { - switch ( nState ) { - case STATE_NON: { - return NULL; // no valid command line - } - case STATE_INPUT: { - sInputFileName = argv[ i ]; - bInput = sal_True; // source file found - } - break; - case STATE_OUTPUT: { - sOutputFile = argv[ i ]; // the dest. file - } - break; - case STATE_PRJ: { - sPrj = rtl::OString( argv[ i ]); - } - break; - case STATE_ROOT: { - sPrjRoot = rtl::OString( argv[ i ]); // path to project root - } - break; - case STATE_MERGESRC: { - sMergeSrc = rtl::OString( argv[ i ]); - bMergeMode = sal_True; // activate merge mode, cause merge database found - } - break; - case STATE_LANGUAGES: { - Export::sLanguages = rtl::OString( argv[ i ]); - } - break; - } - } - } - if ( bInput ) { + HandledArgs aArgs; + if ( Export::handleArguments(argc, argv, aArgs) ) + { // command line is valid - bEnableExport = sal_True; + bMergeMode = aArgs.m_bMergeMode; + sPrj = aArgs.m_sPrj; + sPrjRoot = aArgs.m_sPrjRoot; + sInputFileName = aArgs.m_sInputFile; + sOutputFile = aArgs.m_sOutputFile; + sMergeSrc = aArgs.m_sMergeSrc; char *pReturn = new char[ sOutputFile.getLength() + 1 ]; std::strcpy( pReturn, sOutputFile.getStr()); // #100211# - checked return pReturn; } - - // command line is not valid - return NULL; + else + { + // command line is not valid + Export::writeUsage("xrmex","xrm/xml"); + return NULL; + } } /*****************************************************************************/ @@ -261,9 +192,9 @@ int XRMResParser::Execute( int nToken, char * pToken ) switch ( nToken ) { case XRM_TEXT_START:{ - rtl::OString sNewLID = GetAttribute( rToken, "id" ); - if ( sNewLID != sLID ) { - sLID = sNewLID; + rtl::OString sNewGID = GetAttribute( rToken, "id" ); + if ( sNewGID != sGID ) { + sGID = sNewGID; } bText = sal_True; sCurrentText = ""; @@ -297,7 +228,7 @@ int XRMResParser::Execute( int nToken, char * pToken ) case DESC_TEXT_START:{ if (bDisplayName) { - sLID = rtl::OString("dispname"); + sGID = rtl::OString("dispname"); bText = sal_True; sCurrentText = ""; sCurrentOpenTag = rToken; @@ -333,7 +264,7 @@ int XRMResParser::Execute( int nToken, char * pToken ) case DESC_EXTENSION_DESCRIPTION_SRC: { if (bExtensionDescription) { - sLID = rtl::OString("extdesc"); + sGID = rtl::OString("extdesc"); sResourceType = rtl::OString ( "description" ); sLangAttribute = rtl::OString ( "lang" ); sCurrentOpenTag = rToken; @@ -498,7 +429,6 @@ void XRMResExport::WorkOnText( { rtl::OString sPlatform( "" ); pResData = new ResData( sPlatform, GetGID() ); - pResData->sId = GetLID(); } rtl::OString sText(rText); @@ -528,12 +458,8 @@ void XRMResExport::EndOfText( sOutput += "\t0\t"; sOutput += sResourceType; sOutput += "\t"; - sOutput += pResData->sId; - // USE LID AS GID OR MERGE DON'T WORK - //sOutput += pResData->sGId; - sOutput += "\t"; - sOutput += pResData->sId; - sOutput += "\t\t\t0\t"; + sOutput += pResData->sGId; + sOutput += "\t\t\t\t0\t"; sOutput += sCur; sOutput += "\t"; @@ -670,8 +596,7 @@ void XRMResMerge::WorkOnText( if ( pMergeDataFile ) { if ( !pResData ) { rtl::OString sPlatform( "" ); - pResData = new ResData( sPlatform, GetLID() , sFilename ); - pResData->sId = GetLID(); + pResData = new ResData( sPlatform, GetGID() , sFilename ); pResData->sResTyp = sResourceType; } |