blob: 75827a8b47590a18648433ac08b6b7e9fec909c8 [file] [log] [blame]
/**************************************************************
*
* 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;
}