| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include <com/sun/star/xml/sax/SAXException.hpp> |
| #include <l10ntools/vosapp.hxx> |
| |
| #include <osl/file.hxx> |
| |
| #include "export.hxx" |
| #include "layoutparse.hxx" |
| #include "helpmerge.hxx" |
| #include "xmlparse.hxx" |
| |
| // Convert a rtl::OUString to a byte string. |
| #define OUSTRING_CSTR( str ) \ |
| rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() |
| |
| #define STRING( str ) String( str, RTL_TEXTENCODING_UTF8 ) |
| #define BSTRING( str ) ByteString( str, RTL_TEXTENCODING_UTF8 ) |
| |
| using ::rtl::OUString; |
| |
| using namespace ::osl; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| |
| |
| class TranslateLayout : public Application |
| { |
| ByteString mGid1; |
| ByteString mLanguage; |
| ByteString mLocalize; |
| ByteString mOutput; |
| ByteString mProject; |
| ByteString mRoot; |
| bool mMergeMode; |
| std::vector< ByteString > mLanguages; |
| std::list< ByteString > mFiles; |
| |
| public: |
| TranslateLayout(); |
| virtual ~TranslateLayout(); |
| ByteString GetCommandLineParam( int i ); |
| ByteString GetOptionArgument( int const i ); |
| void ExceptionalMain(); |
| void Main(); |
| void Merge(); |
| void MergeLanguage( ByteString const& language ); |
| void ParseCommandLine(); |
| void CreateSDF(); |
| |
| using Application::GetCommandLineParam; |
| }; |
| |
| static void usage() |
| { |
| fprintf( stderr, "Usage: tralay [OPTION]... XML-FILE\n" ); |
| fprintf( stderr, "\nOptions:\n" ); |
| fprintf( stderr, " -h,--help show this help\n" ); |
| fprintf( stderr, " -l,--language=LANG process this language\n" ); |
| fprintf( stderr, " -m,--merge=DATABASE.SDF translation database\n" ); |
| fprintf( stderr, "\nExamples:\n" ); |
| fprintf( stderr, " tralay -l en-US -o localize.sdf zoom.xml # Extract\n" ); |
| fprintf( stderr, " tralay -m localize.sdf -l de -l nl -o out zoom.xml # Merge/translate\n" ); |
| exit( 2 ); |
| } |
| |
| static ByteString ConvertSystemPath( const ByteString& rPath ) |
| { |
| if( rPath.CompareTo( ".", 1 ) == 0 ) |
| { |
| OUString sPath( rPath.GetBuffer(), rPath.Len(), RTL_TEXTENCODING_UTF8 ); |
| |
| ::rtl::OUString curDirPth, sURL; |
| osl_getProcessWorkingDir( &curDirPth.pData ); |
| |
| ::osl::FileBase::getAbsoluteFileURL( curDirPth, sPath, sURL ); |
| ::osl::FileBase::getSystemPathFromFileURL( sURL, sPath ); |
| |
| return ByteString( rtl::OUStringToOString( sPath, RTL_TEXTENCODING_UTF8 ) ); |
| } |
| else |
| { |
| return rPath; |
| } |
| } |
| |
| ByteString TranslateLayout::GetCommandLineParam( int i ) |
| { |
| return ByteString( OUSTRING_CSTR( Application::GetCommandLineParam( sal::static_int_cast< sal_uInt16 >( i ) ) ) ); |
| } |
| |
| ByteString TranslateLayout::GetOptionArgument( int const i ) |
| { |
| if ( i >= GetCommandLineParamCount() ) |
| usage(); |
| ByteString arg = GetCommandLineParam( i ); |
| if ( !arg.CompareTo( "-", 1 ) ) |
| { |
| fprintf( stderr, "Option needs an argument: %s, found: %s\n", |
| GetCommandLineParam( i - 1 ).GetBuffer(), |
| arg.GetBuffer() ); |
| usage(); |
| } |
| return arg; |
| } |
| |
| void TranslateLayout::ParseCommandLine() |
| { |
| for ( int i = 0; i < GetCommandLineParamCount(); i++ ) |
| { |
| ByteString aParam = GetCommandLineParam( i ); |
| if ( aParam.Equals( "-h" ) || aParam.Equals( "--help" ) ) |
| usage(); |
| else if ( aParam.Equals( "-l" ) || aParam.Equals( "--language" ) ) |
| mLanguages.push_back ( GetOptionArgument( ++i ) ); |
| else if ( aParam.Equals( "-m" ) || aParam.Equals( "--merge" ) ) |
| { |
| mMergeMode = true; |
| mLocalize = GetOptionArgument( ++i ); |
| } |
| else if ( aParam.Equals( "-o" ) || aParam.Equals( "--output" ) ) |
| mOutput = ConvertSystemPath( GetOptionArgument( ++i ) ); |
| else if ( !aParam.CompareTo( "-", 1 ) ) |
| { |
| fprintf( stderr, "error: No such option: %s\n", aParam.GetBuffer() ); |
| usage(); |
| } |
| else |
| mFiles.push_back( ConvertSystemPath( aParam ) ); |
| } |
| if ( !mFiles.size() ) |
| { |
| fprintf( stderr, "error: No XML-FILE found\n" ); |
| usage(); |
| } |
| } |
| |
| static XMLAttribute* |
| findAttribute( XMLAttributeList* lst, String const& name ) |
| { |
| for ( sal_uLong i = 0; i < lst->Count(); i++ ) |
| if ( lst->GetObject( i )->Equals( name ) ) |
| return lst->GetObject( i ); |
| return 0; |
| } |
| |
| static XMLAttribute* |
| translateAttribute( XMLAttributeList* lst, |
| String const& name, String const& translation ) |
| { |
| if ( XMLAttribute* a = findAttribute( lst, name ) ) |
| return lst->Replace ( new XMLAttribute( name.Copy( 1 ), translation ), a ); |
| return 0; |
| } |
| |
| static void |
| translateElement( XMLElement* element, ByteString const& lang, |
| ResData* resData, MergeDataFile& mergeData ) |
| { |
| XMLAttributeList* attributes = element->GetAttributeList(); |
| std::vector<XMLAttribute*> interesting( interestingAttributes( attributes ) ); |
| |
| |
| if( !interesting.empty() ) |
| { |
| std::vector<XMLAttribute*>::iterator i( interesting.begin() ); |
| ByteString id = BSTRING( (*i++)->GetValue() ); |
| for ( ; i != interesting.end(); ++i ) |
| { |
| ByteString attributeId = id; |
| attributeId += BSTRING ( **i ); |
| resData->sGId = attributeId; |
| resData->sId = element->GetOldref(); |
| |
| if ( PFormEntrys* entry = mergeData.GetPFormEntrys( resData ) ) |
| { |
| ByteString translation; |
| entry->GetText( translation, STRING_TYP_TEXT, lang, true ); |
| // ByteString original = removeContent( element ); |
| if ( !translation.Len() ) |
| #if 0 |
| translation = original; |
| #else |
| translation = BSTRING( ( *i )->GetValue() ); |
| #endif |
| delete translateAttribute( attributes, **i , STRING( translation ) ); |
| } |
| } |
| } |
| } |
| |
| static bool is_dir( ByteString const& name ) |
| { |
| DirectoryItem aItem; |
| OUString sFileURL( name.GetBuffer(), name.Len(), RTL_TEXTENCODING_UTF8 ); |
| FileBase::getFileURLFromSystemPath( sFileURL, sFileURL ); |
| if( DirectoryItem::get( sFileURL, aItem ) == FileBase::E_None ) |
| { |
| FileStatus aStatus(FileStatusMask_Type); |
| if( aItem.getFileStatus( aStatus ) == FileBase::E_None ) |
| { |
| if( aStatus.getFileType() == FileStatus::Directory ) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| static void make_directory( ByteString const& name ) |
| { |
| OUString sFileURL( name.GetBuffer(), name.Len(), RTL_TEXTENCODING_UTF8 ); |
| FileBase::getFileURLFromSystemPath( sFileURL, sFileURL ); |
| Directory::create( sFileURL ); |
| } |
| |
| static void insertMarker( XMLParentNode *p, ByteString const& file ) |
| { |
| if ( XMLChildNodeList* lst = p->GetChildList() ) |
| if ( lst->Count() ) |
| { |
| sal_uLong i = 1; |
| // Skip newline, if possible. |
| if ( lst->Count() > 1 |
| && lst->GetObject( 2 )->GetNodeType() == XML_NODE_TYPE_DEFAULT ) |
| i++; |
| OUString marker = OUString::createFromAscii( "\n NOTE: This file has been generated automagically by transex3/layout/tralay,\n from source template: " ) |
| + STRING( file ) |
| + OUString::createFromAscii( ".\n Do not edit, changes will be lost.\n" ); |
| lst->Insert( new XMLComment( marker, 0 ), i ); |
| } |
| } |
| |
| void TranslateLayout::MergeLanguage( ByteString const& language ) |
| { |
| ByteString xmlFile = mFiles.front(); |
| |
| MergeDataFile mergeData( mLocalize, xmlFile, |
| sal_False, RTL_TEXTENCODING_MS_1252 ); |
| |
| DirEntry aFile( xmlFile ); |
| SimpleXMLParser aParser; |
| LayoutXMLFile* layoutXml = new LayoutXMLFile( mMergeMode ); |
| if ( !aParser.Execute( aFile.GetFull() , STRING( xmlFile ), layoutXml ) ) |
| { |
| fprintf(stderr, "error: parsing: %s\n", xmlFile.GetBuffer() ); |
| return; |
| } |
| |
| layoutXml->Extract(); |
| insertMarker( layoutXml, xmlFile ); |
| |
| ResData resData( "", "", "" ); |
| resData.sResTyp = mProject; /* mGid1 ?? */ |
| resData.sFilename = xmlFile; |
| |
| XMLHashMap* xmlStrings = layoutXml->GetStrings(); |
| for ( XMLHashMap::iterator i = xmlStrings->begin(); i != xmlStrings->end(); |
| ++i ) |
| { |
| if ( LangHashMap* languageMap = i->second ) |
| if ( XMLElement* element = ( *languageMap )[ "en-US" ] ) |
| translateElement( element, language, &resData, mergeData ); |
| } |
| |
| #ifndef WNT |
| ByteString outFile = "/dev/stdout"; |
| #else |
| ByteString outFile = "\\\\.\\CON"; |
| #endif |
| if ( mOutput.Len() ) |
| { |
| outFile = mOutput; |
| if ( is_dir( outFile ) ) |
| { |
| ByteString outDir = mOutput; |
| outDir.Append( "/" ).Append( language ); |
| if ( !is_dir( outDir ) ) |
| make_directory( outDir ); |
| outFile = outDir; |
| outFile.Append( "/" ).Append( xmlFile ); |
| } |
| } |
| layoutXml->Write( outFile ); |
| delete layoutXml; |
| } |
| |
| void TranslateLayout::Merge() |
| { |
| if ( mLanguages.size() ) |
| for ( std::vector<ByteString>::iterator i = mLanguages.begin(); |
| i != mLanguages.end(); ++i) |
| MergeLanguage( *i ); |
| else |
| MergeLanguage( mLanguage ); |
| } |
| |
| void TranslateLayout::CreateSDF() |
| { |
| ByteString xmlFile = mFiles.front(); |
| #ifndef WNT |
| ByteString sdf = "/dev/stdout"; |
| #else |
| ByteString sdf = "\\\\.\\CON"; |
| #endif |
| if ( mOutput.Len() ) |
| sdf = mOutput; |
| Export::SetLanguages( mLanguages ); |
| HelpParser::CreateSDF( sdf, mProject, mRoot, xmlFile, |
| new LayoutXMLFile( mMergeMode ), mGid1 ); |
| } |
| |
| void TranslateLayout::ExceptionalMain() |
| { |
| ParseCommandLine(); |
| if ( mLanguages.size() ) |
| mLanguage = mLanguages.front(); |
| if ( mMergeMode ) |
| Merge(); |
| else |
| CreateSDF(); |
| } |
| |
| void TranslateLayout::Main() |
| { |
| try |
| { |
| ExceptionalMain(); |
| } |
| catch ( xml::sax::SAXException& rExc ) |
| { |
| OString aStr( OUStringToOString( rExc.Message, |
| RTL_TEXTENCODING_ASCII_US ) ); |
| uno::Exception exc; |
| if (rExc.WrappedException >>= exc) |
| { |
| aStr += OString( " >>> " ); |
| aStr += OUStringToOString( exc.Message, RTL_TEXTENCODING_ASCII_US ); |
| } |
| fprintf( stderr, "error: parsing: '%s'\n", aStr.getStr() ); |
| OSL_ENSURE( 0, aStr.getStr() ); |
| } |
| catch ( uno::Exception& rExc ) |
| { |
| OString aStr( OUStringToOString( rExc.Message, |
| RTL_TEXTENCODING_ASCII_US ) ); |
| fprintf( stderr, "error: UNO: '%s'\n", aStr.getStr() ); |
| OSL_ENSURE( 0, aStr.getStr() ); |
| } |
| } |
| |
| TranslateLayout::TranslateLayout() |
| : Application() |
| , mGid1( "layout" ) |
| , mLanguage( "en-US" ) |
| , mLocalize( "localize.sdf" ) |
| , mOutput() |
| , mProject( "layout" ) |
| , mRoot() |
| , mMergeMode( false ) |
| , mLanguages() |
| , mFiles() |
| { |
| } |
| |
| TranslateLayout::~TranslateLayout() |
| { |
| } |
| |
| SAL_IMPLEMENT_MAIN() |
| { |
| TranslateLayout t; |
| t.Main(); |
| return 0; |
| } |