xref: /aoo41x/main/l10ntools/layout/tralay.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <com/sun/star/xml/sax/SAXException.hpp>
29 #include <l10ntools/vosapp.hxx>
30 
31 #include <osl/file.hxx>
32 
33 #include "export.hxx"
34 #include "layoutparse.hxx"
35 #include "helpmerge.hxx"
36 #include "xmlparse.hxx"
37 
38 // Convert a rtl::OUString to a byte string.
39 #define OUSTRING_CSTR( str ) \
40     rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr()
41 
42 #define STRING( str ) String( str, RTL_TEXTENCODING_UTF8 )
43 #define BSTRING( str ) ByteString( str, RTL_TEXTENCODING_UTF8 )
44 
45 using ::rtl::OUString;
46 
47 using namespace ::osl;
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::uno;
50 
51 
52 class TranslateLayout : public Application
53 {
54     ByteString mGid1;
55     ByteString mLanguage;
56     ByteString mLocalize;
57     ByteString mOutput;
58     ByteString mProject;
59     ByteString mRoot;
60     bool mMergeMode;
61     std::vector< ByteString > mLanguages;
62     std::list< ByteString > mFiles;
63 
64 public:
65     TranslateLayout();
66     virtual ~TranslateLayout();
67     ByteString GetCommandLineParam( int i );
68     ByteString GetOptionArgument( int const i );
69     void ExceptionalMain();
70     void Main();
71     void Merge();
72     void MergeLanguage( ByteString const& language );
73     void ParseCommandLine();
74     void CreateSDF();
75 
76     using Application::GetCommandLineParam;
77 };
78 
79 static void usage()
80 {
81     fprintf( stderr, "Usage: tralay [OPTION]... XML-FILE\n" );
82     fprintf( stderr, "\nOptions:\n" );
83     fprintf( stderr, "  -h,--help                  show this help\n" );
84     fprintf( stderr, "  -l,--language=LANG         process this language\n" );
85     fprintf( stderr, "  -m,--merge=DATABASE.SDF    translation database\n" );
86     fprintf( stderr, "\nExamples:\n" );
87     fprintf( stderr, "  tralay -l en-US -o localize.sdf zoom.xml   # Extract\n" );
88     fprintf( stderr, "  tralay -m localize.sdf -l de -l nl -o out zoom.xml  # Merge/translate\n" );
89     exit( 2 );
90 }
91 
92 static ByteString ConvertSystemPath( const ByteString& rPath )
93 {
94     if( rPath.CompareTo( ".", 1 ) == 0 )
95     {
96         OUString sPath( rPath.GetBuffer(), rPath.Len(), RTL_TEXTENCODING_UTF8 );
97 
98         ::rtl::OUString curDirPth, sURL;
99         osl_getProcessWorkingDir( &curDirPth.pData );
100 
101         ::osl::FileBase::getAbsoluteFileURL( curDirPth, sPath, sURL );
102         ::osl::FileBase::getSystemPathFromFileURL( sURL, sPath );
103 
104         return ByteString( rtl::OUStringToOString( sPath, RTL_TEXTENCODING_UTF8 ) );
105     }
106     else
107     {
108         return rPath;
109     }
110 }
111 
112 ByteString TranslateLayout::GetCommandLineParam( int i )
113 {
114     return ByteString( OUSTRING_CSTR( Application::GetCommandLineParam( sal::static_int_cast< sal_uInt16 >( i ) ) ) );
115 }
116 
117 ByteString TranslateLayout::GetOptionArgument( int const i )
118 {
119     if ( i >= GetCommandLineParamCount() )
120         usage();
121     ByteString arg = GetCommandLineParam( i );
122     if ( !arg.CompareTo( "-", 1 ) )
123     {
124         fprintf( stderr, "Option needs an argument: %s, found: %s\n",
125                  GetCommandLineParam( i - 1 ).GetBuffer(),
126                  arg.GetBuffer() );
127         usage();
128     }
129     return arg;
130  }
131 
132 void TranslateLayout::ParseCommandLine()
133 {
134     for ( int i = 0; i < GetCommandLineParamCount(); i++ )
135     {
136         ByteString aParam = GetCommandLineParam( i );
137         if ( aParam.Equals( "-h" ) || aParam.Equals( "--help" ) )
138             usage();
139         else if ( aParam.Equals( "-l" ) || aParam.Equals( "--language" ) )
140             mLanguages.push_back ( GetOptionArgument( ++i ) );
141         else if ( aParam.Equals( "-m" ) || aParam.Equals( "--merge" ) )
142         {
143             mMergeMode = true;
144             mLocalize = GetOptionArgument( ++i );
145         }
146         else if ( aParam.Equals( "-o" ) || aParam.Equals( "--output" ) )
147             mOutput = ConvertSystemPath( GetOptionArgument( ++i ) );
148         else if ( !aParam.CompareTo( "-", 1 ) )
149         {
150             fprintf( stderr, "error: No such option: %s\n", aParam.GetBuffer() );
151             usage();
152         }
153         else
154             mFiles.push_back( ConvertSystemPath( aParam ) );
155     }
156     if ( !mFiles.size() )
157     {
158         fprintf( stderr, "error: No XML-FILE found\n" );
159         usage();
160     }
161 }
162 
163 static XMLAttribute*
164 findAttribute( XMLAttributeList* lst, String const& name )
165 {
166     for ( sal_uLong i = 0; i < lst->Count(); i++ )
167         if ( lst->GetObject( i )->Equals( name ) )
168             return lst->GetObject( i );
169     return 0;
170 }
171 
172 static XMLAttribute*
173 translateAttribute( XMLAttributeList* lst,
174                     String const& name, String const& translation )
175 {
176     if ( XMLAttribute* a = findAttribute( lst, name ) )
177         return lst->Replace ( new XMLAttribute( name.Copy( 1 ), translation ), a );
178     return 0;
179 }
180 
181 static void
182 translateElement( XMLElement* element, ByteString const& lang,
183                   ResData* resData, MergeDataFile& mergeData )
184 {
185     XMLAttributeList* attributes = element->GetAttributeList();
186     std::vector<XMLAttribute*> interesting( interestingAttributes( attributes ) );
187 
188 
189     if( !interesting.empty() )
190     {
191         std::vector<XMLAttribute*>::iterator i( interesting.begin() );
192         ByteString id = BSTRING( (*i++)->GetValue() );
193         for ( ; i != interesting.end(); ++i )
194         {
195             ByteString attributeId = id;
196             attributeId += BSTRING ( **i );
197             resData->sGId = attributeId;
198             resData->sId = element->GetOldref();
199 
200             if ( PFormEntrys* entry = mergeData.GetPFormEntrys( resData ) )
201             {
202                 ByteString translation;
203                 entry->GetText( translation, STRING_TYP_TEXT, lang, true );
204     //            ByteString original = removeContent( element );
205                 if ( !translation.Len() )
206 #if 0
207                     translation = original;
208 #else
209                     translation = BSTRING( ( *i )->GetValue() );
210 #endif
211                 delete translateAttribute( attributes, **i , STRING( translation ) );
212             }
213         }
214     }
215 }
216 
217 static bool is_dir( ByteString const& name )
218 {
219     DirectoryItem aItem;
220     OUString sFileURL( name.GetBuffer(), name.Len(), RTL_TEXTENCODING_UTF8 );
221     FileBase::getFileURLFromSystemPath( sFileURL, sFileURL );
222     if( DirectoryItem::get( sFileURL, aItem ) == FileBase::E_None )
223     {
224         FileStatus aStatus(FileStatusMask_Type);
225         if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
226         {
227             if( aStatus.getFileType() == FileStatus::Directory )
228                 return true;
229         }
230     }
231     return false;
232 }
233 
234 static void make_directory( ByteString const& name )
235 {
236     OUString sFileURL( name.GetBuffer(), name.Len(), RTL_TEXTENCODING_UTF8 );
237     FileBase::getFileURLFromSystemPath( sFileURL, sFileURL );
238     Directory::create( sFileURL );
239 }
240 
241 static void insertMarker( XMLParentNode *p, ByteString const& file )
242 {
243     if ( XMLChildNodeList* lst = p->GetChildList() )
244         if ( lst->Count() )
245         {
246             sal_uLong i = 1;
247             // Skip newline, if possible.
248             if ( lst->Count() > 1
249                  && lst->GetObject( 2 )->GetNodeType() == XML_NODE_TYPE_DEFAULT )
250                 i++;
251             OUString marker = OUString::createFromAscii( "\n    NOTE: This file has been generated automagically by transex3/layout/tralay,\n          from source template: " )
252                 + STRING( file )
253                 + OUString::createFromAscii( ".\n          Do not edit, changes will be lost.\n" );
254             lst->Insert( new XMLComment( marker, 0 ), i );
255         }
256 }
257 
258 void TranslateLayout::MergeLanguage( ByteString const& language )
259 {
260     ByteString xmlFile = mFiles.front();
261 
262     MergeDataFile mergeData( mLocalize, xmlFile,
263                              sal_False, RTL_TEXTENCODING_MS_1252 );
264 
265     DirEntry aFile( xmlFile );
266     SimpleXMLParser aParser;
267     LayoutXMLFile* layoutXml = new LayoutXMLFile( mMergeMode );
268     if ( !aParser.Execute( aFile.GetFull() , STRING( xmlFile ), layoutXml ) )
269     {
270         fprintf(stderr, "error: parsing: %s\n", xmlFile.GetBuffer() );
271         return;
272     }
273 
274     layoutXml->Extract();
275     insertMarker( layoutXml, xmlFile );
276 
277     ResData resData( "", "", "" );
278     resData.sResTyp = mProject; /* mGid1 ?? */
279     resData.sFilename = xmlFile;
280 
281     XMLHashMap* xmlStrings = layoutXml->GetStrings();
282     for ( XMLHashMap::iterator i = xmlStrings->begin(); i != xmlStrings->end();
283           ++i )
284     {
285         if ( LangHashMap* languageMap = i->second )
286             if ( XMLElement* element = ( *languageMap )[ "en-US" ] )
287                 translateElement( element, language, &resData, mergeData );
288     }
289 
290 #ifndef WNT
291     ByteString outFile = "/dev/stdout";
292 #else
293     ByteString outFile = "\\\\.\\CON";
294 #endif
295     if ( mOutput.Len() )
296     {
297         outFile = mOutput;
298         if ( is_dir( outFile ) )
299         {
300             ByteString outDir = mOutput;
301             outDir.Append( "/" ).Append( language );
302             if ( !is_dir( outDir ) )
303                 make_directory( outDir );
304             outFile = outDir;
305             outFile.Append( "/" ).Append( xmlFile );
306         }
307     }
308     layoutXml->Write( outFile );
309     delete layoutXml;
310 }
311 
312 void TranslateLayout::Merge()
313 {
314     if ( mLanguages.size() )
315         for ( std::vector<ByteString>::iterator i = mLanguages.begin();
316               i != mLanguages.end(); ++i)
317             MergeLanguage( *i );
318     else
319         MergeLanguage( mLanguage );
320 }
321 
322 void TranslateLayout::CreateSDF()
323 {
324     ByteString xmlFile = mFiles.front();
325 #ifndef WNT
326     ByteString sdf = "/dev/stdout";
327 #else
328     ByteString sdf = "\\\\.\\CON";
329 #endif
330     if ( mOutput.Len() )
331         sdf = mOutput;
332     Export::SetLanguages( mLanguages );
333     HelpParser::CreateSDF( sdf, mProject, mRoot, xmlFile,
334                            new LayoutXMLFile( mMergeMode ), mGid1 );
335 }
336 
337 void TranslateLayout::ExceptionalMain()
338 {
339     ParseCommandLine();
340     if ( mLanguages.size() )
341         mLanguage = mLanguages.front();
342     if ( mMergeMode )
343         Merge();
344     else
345         CreateSDF();
346 }
347 
348 void TranslateLayout::Main()
349 {
350     try
351     {
352         ExceptionalMain();
353     }
354     catch ( xml::sax::SAXException& rExc )
355     {
356         OString aStr( OUStringToOString( rExc.Message,
357                                          RTL_TEXTENCODING_ASCII_US ) );
358         uno::Exception exc;
359         if (rExc.WrappedException >>= exc)
360         {
361             aStr += OString( " >>> " );
362             aStr += OUStringToOString( exc.Message, RTL_TEXTENCODING_ASCII_US );
363         }
364         fprintf( stderr, "error: parsing: '%s'\n", aStr.getStr() );
365         OSL_ENSURE( 0, aStr.getStr() );
366     }
367     catch ( uno::Exception& rExc )
368     {
369         OString aStr( OUStringToOString( rExc.Message,
370                                          RTL_TEXTENCODING_ASCII_US ) );
371         fprintf( stderr, "error: UNO: '%s'\n", aStr.getStr() );
372         OSL_ENSURE( 0, aStr.getStr() );
373     }
374 }
375 
376 TranslateLayout::TranslateLayout()
377     : Application()
378     , mGid1( "layout" )
379     , mLanguage( "en-US" )
380     , mLocalize( "localize.sdf" )
381     , mOutput()
382     , mProject( "layout" )
383     , mRoot()
384     , mMergeMode( false )
385     , mLanguages()
386     , mFiles()
387 {
388 }
389 
390 TranslateLayout::~TranslateLayout()
391 {
392 }
393 
394 SAL_IMPLEMENT_MAIN()
395 {
396     TranslateLayout t;
397     t.Main();
398     return 0;
399 }
400