/* **************************************************************************** This file is part of KBabel Copyright (C) 1999-2001 by Matthias Kiefer 2002-2003 by StanislavVsinovsky This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the TQt library by Trolltech AS, Norway (or with modified versions of TQt that use the same license as TQt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than TQt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. **************************************************************************** */ #include "catalog.h" #include "catalogsettings.h" #include "editcmd.h" #include "dictchooser.h" #include "kbabeldictbox.h" #include "regexpextractor.h" #include "roughtransdlg.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KBabel; RoughTransDlg::RoughTransDlg(KBabelDictBox *dict, Catalog *cat , TQWidget *parent,const char *name) : KDialogBase(parent,name,true ,i18n("Caption of dialog","Rough Translation") , User1|User2|User3|Close) ,catalog(cat) ,active(false) ,stop(false) ,cancel(false) ,dictBox(dict) ,exactTransCounter(0) ,partTransCounter(0) ,totalTried(0) { setButtonBoxOrientation(Qt::Vertical); setButtonText(User1,i18n("&Start")); setButtonText(User2,i18n("S&top")); setButtonText(User3,i18n("C&ancel")); enableButton(User2,false); enableButton(User3,false); TQWidget *mw = new TQWidget(this); setMainWidget(mw); TQVBoxLayout *mainLayout = new TQVBoxLayout(mw); configWidget = new TQVBox(mw); mainLayout->addWidget(configWidget); TQVGroupBox *box = new TQVGroupBox(i18n("What to Translate"),configWidget); TQHButtonGroup *bBox = new TQHButtonGroup(box); bBox->setMargin(0); bBox->setFrameStyle(TQFrame::NoFrame); whatBox = bBox; untransButton = new TQCheckBox(i18n("U&ntranslated entries"),bBox); fuzzyButton = new TQCheckBox(i18n("&Fuzzy entries"),bBox); transButton = new TQCheckBox(i18n("T&ranslated entries"),bBox); connect(bBox,TQT_SIGNAL(clicked(int)),this,TQT_SLOT(msgButtonClicked(int))); TQWhatsThis::add(bBox,i18n("

What entries to translate

" "

Choose here, for which entries of the file KBabel " "tries to find a translation. Changed entries are always " "marked as fuzzy, no matter which option you choose.

")); box = new TQVGroupBox(i18n("How to Translate"),configWidget); bBox = new TQHButtonGroup(box); bBox->setFrameStyle(TQFrame::NoFrame); bBox->setMargin(0); searchMatchButton = new TQCheckBox(i18n("&Use dictionary settings") ,bBox); fuzzyMatchButton = new TQCheckBox(i18n("Fu&zzy translation (slow)") ,bBox); singleWordButton = new TQCheckBox(i18n("&Single word translation") ,bBox); TQWhatsThis::add(bBox,i18n("

How messages get translated

" "

Here you can define if a message can only get translated " "completely, if similar messages are acceptable or if KBabel " "is supposed to try translating " "the single words of a message if no translation of the " "complete message or similar message was found.

")); box = new TQVGroupBox(i18n("Options"),configWidget); markFuzzyButton = new TQCheckBox(i18n("&Mark changed entries as fuzzy"),box); markFuzzyButton->setChecked(true); TQWhatsThis::add(markFuzzyButton, i18n("

Mark changed entries as fuzzy

" "

When a translation for a message is found, the entry " "will be marked fuzzy by default. This is because the " "translation is just guessed by KBabel and you should always " "check the results carefully. Deactivate this option only if " "you know what you are doing.

")); connect(markFuzzyButton, TQT_SIGNAL(toggled(bool)) , this, TQT_SLOT(fuzzyButtonToggled(bool))); kdeButton = new TQCheckBox(i18n("Initialize &TDE-specific entries"),box); kdeButton->setChecked(true); TQWhatsThis::add(kdeButton, i18n("

Initialize TDE-specific entries

" "

Initialize \"Comment=\" and \"Name=\" entries " "if a translation is not found. Also, \"NAME OF TRANSLATORS\" " "and \"EMAIL OF TRANSLATORS\" is filled with identity settings.

")); TQVGroupBox *dBox = new TQVGroupBox(i18n("Dictionaries"),configWidget); configWidget->setStretchFactor(dBox,1); TQPtrList moduleList = dict->moduleInfos(); TDEConfig *config = TDEGlobal::config(); TDEConfigGroupSaver gs(config,"RoughTranslation"); TQStringList selectedList=config->readListEntry("Selected"); if(selectedList.isEmpty()) { int a = dict->activeModule(); ModuleInfo *mi = moduleList.at(a); if(mi) { selectedList.append(mi->id); } } dictChooser = new DictChooser(dict,selectedList,dBox,"dictChooser"); TQWhatsThis::add(dictChooser,i18n("

Dictionaries

" "

Choose here, which dictionaries have to be used for " "finding a translation. If you select more than one " "dictionary, they are used in the same order as they " "are displayed in the list.

" "

The Configure button allows you to temporarily " "configure selected dictionary. The original settings " "will be restored after closing the dialog.

")); TQLabel* label = new TQLabel( i18n("Messages:"), mw ); progressbar = new KProgress(mw,"progressbar"); progressbar->setTextEnabled(true); progressbar->setFormat("%v/%m (%p%)"); TQHBoxLayout* pblayout= new TQHBoxLayout(mainLayout); pblayout->add(label); pblayout->add(progressbar); transButton->setChecked(config->readBoolEntry("Translated",false)); untransButton->setChecked(config->readBoolEntry("Untranslated",true)); fuzzyButton->setChecked(config->readBoolEntry("Fuzzies",false)); bool flag = config->readBoolEntry("fuzzyMatch",true); fuzzyMatchButton->setChecked(flag); flag = config->readBoolEntry("searchMatch",true); searchMatchButton->setChecked(flag); flag = config->readBoolEntry("singleWord",true); singleWordButton->setChecked(flag); flag = config->readBoolEntry("kdeSpecific",true); kdeButton->setChecked(flag); msgButtonClicked(0); } RoughTransDlg::~RoughTransDlg() { TDEConfig *config=TDEGlobal::config(); TDEConfigGroupSaver gs(config,"RoughTranslation"); config->writeEntry("Selected",dictChooser->selectedDicts()); bool flag=transButton->isChecked(); config->writeEntry("Translated",flag); flag=untransButton->isChecked(); config->writeEntry("Untranslated",flag); flag=fuzzyButton->isChecked(); config->writeEntry("Fuzzies",flag); flag=singleWordButton->isChecked(); config->writeEntry("singleWord",flag); flag=fuzzyMatchButton->isChecked(); config->writeEntry("fuzzyMatch",flag); flag=searchMatchButton->isChecked(); config->writeEntry("searchMatch",flag); flag=kdeButton->isChecked(); config->writeEntry("kdeSpecific",flag); } void RoughTransDlg::slotUser1() { configWidget->setEnabled(false); enableButton(User1,false); enableButton(Close,false); enableButton(User2,true); enableButton(User3,true); active=true; stop=false; cancel=false; exactTransCounter=0; partTransCounter=0; totalTried=0; TQTimer::singleShot(0,this, TQT_SLOT(translate())); } void RoughTransDlg::translate() { bool markFuzzy = markFuzzyButton->isChecked(); bool translated = transButton->isChecked(); bool untranslated = untransButton->isChecked(); bool fuzzies = fuzzyButton->isChecked(); bool kdeSpecific=kdeButton->isChecked(); int total=catalog->numberOfEntries(); progressbar->setTotalSteps(total); TQStringList dictList = dictChooser->selectedDicts(); catalog->applyBeginCommand(0,Msgstr,0); bool singleWords=singleWordButton->isChecked(); bool fuzzyMatch=fuzzyMatchButton->isChecked(); bool searchMatch=searchMatchButton->isChecked(); TQRegExp contextReg=catalog->miscSettings().contextInfo; TQChar accelMarker=catalog->miscSettings().accelMarker; TQRegExp endPunctReg("[\\.?!: ]+$"); for(int i = 0; i < total; i++) { progressbar->setProgress(i+1); kapp->processEvents(100); if(stop || cancel) break; // FIXME: should care about plural forms TQString msg=catalog->msgid(i,true).first(); TQString translation; // this is KDE specific: if( kdeSpecific ) { if( catalog->pluralForm(i) == NoPluralForm ) { TQString origTrans = catalog->msgstr(i).first(); if(msg.find("_: NAME OF TRANSLATORS\\n")==0) { TQString authorName; if( !catalog->identitySettings().authorLocalizedName.isEmpty() ) authorName = catalog->identitySettings().authorLocalizedName; else // fallback to non-localized name if( !catalog->identitySettings().authorName.isEmpty() ) authorName = catalog->identitySettings().authorName; else continue; // there is no name to be inserted if( !TQStringList::split(',', origTrans).contains(authorName) ) { if(origTrans.isEmpty() ) translation=authorName; else translation+=origTrans+","+authorName; } } else if(msg.find("_: EMAIL OF TRANSLATORS\\n")==0) { // skip, if email is not specified in settings if( catalog->identitySettings().authorEmail.isEmpty() ) continue; if( !TQStringList::split(',', origTrans).contains(catalog->identitySettings().authorEmail) ) { if(origTrans.isEmpty() ) translation=catalog->identitySettings().authorEmail; else translation=origTrans+","+catalog->identitySettings().authorEmail; } } else if (msg.find("ROLES_OF_TRANSLATORS") == 0) { TQString temp = "\n" "\n
" + catalog->identitySettings( ).authorEmail+"
\n" "
"; if (origTrans.isEmpty( )) translation = temp; else if (origTrans.find(catalog->identitySettings( ).authorEmail) < 0) translation = origTrans + "\n" + temp; } else if (msg.find("CREDIT_FOR_TRANSLATORS") == 0) { TQString authorName; if (!catalog->identitySettings( ).authorLocalizedName.isEmpty( )) authorName = catalog->identitySettings( ).authorLocalizedName; else if (!catalog->identitySettings( ).authorName.isEmpty( )) authorName = catalog->identitySettings( ).authorName; TQString temp = "" + authorName + "\n" + "" + catalog->identitySettings( ).authorEmail + ""; if (origTrans.isEmpty( )) translation = temp; else if (origTrans.find(authorName) < 0 && origTrans.find(catalog->identitySettings( ).authorEmail) < 0) translation = origTrans + "\n" + temp; } } } else // not kdeSpecific { // skip KDE specific texts if( msg.find("_: EMAIL OF TRANSLATORS\\n")==0 || msg.find("_: NAME OF TRANSLATORS\\n")==0 || msg.find("ROLES_OF_TRANSLATORS")==0 || msg.find("CREDIT_FOR_TRANSLATORS")==0) continue; } if( translation.isEmpty() ) // KDE-specific translation didn't work { if( !untranslated && catalog->isUntranslated(i) ) continue; if( !translated && !catalog->isUntranslated(i) && !catalog->isFuzzy(i) ) continue; if( !fuzzies && catalog->isFuzzy(i) ) continue; } totalTried++; if(msg.contains(contextReg)) { msg.replace(contextReg,""); } // try exact translation TQStringList::Iterator dit = dictList.begin(); while(translation.isEmpty() && dit != dictList.end()) { dictBox->setActiveModule(*dit); translation = dictBox->translate(msg); ++dit; } if(!translation.isEmpty()) { exactTransCounter++; } // try search settings translation else if (searchMatch) { TQString tr; int score, best_score = 0; dit = dictList.begin(); while(dit != dictList.end()) { dictBox->setActiveModule(*dit); tr = dictBox->searchTranslation(msg,score); kdDebug() << "Found: " << tr << ", score " << score << endl; if (score > best_score) { kdDebug() << "Best score" << endl; translation = tr; best_score = score; } ++dit; } if(!translation.isEmpty()) { partTransCounter++; } } // try fuzzy translation else if (fuzzyMatch) { TQString tr; int score, best_score = 0; dit = dictList.begin(); while(dit != dictList.end()) { dictBox->setActiveModule(*dit); tr = dictBox->fuzzyTranslation(msg,score); if (score > best_score) { translation = tr; best_score = score; } ++dit; } if(!translation.isEmpty()) { partTransCounter++; } } kdDebug() << "Best translation so far: " << translation << endl; // try single word translation if(translation.isEmpty() && singleWords) { TQStringList wordList; TQChar accel; TQString endingPunctuation; int pos = msg.findRev(endPunctReg); if(pos >= 0) { endingPunctuation = msg.right(msg.length()-pos); } msg=msg.simplifyWhiteSpace(); msg=msg.stripWhiteSpace(); RegExpExtractor te(catalog->tagSettings().tagExpressions); te.setString(msg); msg=te.matchesReplaced(" KBABELTAG "); TQString word; int length = msg.length(); TQRegExp digitReg("^[0-9]*$"); for(int index=0; index < length; index++) { TQChar c=msg[index]; if(c==accelMarker) { index++; if(index < length) { if(msg[index].isLetterOrNumber()) { word+=msg[index]; accel=msg[index]; } else if(!word.isEmpty() ) { if(!word.contains(digitReg)) wordList.append(word); word=TQString(); } } else if(!word.isEmpty()) { if(!word.contains(digitReg)) wordList.append(word); word=TQString(); } } else if(c.isLetterOrNumber()) { word+=c; } else if(c == '\\') { if(index < length-2) { if(msg[index+1]=='n' && msg[index+2].isSpace()) { if(!word.isEmpty() && !word.contains(digitReg)) wordList.append(word); word=TQString(); wordList.append("\\n\n"); index+=2; } else if(!word.isEmpty() ) { if(!word.contains(digitReg)) wordList.append(word); word=TQString(); } } else if(!word.isEmpty()) { if(!word.contains(digitReg)) wordList.append(word); word=TQString(); } } else if(!word.isEmpty()) { if(!word.contains(digitReg)) { wordList.append(word); } word=TQString(); } } // handle the last word as well if( !word.isEmpty() ) wordList.append(word); dit = dictList.begin(); int wordCounter=0; while(wordCounter==0 && dit != dictList.end()) { dictBox->setActiveModule(*dit); for(TQStringList::Iterator it=wordList.begin(); it!=wordList.end(); ++it) { if( (*it)=="\\n\n" ) { translation+="\\n\n"; } else if( (*it)=="KBABELTAG" ) { translation+=te.nextMatch(); } else { TQString trans = dictBox->translate(*it); if(!trans.isEmpty()) { wordCounter++; if(!translation.isEmpty()) { translation += ' '; } translation += trans; } } } if(wordCounter==0) translation=TQString(); ++dit; } if(!translation.isEmpty()) { partTransCounter++; // try to set the correct keyboard accelerator if(!accel.isNull()) { int index = translation.find(accel,0,false); if(index >= 0) { translation.insert(index,accelMarker); } } translation+=endingPunctuation; } } // this is KDE specific: if(kdeSpecific && translation.isEmpty()) { if( msg.startsWith("Name=") ) { translation="Name="; partTransCounter++; } if( msg.startsWith("Comment=") ) { translation="Comment="; partTransCounter++; } } if(!translation.isEmpty()) { if(!catalog->isUntranslated(i)) { TQStringList msgs = catalog->msgstr(i); uint counter = 0; for( TQStringList::Iterator it = msgs.begin() ; it != msgs.end() ; ++it) { DelTextCmd* delCmd = new DelTextCmd(0 ,(*it),counter++); delCmd->setPart(Msgstr); delCmd->setIndex(i); catalog->applyEditCommand(delCmd,0); } } for( int count=0; count < catalog->numberOfPluralForms(i) ; count++ ) { InsTextCmd* insCmd = new InsTextCmd(0,translation,count); insCmd->setPart(Msgstr); insCmd->setIndex(i); catalog->applyEditCommand(insCmd,0); } if(markFuzzy) { catalog->setFuzzy(i,true); } } } catalog->applyEndCommand(0,Msgstr,0); if(stop || cancel) { if(cancel) { catalog->undo(); } else { msgButtonClicked(0); } progressbar->setProgress(0); configWidget->setEnabled(true); active = false; enableButton(User1,true); enableButton(Close,true); enableButton(User2,false); enableButton(User3,false); return; } showStatistics(); } void RoughTransDlg::showStatistics() { int nothing=totalTried-partTransCounter-exactTransCounter; TDELocale *locale = TDEGlobal::locale(); TQString statMsg = i18n("Result of the translation:\n" "Edited entries: %1\n" "Exact translations: %2 (%3%)\n" "Approximate translations: %4 (%5%)\n" "Nothing found: %6 (%7%)") .arg( locale->formatNumber(totalTried,0) ) .arg( locale->formatNumber(exactTransCounter,0) ) .arg( locale->formatNumber( ((double)(10000*exactTransCounter/TQMAX(totalTried,1)))/100) ) .arg( locale->formatNumber(partTransCounter,0) ) .arg( locale->formatNumber(((double)(10000*partTransCounter/TQMAX(totalTried,1)))/100) ) .arg( locale->formatNumber(nothing,0) ) .arg( locale->formatNumber(((double)(10000*nothing/TQMAX(totalTried,1)))/100) ); KMessageBox::information(this, statMsg , i18n("Rough Translation Statistics")); dictChooser->restoreConfig(); accept(); } void RoughTransDlg::slotClose() { if(active) { cancel = true; return; } else { dictChooser->restoreConfig(); accept(); } } void RoughTransDlg::slotUser2() { stop=true; } void RoughTransDlg::slotUser3() { cancel=true; } void RoughTransDlg::msgButtonClicked(int id) { if(!transButton->isChecked() && !untransButton->isChecked() && !fuzzyButton->isChecked()) { TQButton *button = whatBox->find(id); if(button == transButton) { transButton->setChecked(true); } else if(button == untransButton) { untransButton->setChecked(true); } else if(button == fuzzyButton) { fuzzyButton->setChecked(true); } } progressbar->setTotalSteps(catalog->numberOfEntries()); enableButton(User1,catalog->numberOfEntries()); } void RoughTransDlg::fuzzyButtonToggled(bool on) { if(!on) { TQString msg=i18n("

" "When a translation for a message is found, the entry " "will be marked fuzzy by default. This is because the " "translation is just guessed by KBabel and you should always " "check the results carefully. Deactivate this option only if " "you know what you are doing.

"); KMessageBox::information(this, msg, TQString(),"MarkFuzzyWarningInRoughTransDlg"); } } void RoughTransDlg::statistics(int &total, int& exact, int& part) const { total = totalTried; exact = exactTransCounter; part = partTransCounter; } #include "roughtransdlg.moc"