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