summaryrefslogtreecommitdiffstats
path: root/tools/linguist
diff options
context:
space:
mode:
Diffstat (limited to 'tools/linguist')
-rw-r--r--tools/linguist/lconvert/main.cpp8
-rw-r--r--tools/linguist/linguist/batchtranslation.ui4
-rw-r--r--tools/linguist/linguist/images/minus.pngbin0 -> 296 bytes
-rw-r--r--tools/linguist/linguist/images/plus.pngbin0 -> 383 bytes
-rw-r--r--tools/linguist/linguist/linguist.qrc2
-rw-r--r--tools/linguist/linguist/mainwindow.cpp37
-rw-r--r--tools/linguist/linguist/mainwindow.h6
-rw-r--r--tools/linguist/linguist/mainwindow.ui33
-rw-r--r--tools/linguist/linguist/messageeditor.cpp122
-rw-r--r--tools/linguist/linguist/messageeditor.h12
-rw-r--r--tools/linguist/linguist/messageeditorwidgets.cpp248
-rw-r--r--tools/linguist/linguist/messageeditorwidgets.h50
-rw-r--r--tools/linguist/lrelease/lrelease.112
-rw-r--r--tools/linguist/lrelease/main.cpp29
-rw-r--r--tools/linguist/lupdate/cpp.cpp120
-rw-r--r--tools/linguist/lupdate/lupdate.114
-rw-r--r--tools/linguist/lupdate/main.cpp6
-rw-r--r--tools/linguist/shared/po.cpp10
-rw-r--r--tools/linguist/shared/profileevaluator.cpp4
-rw-r--r--tools/linguist/shared/qm.cpp64
-rw-r--r--tools/linguist/shared/qph.cpp7
-rw-r--r--tools/linguist/shared/translator.h8
-rw-r--r--tools/linguist/shared/ts.cpp6
-rw-r--r--tools/linguist/shared/ts.dtd8
-rw-r--r--tools/linguist/shared/xliff.cpp7
25 files changed, 667 insertions, 150 deletions
diff --git a/tools/linguist/lconvert/main.cpp b/tools/linguist/lconvert/main.cpp
index 534bc11..4bed02f 100644
--- a/tools/linguist/lconvert/main.cpp
+++ b/tools/linguist/lconvert/main.cpp
@@ -81,10 +81,10 @@ static int usage(const QStringList &args)
" --output-format <outformat>\n"
" Specify output format. See -if.\n\n"
" --input-codec <codec>\n"
- " Specify encoding for .qm input files. Default is 'Latin1'.\n"
+ " Specify encoding for QM input files. Default is 'Latin1'.\n"
" UTF-8 is always tried as well, corresponding to the trUtf8() function.\n\n"
" --drop-tags <regexp>\n"
- " Drop named extra tags when writing 'ts' or 'xlf' files.\n"
+ " Drop named extra tags when writing TS or XLIFF files.\n"
" May be specified repeatedly.\n\n"
" --drop-translations\n"
" Drop existing translations and reset the status to 'unfinished'.\n"
@@ -101,10 +101,10 @@ static int usage(const QStringList &args)
" --no-finished\n"
" Drop finished messages.\n\n"
" --locations {absolute|relative|none}\n"
- " Override how source code references are saved in ts files.\n"
+ " Override how source code references are saved in TS files.\n"
" Default is absolute.\n\n"
" --no-ui-lines\n"
- " Drop line numbers from references to .ui files.\n\n"
+ " Drop line numbers from references to UI files.\n\n"
" --verbose\n"
" be a bit more verbose\n\n"
"Long options can be specified with only one leading dash, too.\n\n"
diff --git a/tools/linguist/linguist/batchtranslation.ui b/tools/linguist/linguist/batchtranslation.ui
index 88b55e2..0f7fe4b 100644
--- a/tools/linguist/linguist/batchtranslation.ui
+++ b/tools/linguist/linguist/batchtranslation.ui
@@ -104,7 +104,7 @@
<item>
<widget class="QCheckBox" name="ckTranslateFinished">
<property name="toolTip">
- <string>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked.</string>
+ <string>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked</string>
</property>
<property name="text">
<string>Translate also finished entries</string>
@@ -189,7 +189,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
- <string>The batch translator will search through the selected phrase books in the order given above.</string>
+ <string>The batch translator will search through the selected phrase books in the order given above</string>
</property>
<property name="wordWrap">
<bool>true</bool>
diff --git a/tools/linguist/linguist/images/minus.png b/tools/linguist/linguist/images/minus.png
new file mode 100644
index 0000000..745b445
--- /dev/null
+++ b/tools/linguist/linguist/images/minus.png
Binary files differ
diff --git a/tools/linguist/linguist/images/plus.png b/tools/linguist/linguist/images/plus.png
new file mode 100644
index 0000000..ef43788
--- /dev/null
+++ b/tools/linguist/linguist/images/plus.png
Binary files differ
diff --git a/tools/linguist/linguist/linguist.qrc b/tools/linguist/linguist/linguist.qrc
index 42cf6e3..a43f0ce 100644
--- a/tools/linguist/linguist/linguist.qrc
+++ b/tools/linguist/linguist/linguist.qrc
@@ -32,6 +32,8 @@
<file>images/up.png</file>
<file>images/down.png</file>
<file>images/editdelete.png</file>
+ <file>images/minus.png</file>
+ <file>images/plus.png</file>
<file>images/win/accelerator.png</file>
<file>images/win/book.png</file>
<file>images/win/doneandnext.png</file>
diff --git a/tools/linguist/linguist/mainwindow.cpp b/tools/linguist/linguist/mainwindow.cpp
index 18edc05..bb79b19 100644
--- a/tools/linguist/linguist/mainwindow.cpp
+++ b/tools/linguist/linguist/mainwindow.cpp
@@ -82,6 +82,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QPrintDialog>
+#include <QPrinter>
#include <QProcess>
#include <QRegExp>
#include <QSettings>
@@ -257,6 +258,7 @@ bool FocusWatcher::eventFilter(QObject *, QEvent *event)
MainWindow::MainWindow()
: QMainWindow(0, Qt::Window),
m_assistantProcess(0),
+ m_printer(0),
m_findMatchCase(Qt::CaseInsensitive),
m_findIgnoreAccelerators(true),
m_findWhere(DataModel::NoLocation),
@@ -480,6 +482,10 @@ MainWindow::MainWindow()
readConfig();
m_statistics = 0;
+ connect(m_ui.actionLenghtVariants, SIGNAL(toggled(bool)),
+ m_messageEditor, SLOT(setLenghtVariants(bool)));
+ m_messageEditor->setLenghtVariants(m_ui.actionLenghtVariants->isChecked());
+
m_focusWatcher = new FocusWatcher(m_messageEditor, this);
m_contextView->installEventFilter(m_focusWatcher);
m_messageView->installEventFilter(m_focusWatcher);
@@ -499,6 +505,7 @@ MainWindow::~MainWindow()
qDeleteAll(m_phraseBooks);
delete m_dataModel;
delete m_statistics;
+ delete m_printer;
}
void MainWindow::modelCountChanged()
@@ -866,15 +873,22 @@ void MainWindow::releaseAll()
releaseInternal(i);
}
+QPrinter *MainWindow::printer()
+{
+ if (!m_printer)
+ m_printer = new QPrinter;
+ return m_printer;
+}
+
void MainWindow::print()
{
int pageNum = 0;
- QPrintDialog dlg(&m_printer, this);
+ QPrintDialog dlg(printer(), this);
if (dlg.exec()) {
QApplication::setOverrideCursor(Qt::WaitCursor);
- m_printer.setDocName(m_dataModel->condensedSrcFileNames(true));
+ printer()->setDocName(m_dataModel->condensedSrcFileNames(true));
statusBar()->showMessage(tr("Printing..."));
- PrintOut pout(&m_printer);
+ PrintOut pout(printer());
for (int i = 0; i < m_dataModel->contextCount(); ++i) {
MultiContextItem *mc = m_dataModel->multiContextItem(i);
@@ -1225,11 +1239,11 @@ void MainWindow::printPhraseBook(QAction *action)
int pageNum = 0;
- QPrintDialog dlg(&m_printer, this);
+ QPrintDialog dlg(printer(), this);
if (dlg.exec()) {
- m_printer.setDocName(phraseBook->fileName());
+ printer()->setDocName(phraseBook->fileName());
statusBar()->showMessage(tr("Printing..."));
- PrintOut pout(&m_printer);
+ PrintOut pout(printer());
pout.setRule(PrintOut::ThinRule);
foreach (const Phrase *p, phraseBook->phrases()) {
pout.setGuide(p->source());
@@ -2358,6 +2372,13 @@ void MainWindow::updateDanger(const MultiDataIndex &index, bool verbose)
}
QStringList translations = m->translations();
+ // Truncated variants are permitted to be "denormalized"
+ for (int i = 0; i < translations.count(); ++i) {
+ int sep = translations.at(i).indexOf(QChar(Translator::BinaryVariantSeparator));
+ if (sep >= 0)
+ translations[i].truncate(sep);
+ }
+
if (m_ui.actionAccelerators->isChecked()) {
bool sk = !QKeySequence::mnemonic(source).isEmpty();
bool tk = true;
@@ -2500,6 +2521,8 @@ void MainWindow::readConfig()
config.value(settingPath("Validators/PhraseMatch"), true).toBool());
m_ui.actionPlaceMarkerMatches->setChecked(
config.value(settingPath("Validators/PlaceMarkers"), true).toBool());
+ m_ui.actionLenghtVariants->setChecked(
+ config.value(settingPath("Options/LengthVariants"), false).toBool());
recentFiles().readConfig();
@@ -2524,6 +2547,8 @@ void MainWindow::writeConfig()
m_ui.actionPhraseMatches->isChecked());
config.setValue(settingPath("Validators/PlaceMarkers"),
m_ui.actionPlaceMarkerMatches->isChecked());
+ config.setValue(settingPath("Options/LengthVariants"),
+ m_ui.actionLenghtVariants->isChecked());
config.setValue(settingPath("MainWindowState"),
saveState());
recentFiles().writeConfig();
diff --git a/tools/linguist/linguist/mainwindow.h b/tools/linguist/linguist/mainwindow.h
index 167dfe4..3dedcb5 100644
--- a/tools/linguist/linguist/mainwindow.h
+++ b/tools/linguist/linguist/mainwindow.h
@@ -51,7 +51,6 @@
#include <QtCore/QLocale>
#include <QtGui/QMainWindow>
-#include <QtGui/QPrinter>
QT_BEGIN_NAMESPACE
@@ -60,6 +59,7 @@ class QAction;
class QDialog;
class QLabel;
class QMenu;
+class QPrinter;
class QProcess;
class QIcon;
class QSortFilterProxyModel;
@@ -200,6 +200,8 @@ private:
void releaseInternal(int model);
void saveInternal(int model);
+ QPrinter *printer();
+
// FIXME: move to DataModel
void updateDanger(const MultiDataIndex &index, bool verbose);
@@ -226,7 +228,7 @@ private:
QList<QHash<QString, QList<Phrase *> > > m_phraseDict;
QList<PhraseBook *> m_phraseBooks;
QMap<QAction *, PhraseBook *> m_phraseBookMenu[3];
- QPrinter m_printer;
+ QPrinter *m_printer;
FindDialog *m_findDialog;
QString m_findText;
diff --git a/tools/linguist/linguist/mainwindow.ui b/tools/linguist/linguist/mainwindow.ui
index 6d42db0..613241b 100644
--- a/tools/linguist/linguist/mainwindow.ui
+++ b/tools/linguist/linguist/mainwindow.ui
@@ -60,7 +60,7 @@
<x>0</x>
<y>0</y>
<width>673</width>
- <height>30</height>
+ <height>28</height>
</rect>
</property>
<widget class="QMenu" name="menuPhrases">
@@ -116,6 +116,7 @@
<addaction name="actionResetSorting"/>
<addaction name="actionDisplayGuesses"/>
<addaction name="actionStatistics"/>
+ <addaction name="actionLenghtVariants"/>
<addaction name="separator"/>
<addaction name="menuToolbars"/>
<addaction name="menuViewViews"/>
@@ -401,7 +402,7 @@
<string>&amp;Prev Unfinished</string>
</property>
<property name="toolTip">
- <string>Previous unfinished item.</string>
+ <string>Previous unfinished item</string>
</property>
<property name="whatsThis">
<string>Move to the previous unfinished item.</string>
@@ -418,7 +419,7 @@
<string>&amp;Next Unfinished</string>
</property>
<property name="toolTip">
- <string>Next unfinished item.</string>
+ <string>Next unfinished item</string>
</property>
<property name="whatsThis">
<string>Move to the next unfinished item.</string>
@@ -435,7 +436,7 @@
<string>P&amp;rev</string>
</property>
<property name="toolTip">
- <string>Move to previous item.</string>
+ <string>Move to previous item</string>
</property>
<property name="whatsThis">
<string>Move to the previous item.</string>
@@ -452,7 +453,7 @@
<string>Ne&amp;xt</string>
</property>
<property name="toolTip">
- <string>Next item.</string>
+ <string>Next item</string>
</property>
<property name="whatsThis">
<string>Move to the next item.</string>
@@ -472,7 +473,7 @@
<string>&amp;Done and Next</string>
</property>
<property name="toolTip">
- <string>Mark item as done and move to the next unfinished item.</string>
+ <string>Mark item as done and move to the next unfinished item</string>
</property>
<property name="whatsThis">
<string>Mark this item as done and move to the next unfinished item.</string>
@@ -492,7 +493,7 @@
<string>Copy from source text</string>
</property>
<property name="toolTip">
- <string>Copies the source text into the translation field.</string>
+ <string>Copies the source text into the translation field</string>
</property>
<property name="whatsThis">
<string>Copies the source text into the translation field.</string>
@@ -512,7 +513,7 @@
<string>&amp;Accelerators</string>
</property>
<property name="toolTip">
- <string>Toggle the validity check of accelerators.</string>
+ <string>Toggle the validity check of accelerators</string>
</property>
<property name="whatsThis">
<string>Toggle the validity check of accelerators, i.e. whether the number of ampersands in the source and translation text is the same. If the check fails, a message is shown in the warnings window.</string>
@@ -529,7 +530,7 @@
<string>&amp;Ending Punctuation</string>
</property>
<property name="toolTip">
- <string>Toggle the validity check of ending punctuation.</string>
+ <string>Toggle the validity check of ending punctuation</string>
</property>
<property name="whatsThis">
<string>Toggle the validity check of ending punctuation. If the check fails, a message is shown in the warnings window.</string>
@@ -546,7 +547,7 @@
<string>&amp;Phrase matches</string>
</property>
<property name="toolTip">
- <string>Toggle checking that phrase suggestions are used.</string>
+ <string>Toggle checking that phrase suggestions are used</string>
</property>
<property name="whatsThis">
<string>Toggle checking that phrase suggestions are used. If the check fails, a message is shown in the warnings window.</string>
@@ -563,7 +564,7 @@
<string>Place &amp;Marker Matches</string>
</property>
<property name="toolTip">
- <string>Toggle the validity check of place markers.</string>
+ <string>Toggle the validity check of place markers</string>
</property>
<property name="whatsThis">
<string>Toggle the validity check of place markers, i.e. whether %1, %2, ... are used consistently in the source text and translation text. If the check fails, a message is shown in the warnings window.</string>
@@ -746,7 +747,7 @@
<string>Release As...</string>
</property>
<property name="whatsThis">
- <string>Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the .ts file.</string>
+ <string>Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the TS file.</string>
</property>
</action>
<action name="actionFile">
@@ -877,6 +878,14 @@
<string>Ctrl+W</string>
</property>
</action>
+ <action name="actionLenghtVariants">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Lenght Variants</string>
+ </property>
+ </action>
</widget>
<resources/>
<connections/>
diff --git a/tools/linguist/linguist/messageeditor.cpp b/tools/linguist/linguist/messageeditor.cpp
index be70d2b..9e598a8 100644
--- a/tools/linguist/linguist/messageeditor.cpp
+++ b/tools/linguist/linguist/messageeditor.cpp
@@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE
// functionality is provided within Qt (see task 196275).
static const char * language_strings[] =
{
+ QT_TRANSLATE_NOOP("MessageEditor", "Russian"),
QT_TRANSLATE_NOOP("MessageEditor", "German"),
QT_TRANSLATE_NOOP("MessageEditor", "Japanese"),
QT_TRANSLATE_NOOP("MessageEditor", "French"),
@@ -87,6 +88,7 @@ MessageEditor::MessageEditor(MultiDataModel *dataModel, QMainWindow *parent)
m_dataModel(dataModel),
m_currentModel(-1),
m_currentNumerus(-1),
+ m_lengthVariants(false),
m_undoAvail(false),
m_redoAvail(false),
m_cutAvail(false),
@@ -120,6 +122,9 @@ MessageEditor::MessageEditor(MultiDataModel *dataModel, QMainWindow *parent)
connect(m_dataModel, SIGNAL(languageChanged(int)),
SLOT(setTargetLanguage(int)));
+ m_tabOrderTimer.setSingleShot(true);
+ connect(&m_tabOrderTimer, SIGNAL(timeout()), SLOT(reallyFixTabOrder()));
+
clipboardChanged();
setWhatsThis(tr("This whole panel allows you to view and edit "
@@ -223,6 +228,7 @@ void MessageEditor::messageModelAppended()
SLOT(emitTranslatorCommentChanged(QTextEdit *)));
connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit *)), SLOT(resetHoverSelection()));
connect(ed.transCommentText, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection()));
+ fixTabOrder();
QBoxLayout *box = new QVBoxLayout(ed.container);
box->setMargin(5);
box->addWidget(ed.transCommentText);
@@ -268,18 +274,16 @@ void MessageEditor::messageModelDeleted(int model)
void MessageEditor::addPluralForm(int model, const QString &label, bool writable)
{
- FormWidget *transEditor = new FormWidget(label, true);
- QFont font;
- font.setPointSize(static_cast<int>(m_editors[model].fontSize));
- transEditor->getEditor()->setFont(font);
+ FormMultiWidget *transEditor = new FormMultiWidget(label);
+ connect(transEditor, SIGNAL(editorCreated(QTextEdit *)), SLOT(editorCreated(QTextEdit *)));
transEditor->setEditingEnabled(writable);
transEditor->setHideWhenEmpty(!writable);
if (!m_editors[model].transTexts.isEmpty())
transEditor->setVisible(false);
+ transEditor->setMultiEnabled(m_lengthVariants);
static_cast<QBoxLayout *>(m_editors[model].container->layout())->insertWidget(
m_editors[model].transTexts.count(), transEditor);
- transEditor->getEditor()->installEventFilter(this);
connect(transEditor, SIGNAL(selectionChanged(QTextEdit *)),
SLOT(selectionChanged(QTextEdit *)));
connect(transEditor, SIGNAL(textChanged(QTextEdit *)),
@@ -290,6 +294,44 @@ void MessageEditor::addPluralForm(int model, const QString &label, bool writable
m_editors[model].transTexts << transEditor;
}
+void MessageEditor::editorCreated(QTextEdit *te)
+{
+ FormMultiWidget *snd = static_cast<FormMultiWidget *>(sender());
+ for (int model = 0; ; ++model) {
+ MessageEditorData med = m_editors.at(model);
+ if (med.transTexts.contains(snd)) {
+ QFont font;
+ font.setPointSize(static_cast<int>(med.fontSize));
+ te->setFont(font);
+
+ te->installEventFilter(this);
+
+ fixTabOrder();
+ return;
+ }
+ }
+}
+
+void MessageEditor::fixTabOrder()
+{
+ m_tabOrderTimer.start(0);
+}
+
+void MessageEditor::reallyFixTabOrder()
+{
+ QWidget *prev = this;
+ foreach (const MessageEditorData &med, m_editors) {
+ foreach (FormMultiWidget *fmw, med.transTexts)
+ foreach (QTextEdit *te, fmw->getEditors()) {
+ setTabOrder(prev, te);
+ prev = te;
+ }
+ QTextEdit *te = med.transCommentText->getEditor();
+ setTabOrder(prev, te);
+ prev = te;
+ }
+}
+
/*! internal
Returns all translations for an item.
The number of translations is dependent on if we have a plural form or not.
@@ -345,11 +387,12 @@ void MessageEditor::activeModelAndNumerus(int *model, int *numerus) const
{
for (int j = 0; j < m_editors.count(); ++j) {
for (int i = 0; i < m_editors[j].transTexts.count(); ++i)
- if (m_focusWidget == m_editors[j].transTexts[i]->getEditor()) {
- *model = j;
- *numerus = i;
- return;
- }
+ foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors())
+ if (m_focusWidget == te) {
+ *model = j;
+ *numerus = i;
+ return;
+ }
if (m_focusWidget == m_editors[j].transCommentText->getEditor()) {
*model = j;
*numerus = -1;
@@ -364,7 +407,10 @@ QTextEdit *MessageEditor::activeTranslation() const
{
if (m_currentNumerus < 0)
return 0;
- return m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditor();
+ foreach (QTextEdit *te, m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditors())
+ if (te->hasFocus())
+ return te;
+ return 0; // This cannot happen
}
QTextEdit *MessageEditor::activeOr1stTranslation() const
@@ -372,11 +418,11 @@ QTextEdit *MessageEditor::activeOr1stTranslation() const
if (m_currentNumerus < 0) {
for (int i = 0; i < m_editors.size(); ++i)
if (m_editors[i].container->isVisible()
- && !m_editors[i].transTexts[0]->getEditor()->isReadOnly())
- return m_editors[i].transTexts[0]->getEditor();
+ && !m_editors[i].transTexts.first()->getEditors().first()->isReadOnly())
+ return m_editors[i].transTexts.first()->getEditors().first();
return 0;
}
- return m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditor();
+ return activeTranslation();
}
QTextEdit *MessageEditor::activeTransComment() const
@@ -404,25 +450,14 @@ void MessageEditor::setTargetLanguage(int model)
{
const QStringList &numerusForms = m_dataModel->model(model)->numerusForms();
const QString &langLocalized = m_dataModel->model(model)->localizedLanguage();
- bool added = false;
for (int i = 0; i < numerusForms.count(); ++i) {
const QString &label = tr("%1 translation (%2)").arg(langLocalized, numerusForms[i]);
if (!i)
m_editors[model].firstForm = label;
- if (i >= m_editors[model].transTexts.count()) {
+ if (i >= m_editors[model].transTexts.count())
addPluralForm(model, label, m_dataModel->isModelWritable(model));
- QWidget *prev;
- if (i > 0)
- prev = m_editors[model].transTexts[i - 1]->getEditor();
- else if (model)
- prev = m_editors[model - 1].transCommentText->getEditor();
- else
- prev = this;
- setTabOrder(prev, m_editors[model].transTexts[i]->getEditor());
- added = true;
- } else {
+ else
m_editors[model].transTexts[i]->setLabel(label);
- }
m_editors[model].transTexts[i]->setVisible(!i || m_editors[model].pluralEditMode);
m_editors[model].transTexts[i]->setWhatsThis(
tr("This is where you can enter or modify"
@@ -432,16 +467,15 @@ void MessageEditor::setTargetLanguage(int model)
delete m_editors[model].transTexts.takeLast();
m_editors[model].invariantForm = tr("%1 translation").arg(langLocalized);
m_editors[model].transCommentText->setLabel(tr("%1 translator comments").arg(langLocalized));
- if (added)
- setTabOrder(m_editors[model].transTexts.last()->getEditor(), m_editors[model].transCommentText->getEditor());
}
MessageEditorData *MessageEditor::modelForWidget(const QObject *o)
{
for (int j = 0; j < m_editors.count(); ++j) {
for (int i = 0; i < m_editors[j].transTexts.count(); ++i)
- if (m_editors[j].transTexts[i]->getEditor() == o)
- return &m_editors[j];
+ foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors())
+ if (te == o)
+ return &m_editors[j];
if (m_editors[j].transCommentText->getEditor() == o)
return &m_editors[j];
}
@@ -453,7 +487,8 @@ static bool applyFont(MessageEditorData *med)
QFont font;
font.setPointSize(static_cast<int>(med->fontSize));
for (int i = 0; i < med->transTexts.count(); ++i)
- med->transTexts[i]->getEditor()->setFont(font);
+ foreach (QTextEdit *te, med->transTexts[i]->getEditors())
+ te->setFont(font);
med->transCommentText->getEditor()->setFont(font);
return true;
}
@@ -556,7 +591,7 @@ void MessageEditor::showNothing()
m_commentText->clearTranslation();
for (int j = 0; j < m_editors.count(); ++j) {
setEditingEnabled(j, false);
- foreach (FormWidget *widget, m_editors[j].transTexts)
+ foreach (FormMultiWidget *widget, m_editors[j].transTexts)
widget->clearTranslation();
m_editors[j].transCommentText->clearTranslation();
}
@@ -643,7 +678,7 @@ void MessageEditor::setTranslation(int model, const QString &translation, int nu
MessageEditorData &ed = m_editors[model];
if (numerus >= ed.transTexts.count())
numerus = 0;
- FormWidget *transForm = ed.transTexts[numerus];
+ FormMultiWidget *transForm = ed.transTexts[numerus];
transForm->setTranslation(translation, false);
updateBeginFromSource();
@@ -658,8 +693,8 @@ void MessageEditor::setTranslation(int latestModel, const QString &translation)
latestModel = m_currentModel;
numerus = m_currentNumerus;
}
- FormWidget *transForm = m_editors[latestModel].transTexts[numerus];
- transForm->getEditor()->setFocus();
+ FormMultiWidget *transForm = m_editors[latestModel].transTexts[numerus];
+ transForm->getEditors().first()->setFocus();
transForm->setTranslation(translation, true);
updateBeginFromSource();
@@ -668,13 +703,21 @@ void MessageEditor::setTranslation(int latestModel, const QString &translation)
void MessageEditor::setEditingEnabled(int model, bool enabled)
{
MessageEditorData &ed = m_editors[model];
- foreach (FormWidget *widget, ed.transTexts)
+ foreach (FormMultiWidget *widget, ed.transTexts)
widget->setEditingEnabled(enabled);
ed.transCommentText->setEditingEnabled(enabled);
updateCanPaste();
}
+void MessageEditor::setLenghtVariants(bool on)
+{
+ m_lengthVariants = on;
+ foreach (const MessageEditorData &ed, m_editors)
+ foreach (FormMultiWidget *widget, ed.transTexts)
+ widget->setMultiEnabled(on);
+}
+
void MessageEditor::undo()
{
activeEditor()->document()->undo();
@@ -813,12 +856,13 @@ void MessageEditor::setEditorFocus(int model)
resetSelection();
m_currentNumerus = -1;
m_currentModel = -1;
+ m_focusWidget = 0;
emit activeModelChanged(activeModel());
updateBeginFromSource();
updateUndoRedo();
updateCanPaste();
} else {
- m_editors[model].transTexts[0]->getEditor()->setFocus();
+ m_editors[model].transTexts.first()->getEditors().first()->setFocus();
}
}
}
@@ -829,7 +873,7 @@ bool MessageEditor::focusNextUnfinished(int start)
if (m_dataModel->isModelWritable(j))
if (MessageItem *item = m_dataModel->messageItem(m_currentIndex, j))
if (item->type() == TranslatorMessage::Unfinished) {
- m_editors[j].transTexts[0]->getEditor()->setFocus();
+ m_editors[j].transTexts.first()->getEditors().first()->setFocus();
return true;
}
return false;
diff --git a/tools/linguist/linguist/messageeditor.h b/tools/linguist/linguist/messageeditor.h
index 95bcd86..4106036 100644
--- a/tools/linguist/linguist/messageeditor.h
+++ b/tools/linguist/linguist/messageeditor.h
@@ -45,6 +45,7 @@
#include "messagemodel.h"
#include <QtCore/QLocale>
+#include <QtCore/QTimer>
#include <QtGui/QFrame>
#include <QtGui/QScrollArea>
@@ -58,11 +59,12 @@ class QTextEdit;
class MessageEditor;
class FormatTextEdit;
class FormWidget;
+class FormMultiWidget;
struct MessageEditorData {
QWidget *container;
FormWidget *transCommentText;
- QList<FormWidget*> transTexts;
+ QList<FormMultiWidget *> transTexts;
QString invariantForm;
QString firstForm;
float fontSize;
@@ -108,8 +110,10 @@ public slots:
void beginFromSource();
void setEditorFocus();
void setTranslation(int latestModel, const QString &translation);
+ void setLenghtVariants(bool on);
private slots:
+ void editorCreated(QTextEdit *);
void selectionChanged(QTextEdit *);
void resetHoverSelection();
void emitTranslationChanged(QTextEdit *);
@@ -120,6 +124,7 @@ private slots:
void messageModelDeleted(int model);
void allModelsDeleted();
void setTargetLanguage(int model);
+ void reallyFixTabOrder();
private:
void setupEditorPage();
@@ -141,6 +146,7 @@ private:
void updateUndoRedo();
void updateCanCutCopy();
void addPluralForm(int model, const QString &label, bool writable);
+ void fixTabOrder();
QPalette paletteForModel(int model) const;
MultiDataModel *m_dataModel;
@@ -149,6 +155,8 @@ private:
int m_currentModel;
int m_currentNumerus;
+ bool m_lengthVariants;
+
bool m_undoAvail;
bool m_redoAvail;
bool m_cutAvail;
@@ -163,6 +171,8 @@ private:
FormWidget *m_pluralSource;
FormWidget *m_commentText;
QList<MessageEditorData> m_editors;
+
+ QTimer m_tabOrderTimer;
};
QT_END_NAMESPACE
diff --git a/tools/linguist/linguist/messageeditorwidgets.cpp b/tools/linguist/linguist/messageeditorwidgets.cpp
index 2ac426d..f8e2dc2 100644
--- a/tools/linguist/linguist/messageeditorwidgets.cpp
+++ b/tools/linguist/linguist/messageeditorwidgets.cpp
@@ -42,6 +42,8 @@
#include "messageeditorwidgets.h"
#include "messagehighlighter.h"
+#include <translator.h>
+
#include <QAbstractTextDocumentLayout>
#include <QAction>
#include <QApplication>
@@ -49,10 +51,12 @@
#include <QDebug>
#include <QLayout>
#include <QMenu>
+#include <QMessageBox>
#include <QPainter>
#include <QScrollArea>
#include <QTextBlock>
#include <QTextDocumentFragment>
+#include <QToolButton>
#include <QVBoxLayout>
QT_BEGIN_NAMESPACE
@@ -182,14 +186,14 @@ FormWidget::FormWidget(const QString &label, bool isEditable, QWidget *parent)
connect(m_editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged()));
}
-void FormWidget::slotSelectionChanged()
+void FormWidget::slotTextChanged()
{
- emit selectionChanged(m_editor);
+ emit textChanged(m_editor);
}
-void FormWidget::slotTextChanged()
+void FormWidget::slotSelectionChanged()
{
- emit textChanged(m_editor);
+ emit selectionChanged(m_editor);
}
void FormWidget::setTranslation(const QString &text, bool userAction)
@@ -207,4 +211,240 @@ void FormWidget::setEditingEnabled(bool enable)
}
+class ButtonWrapper : public QWidget
+{
+ // no Q_OBJECT: no need to, and don't want the useless moc file
+
+public:
+ ButtonWrapper(QWidget *wrapee, QWidget *relator) : m_wrapee(wrapee)
+ {
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
+ QBoxLayout *box = new QVBoxLayout;
+ box->setMargin(0);
+ setLayout(box);
+ box->addWidget(wrapee, 0, Qt::AlignBottom);
+ if (relator)
+ relator->installEventFilter(this);
+ }
+
+protected:
+ virtual bool eventFilter(QObject *object, QEvent *event)
+ {
+ if (event->type() == QEvent::Resize) {
+ QWidget *relator = static_cast<QWidget *>(object);
+ setFixedHeight((relator->height() + layout()->spacing() + m_wrapee->height()) / 2);
+ }
+ return false;
+ }
+
+private:
+ QWidget *m_wrapee;
+};
+
+FormMultiWidget::FormMultiWidget(const QString &label, QWidget *parent)
+ : QWidget(parent),
+ m_hideWhenEmpty(false),
+ m_multiEnabled(false),
+ m_plusIcon(QIcon(QLatin1String(":/images/plus.png"))), // make static
+ m_minusIcon(QIcon(QLatin1String(":/images/minus.png")))
+{
+ m_label = new QLabel(this);
+ m_label->setText(label);
+
+ m_plusButtons.append(
+ new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), 0));
+}
+
+QAbstractButton *FormMultiWidget::makeButton(const QIcon &icon, const char *slot)
+{
+ QAbstractButton *btn = new QToolButton(this);
+ btn->setIcon(icon);
+ btn->setFixedSize(icon.availableSizes().first() /* + something */);
+ btn->setFocusPolicy(Qt::NoFocus);
+ connect(btn, SIGNAL(clicked()), slot);
+ return btn;
+}
+
+void FormMultiWidget::addEditor(int idx)
+{
+ FormatTextEdit *editor = new FormatTextEdit(this);
+ m_editors.insert(idx, editor);
+
+ m_minusButtons.insert(idx, makeButton(m_minusIcon, SLOT(minusButtonClicked())));
+ m_plusButtons.insert(idx + 1,
+ new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), editor));
+
+ connect(editor, SIGNAL(textChanged()), SLOT(slotTextChanged()));
+ connect(editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
+ connect(editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged()));
+ editor->installEventFilter(this);
+
+ emit editorCreated(editor);
+}
+
+bool FormMultiWidget::eventFilter(QObject *watched, QEvent *event)
+{
+ int i = 0;
+ while (m_editors.at(i) != watched)
+ if (++i >= m_editors.count()) // Happens when deleting an editor
+ return false;
+ if (event->type() == QEvent::FocusOut) {
+ m_minusButtons.at(i)->setToolTip(QString());
+ m_plusButtons.at(i)->setToolTip(QString());
+ m_plusButtons.at(i + 1)->setToolTip(QString());
+ } else if (event->type() == QEvent::FocusIn) {
+ m_minusButtons.at(i)->setToolTip(/*: translate, but don't change */ tr("Alt+Delete"));
+ m_plusButtons.at(i)->setToolTip(/*: translate, but don't change */ tr("Shift+Alt+Insert"));
+ m_plusButtons.at(i + 1)->setToolTip(/*: translate, but don't change */ tr("Alt+Insert"));
+ } else if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (ke->modifiers() & Qt::AltModifier) {
+ if (ke->key() == Qt::Key_Delete) {
+ deleteEditor(i);
+ return true;
+ } else if (ke->key() == Qt::Key_Insert) {
+ if (!(ke->modifiers() & Qt::ShiftModifier))
+ ++i;
+ insertEditor(i);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void FormMultiWidget::updateLayout()
+{
+ delete layout();
+
+ QGridLayout *layout = new QGridLayout;
+ layout->setMargin(0);
+ setLayout(layout);
+
+ bool variants = m_multiEnabled && m_label->isEnabled();
+
+ layout->addWidget(m_label, 0, 0, 1, variants ? 3 : 1);
+
+ for (int i = 0; i < m_plusButtons.count(); ++i) {
+ if (variants)
+ layout->addWidget(m_plusButtons.at(i), 1 + i * 2, 0, 2, 1, Qt::AlignTop);
+ m_plusButtons.at(i)->setVisible(variants);
+ }
+ for (int j = 0; j < m_minusButtons.count(); ++j) {
+ if (variants)
+ layout->addWidget(m_minusButtons.at(j), 2 + j * 2, 2, 2, 1, Qt::AlignVCenter);
+ m_minusButtons.at(j)->setVisible(variants);
+ }
+ for (int k = 0; k < m_editors.count(); ++k)
+ layout->addWidget(m_editors.at(k), 2 + k * 2, variants ? 1 : 0, 2, 1, Qt::AlignVCenter);
+
+ updateGeometry();
+}
+
+void FormMultiWidget::slotTextChanged()
+{
+ emit textChanged(static_cast<QTextEdit *>(sender()));
+}
+
+void FormMultiWidget::slotSelectionChanged()
+{
+ emit selectionChanged(static_cast<QTextEdit *>(sender()));
+}
+
+void FormMultiWidget::setTranslation(const QString &text, bool userAction)
+{
+ QStringList texts = text.split(QChar(Translator::BinaryVariantSeparator), QString::KeepEmptyParts);
+
+ while (m_editors.count() > texts.count()) {
+ delete m_minusButtons.takeLast();
+ delete m_plusButtons.takeLast();
+ delete m_editors.takeLast();
+ }
+ while (m_editors.count() < texts.count())
+ addEditor(m_editors.count());
+ updateLayout();
+
+ for (int i = 0; i < texts.count(); ++i)
+ // XXX this will emit n textChanged signals
+ m_editors.at(i)->setPlainText(texts.at(i), userAction);
+
+ if (m_hideWhenEmpty)
+ setHidden(text.isEmpty());
+}
+
+QString FormMultiWidget::getTranslation() const
+{
+ QString ret;
+ for (int i = 0; i < m_editors.count(); ++i) {
+ if (i)
+ ret += QChar(Translator::BinaryVariantSeparator);
+ ret += m_editors.at(i)->toPlainText();
+ }
+ return ret;
+}
+
+void FormMultiWidget::setEditingEnabled(bool enable)
+{
+ // Use read-only state so that the text can still be copied
+ for (int i = 0; i < m_editors.count(); ++i)
+ m_editors.at(i)->setReadOnly(!enable);
+ m_label->setEnabled(enable);
+ if (m_multiEnabled)
+ updateLayout();
+}
+
+void FormMultiWidget::setMultiEnabled(bool enable)
+{
+ m_multiEnabled = enable;
+ if (m_label->isEnabled())
+ updateLayout();
+}
+
+void FormMultiWidget::minusButtonClicked()
+{
+ int i = 0;
+ while (m_minusButtons.at(i) != sender())
+ ++i;
+ deleteEditor(i);
+}
+
+void FormMultiWidget::plusButtonClicked()
+{
+ QWidget *btn = static_cast<QAbstractButton *>(sender())->parentWidget();
+ int i = 0;
+ while (m_plusButtons.at(i) != btn)
+ ++i;
+ insertEditor(i);
+}
+
+void FormMultiWidget::deleteEditor(int idx)
+{
+ if (m_editors.count() == 1) {
+ // Don't just clear(), so the undo history is not lost
+ QTextCursor c = m_editors.first()->textCursor();
+ c.select(QTextCursor::Document);
+ c.removeSelectedText();
+ } else {
+ if (!m_editors.at(idx)->toPlainText().isEmpty()) {
+ if (QMessageBox::question(topLevelWidget(), tr("Confirmation - Qt Linguist"),
+ tr("Delete non-empty length variant?"),
+ QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)
+ != QMessageBox::Yes)
+ return;
+ }
+ delete m_editors.takeAt(idx);
+ delete m_minusButtons.takeAt(idx);
+ delete m_plusButtons.takeAt(idx + 1);
+ updateLayout();
+ emit textChanged(m_editors.at((m_editors.count() == idx) ? idx - 1 : idx));
+ }
+}
+
+void FormMultiWidget::insertEditor(int idx)
+{
+ addEditor(idx);
+ updateLayout();
+ emit textChanged(m_editors.at(idx));
+}
+
QT_END_NAMESPACE
diff --git a/tools/linguist/linguist/messageeditorwidgets.h b/tools/linguist/linguist/messageeditorwidgets.h
index bf3dcb0..c0b445c 100644
--- a/tools/linguist/linguist/messageeditorwidgets.h
+++ b/tools/linguist/linguist/messageeditorwidgets.h
@@ -42,6 +42,7 @@
#ifndef MESSAGEEDITORWIDGETS_H
#define MESSAGEEDITORWIDGETS_H
+#include <QIcon>
#include <QImage>
#include <QLabel>
#include <QMap>
@@ -51,6 +52,7 @@
QT_BEGIN_NAMESPACE
+class QAbstractButton;
class QAction;
class QContextMenuEvent;
class QKeyEvent;
@@ -129,6 +131,54 @@ private:
bool m_hideWhenEmpty;
};
+/*
+ Displays text fields & associated label
+*/
+class FormMultiWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ FormMultiWidget(const QString &label, QWidget *parent = 0);
+ void setLabel(const QString &label) { m_label->setText(label); }
+ void setTranslation(const QString &text, bool userAction = false);
+ void clearTranslation() { setTranslation(QString(), false); }
+ QString getTranslation() const;
+ void setEditingEnabled(bool enable);
+ void setMultiEnabled(bool enable);
+ void setHideWhenEmpty(bool optional) { m_hideWhenEmpty = optional; }
+ const QList<FormatTextEdit *> &getEditors() const { return m_editors; }
+
+signals:
+ void editorCreated(QTextEdit *);
+ void textChanged(QTextEdit *);
+ void selectionChanged(QTextEdit *);
+ void cursorPositionChanged();
+
+protected:
+ bool eventFilter(QObject *watched, QEvent *event);
+
+private slots:
+ void slotTextChanged();
+ void slotSelectionChanged();
+ void minusButtonClicked();
+ void plusButtonClicked();
+
+private:
+ void addEditor(int idx);
+ void updateLayout();
+ QAbstractButton *makeButton(const QIcon &icon, const char *slot);
+ void insertEditor(int idx);
+ void deleteEditor(int idx);
+
+ QLabel *m_label;
+ QList<FormatTextEdit *> m_editors;
+ QList<QWidget *> m_plusButtons;
+ QList<QAbstractButton *> m_minusButtons;
+ bool m_hideWhenEmpty;
+ bool m_multiEnabled;
+ QIcon m_plusIcon, m_minusIcon;
+};
+
QT_END_NAMESPACE
#endif // MESSAGEEDITORWIDGETS_H
diff --git a/tools/linguist/lrelease/lrelease.1 b/tools/linguist/lrelease/lrelease.1
index 9e77504..8dd14b2 100644
--- a/tools/linguist/lrelease/lrelease.1
+++ b/tools/linguist/lrelease/lrelease.1
@@ -51,10 +51,10 @@ This page documents the
tool for the Qt GUI toolkit.
.B Lrelease
reads a qmake/tmake project file (.pro file) and converts the
-translation files (.ts files) specified in it into Qt message files
-(.qm files) used by the application to translate.
+translation files (TS files) specified in it into Qt message files
+(QM files) used by the application to translate.
.PP
-The .qm file format is a compact binary format that provides
+The QM file format is a compact binary format that provides
extremely fast lookups for translations and that is used by Qt.
.SH OPTIONS
.TP
@@ -62,7 +62,7 @@ extremely fast lookups for translations and that is used by Qt.
Display the usage and exit.
.TP
.I "-compress"
-Compress the .qm files.
+Compress the QM files.
.TP
.I "-nounfinished"
Do not include unfinished translations.
@@ -72,7 +72,7 @@ If the translated text is the same as
the source text, do not include the message.
.TP
.I "-silent"
-Don't explain what is being done.
+Do not explain what is being done.
.TP
.I "-version"
Display the version of
@@ -105,7 +105,7 @@ generated from gnomovision_dk.ts, gnomovision_fi.ts,
gnomovision_no.ts and gnomovision_se.ts, respectively.
.PP
.B Lrelease
-can also be invoked with a list of .ts files to convert:
+can also be invoked with a list of TS files to convert:
.PP
.in +4
.nf
diff --git a/tools/linguist/lrelease/main.cpp b/tools/linguist/lrelease/main.cpp
index 86b7866..aeed1f2 100644
--- a/tools/linguist/lrelease/main.cpp
+++ b/tools/linguist/lrelease/main.cpp
@@ -66,19 +66,21 @@ static void printUsage()
" lrelease [options] project-file\n"
" lrelease [options] ts-files [-qm qm-file]\n\n"
"lrelease is part of Qt's Linguist tool chain. It can be used as a\n"
- "stand-alone tool to convert XML based translations files in the .ts\n"
- "format into the 'compiled' .qm format used by QTranslator objects.\n\n"
+ "stand-alone tool to convert XML-based translations files in the TS\n"
+ "format into the 'compiled' QM format used by QTranslator objects.\n\n"
"Options:\n"
" -help Display this information and exit\n"
+ " -idbased\n"
+ " Use IDs instead of source strings for message keying\n"
" -compress\n"
- " Compress the .qm files\n"
+ " Compress the QM files\n"
" -nounfinished\n"
" Do not include unfinished translations\n"
" -removeidentical\n"
" If the translated text is the same as\n"
" the source text, do not include the message\n"
" -silent\n"
- " Don't explain what is being done\n"
+ " Do not explain what is being done\n"
" -version\n"
" Display the version of lrelease and exit\n"
));
@@ -99,7 +101,7 @@ static bool loadTsFile(Translator &tor, const QString &tsFileName, bool /* verbo
static bool releaseTranslator(Translator &tor, const QString &qmFileName,
bool verbose, bool ignoreUnfinished,
- bool removeIdentical, TranslatorSaveMode mode)
+ bool removeIdentical, bool idBased, TranslatorSaveMode mode)
{
Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose);
@@ -121,6 +123,7 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName,
ConversionData cd;
cd.m_verbose = verbose;
cd.m_ignoreUnfinished = ignoreUnfinished;
+ cd.m_idBased = idBased;
cd.m_saveMode = mode;
bool ok = tor.release(&file, cd);
file.close();
@@ -136,7 +139,7 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName,
}
static bool releaseTsFile(const QString& tsFileName, bool verbose,
- bool ignoreUnfinished, bool removeIdentical, TranslatorSaveMode mode)
+ bool ignoreUnfinished, bool removeIdentical, bool idBased, TranslatorSaveMode mode)
{
Translator tor;
if (!loadTsFile(tor, tsFileName, verbose))
@@ -151,7 +154,7 @@ static bool releaseTsFile(const QString& tsFileName, bool verbose,
}
qmFileName += QLatin1String(".qm");
- return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, mode);
+ return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, idBased, mode);
}
int main(int argc, char **argv)
@@ -164,6 +167,7 @@ int main(int argc, char **argv)
bool verbose = true; // the default is true starting with Qt 4.2
bool ignoreUnfinished = false;
+ bool idBased = false;
// the default mode is SaveEverything starting with Qt 4.2
TranslatorSaveMode mode = SaveEverything;
bool removeIdentical = false;
@@ -175,6 +179,9 @@ int main(int argc, char **argv)
if (args[i] == QLatin1String("-compress")) {
mode = SaveStripped;
continue;
+ } else if (args[i] == QLatin1String("-idbased")) {
+ idBased = true;
+ continue;
} else if (args[i] == QLatin1String("-nocompress")) {
mode = SaveEverything;
continue;
@@ -232,18 +239,18 @@ int main(int argc, char **argv)
qPrintable(args[i]));
} else {
foreach (const QString &trans, translations)
- if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, mode))
+ if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, idBased, mode))
return 1;
}
} else {
qWarning("error: lrelease encountered project file functionality that is currently not supported.\n"
- "You might want to consider using .ts files as input instead of a project file.\n"
+ "You might want to consider using TS files as input instead of a project file.\n"
"Try the following syntax:\n"
" lrelease [options] ts-files [-qm qm-file]\n");
}
} else {
if (outputFile.isEmpty()) {
- if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, mode))
+ if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, idBased, mode))
return 1;
} else {
if (!loadTsFile(tor, args[i], verbose))
@@ -254,7 +261,7 @@ int main(int argc, char **argv)
if (!outputFile.isEmpty())
return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished,
- removeIdentical, mode) ? 0 : 1;
+ removeIdentical, idBased, mode) ? 0 : 1;
return 0;
}
diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp
index eb743c2..58e094b 100644
--- a/tools/linguist/lupdate/cpp.cpp
+++ b/tools/linguist/lupdate/cpp.cpp
@@ -58,10 +58,6 @@ QT_BEGIN_NAMESPACE
static const char MagicComment[] = "TRANSLATOR ";
-static const int yyIdentMaxLen = 128;
-static const int yyCommentMaxLen = 65536;
-static const int yyStringMaxLen = 65536;
-
#define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
#define STRING(s) static QString str##s(QLatin1String(STRINGIFY(s)))
@@ -180,7 +176,8 @@ private:
QString transcode(const QString &str, bool utf8);
void recordMessage(
int line, const QString &context, const QString &text, const QString &comment,
- const QString &extracomment, bool utf8, bool plural);
+ const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra,
+ bool utf8, bool plural);
void processInclude(const QString &file, ConversionData &cd,
QSet<QString> &inclusions);
@@ -202,7 +199,7 @@ private:
enum {
Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return,
- Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8,
+ Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid,
Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS,
Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon,
Tok_Equals,
@@ -556,6 +553,8 @@ uint CppParser::getToken()
return Tok_Q_DECLARE_TR_FUNCTIONS;
if (yyIdent == QLatin1String("QT_TR_NOOP"))
return Tok_tr;
+ if (yyIdent == QLatin1String("QT_TRID_NOOP"))
+ return Tok_trid;
if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP"))
return Tok_translate;
if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3"))
@@ -591,6 +590,10 @@ uint CppParser::getToken()
if (yyIdent == QLatin1String("namespace"))
return Tok_namespace;
break;
+ case 'q':
+ if (yyIdent == QLatin1String("qtTrId"))
+ return Tok_trid;
+ break;
case 'r':
if (yyIdent == QLatin1String("return"))
return Tok_return;
@@ -667,14 +670,9 @@ uint CppParser::getToken()
yyCh = getChar();
if (yyCh == EOF || yyCh == '\n')
break;
- if (yyString.size() < yyStringMaxLen) {
- yyString.append(QLatin1Char('\\'));
- yyString.append(yyCh);
- }
- } else {
- if (yyString.size() < yyStringMaxLen)
- yyString.append(yyCh);
+ yyString.append(QLatin1Char('\\'));
}
+ yyString.append(yyCh);
yyCh = getChar();
}
@@ -1299,13 +1297,16 @@ QString CppParser::transcode(const QString &str, bool utf8)
void CppParser::recordMessage(
int line, const QString &context, const QString &text, const QString &comment,
- const QString &extracomment, bool utf8, bool plural)
+ const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra,
+ bool utf8, bool plural)
{
TranslatorMessage msg(
transcode(context, utf8), transcode(text, utf8), transcode(comment, utf8), QString(),
yyFileName, line, QStringList(),
TranslatorMessage::Unfinished, plural);
msg.setExtraComment(transcode(extracomment.simplified(), utf8));
+ msg.setId(msgid);
+ msg.setExtras(extra);
if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit())
msg.setUtf8(true);
results->tor->append(msg);
@@ -1332,6 +1333,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
QString text;
QString comment;
QString extracomment;
+ QString msgid;
+ QString sourcetext;
+ TranslatorMessage::ExtraData extra;
QString prefix;
#ifdef DIAGNOSE_RETRANSLATABILITY
QString functionName;
@@ -1517,6 +1521,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
case Tok_trUtf8:
if (!results->tor)
goto case_default;
+ if (!sourcetext.isEmpty())
+ qWarning("%s:%d: //%% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n",
+ qPrintable(yyFileName), yyLineNo);
utf8 = (yyTok == Tok_trUtf8);
line = yyLineNo;
yyTok = getToken();
@@ -1604,14 +1611,19 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
prefix.clear();
}
- recordMessage(line, context, text, comment, extracomment, utf8, plural);
+ recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural);
}
extracomment.clear();
+ msgid.clear();
+ extra.clear();
break;
case Tok_translateUtf8:
case Tok_translate:
if (!results->tor)
goto case_default;
+ if (!sourcetext.isEmpty())
+ qWarning("%s:%d: //%% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n",
+ qPrintable(yyFileName), yyLineNo);
utf8 = (yyTok == Tok_translateUtf8);
line = yyLineNo;
yyTok = getToken();
@@ -1655,9 +1667,32 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
break;
}
}
- recordMessage(line, context, text, comment, extracomment, utf8, plural);
+ recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural);
}
extracomment.clear();
+ msgid.clear();
+ extra.clear();
+ break;
+ case Tok_trid:
+ if (!results->tor)
+ goto case_default;
+ if (!sourcetext.isEmpty()) {
+ if (!msgid.isEmpty())
+ qWarning("%s:%d: //= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n",
+ qPrintable(yyFileName), yyLineNo);
+ //utf8 = false; // Maybe use //%% or something like that
+ line = yyLineNo;
+ yyTok = getToken();
+ if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) {
+ bool plural = match(Tok_Comma);
+ recordMessage(line, QString(), sourcetext, QString(), extracomment,
+ msgid, extra, false, plural);
+ }
+ sourcetext.clear();
+ }
+ extracomment.clear();
+ msgid.clear();
+ extra.clear();
break;
case Tok_Q_DECLARE_TR_FUNCTIONS:
case Tok_Q_OBJECT:
@@ -1679,6 +1714,49 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
if (yyComment.startsWith(QLatin1Char(':'))) {
yyComment.remove(0, 1);
extracomment.append(yyComment);
+ } else if (yyComment.startsWith(QLatin1Char('='))) {
+ yyComment.remove(0, 1);
+ msgid = yyComment.simplified();
+ } else if (yyComment.startsWith(QLatin1Char('~'))) {
+ yyComment.remove(0, 1);
+ yyComment = yyComment.trimmed();
+ int k = yyComment.indexOf(QLatin1Char(' '));
+ if (k > -1)
+ extra.insert(yyComment.left(k), yyComment.mid(k + 1).trimmed());
+ } else if (yyComment.startsWith(QLatin1Char('%'))) {
+ int p = 1, c;
+ forever {
+ if (p >= yyComment.length())
+ break;
+ c = yyComment.unicode()[p++].unicode();
+ if (isspace(c))
+ continue;
+ if (c != '"') {
+ qWarning("%s:%d: Unexpected character in meta string\n",
+ qPrintable(yyFileName), yyLineNo);
+ break;
+ }
+ forever {
+ if (p >= yyComment.length()) {
+ whoops:
+ qWarning("%s:%d: Unterminated meta string\n",
+ qPrintable(yyFileName), yyLineNo);
+ break;
+ }
+ c = yyComment.unicode()[p++].unicode();
+ if (c == '"')
+ break;
+ if (c == '\\') {
+ if (p >= yyComment.length())
+ goto whoops;
+ c = yyComment.unicode()[p++].unicode();
+ if (c == '\n')
+ goto whoops;
+ sourcetext.append(QLatin1Char('\\'));
+ }
+ sourcetext.append(c);
+ }
+ }
} else {
comment = yyComment.simplified();
if (comment.startsWith(QLatin1String(MagicComment))) {
@@ -1689,7 +1767,11 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
} else {
context = comment.left(k);
comment.remove(0, k + 1);
- recordMessage(yyLineNo, context, QString(), comment, extracomment, false, false);
+ recordMessage(yyLineNo, context, QString(), comment, extracomment,
+ QString(), TranslatorMessage::ExtraData(), false, false);
+ extracomment.clear();
+ results->tor->setExtras(extra);
+ extra.clear();
}
}
}
@@ -1739,6 +1821,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
prospectiveContext.clear();
prefix.clear();
extracomment.clear();
+ msgid.clear();
+ extra.clear();
yyTokColonSeen = false;
yyTok = getToken();
break;
@@ -1799,7 +1883,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat
? translator.codecName() : cd.m_codecForSource;
QTextCodec *codec = QTextCodec::codecForName(codecName);
- foreach (const QString filename, filenames) {
+ foreach (const QString &filename, filenames) {
if (CppFiles::getResults(filename) || CppFiles::isBlacklisted(filename))
continue;
diff --git a/tools/linguist/lupdate/lupdate.1 b/tools/linguist/lupdate/lupdate.1
index 68958b9..b37e7b3 100644
--- a/tools/linguist/lupdate/lupdate.1
+++ b/tools/linguist/lupdate/lupdate.1
@@ -52,12 +52,12 @@ tool for the Qt GUI toolkit.
.B Lupdate
reads a qmake/tmake project file (.pro file), finds the translatable
strings in the specified source, header and interface files, and
-updates the translation files (.ts files) specified in it. The
+updates the translation files (TS files) specified in it. The
translation files are given to the translator who uses
.B Qt Linguist
to read the files and insert the translations.
.PP
-The .ts file format is a simple human-readable XML format that can be
+The TS file format is a simple human-readable XML format that can be
used with version control systems if required.
.PP
.SH OPTIONS
@@ -74,7 +74,7 @@ Default: 'ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx'.
Display the usage and exit.
.TP
.I "-locations {absolute|relative|none}"
-Specify/override how source code references are saved in ts files.
+Specify/override how source code references are saved in TS files.
Default is absolute.
.TP
.I "-no-obsolete"
@@ -84,7 +84,7 @@ Drop all obsolete strings.
Do not recursively scan the following directories.
.TP
.I "-no-sort"
-Do not sort contexts in .ts files.
+Do not sort contexts in TS files.
.TP
.I "-pluralonly"
Only include plural form messages.
@@ -97,7 +97,7 @@ file syntax but different file suffix
Recursively scan the following directories.
.TP
.I "-silent"
-Don't explain what is being done.
+Do not explain what is being done.
.TP
.I "-source-language <language>[_<region>]"
Specify/override the language of the source strings. Defaults to
@@ -139,8 +139,8 @@ translations will be reused as far as possible, and translated
strings that have vanished from the source files are marked obsolete.
.PP
.B lupdate
-can also be invoked with a list of C++ source files, .ui files
-and .ts files:
+can also be invoked with a list of C++ source files, UI files
+and TS files:
.PP
.in +4
.nf
diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp
index 18c8932..c9250c6 100644
--- a/tools/linguist/lupdate/main.cpp
+++ b/tools/linguist/lupdate/main.cpp
@@ -103,7 +103,7 @@ static void printUsage()
" -silent\n"
" Do not explain what is being done.\n"
" -no-sort\n"
- " Do not sort contexts in .ts files.\n"
+ " Do not sort contexts in TS files.\n"
" -no-recursive\n"
" Do not recursively scan the following directories.\n"
" -recursive\n"
@@ -112,10 +112,10 @@ static void printUsage()
" Additional location to look for include files.\n"
" May be specified multiple times.\n"
" -locations {absolute|relative|none}\n"
- " Specify/override how source code references are saved in ts files.\n"
+ " Specify/override how source code references are saved in TS files.\n"
" Default is absolute.\n"
" -no-ui-lines\n"
- " Do not record line numbers in references to .ui files.\n"
+ " Do not record line numbers in references to UI files.\n"
" -disable-heuristic {sametext|similartext|number}\n"
" Disable the named merge heuristic. Can be specified multiple times.\n"
" -pro <filename>\n"
diff --git a/tools/linguist/shared/po.cpp b/tools/linguist/shared/po.cpp
index cb943be..e22aa7d 100644
--- a/tools/linguist/shared/po.cpp
+++ b/tools/linguist/shared/po.cpp
@@ -395,7 +395,10 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd)
const QString prefix = QLatin1String(isObsolete ? "#~ " : "");
while (true) {
int idx = line.indexOf(QLatin1Char(' '), prefix.length());
- item.msgStr.append(slurpEscapedString(lines, l, idx, prefix, cd));
+ QString str = slurpEscapedString(lines, l, idx, prefix, cd);
+ str.replace(QChar(Translator::TextVariantSeparator),
+ QChar(Translator::BinaryVariantSeparator));
+ item.msgStr.append(str);
if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1)))
break;
++l;
@@ -635,8 +638,11 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd)
out << poEscapedString(prefix, QLatin1String("msgid_plural"), noWrap, plural);
QStringList translations = translator.normalizedTranslations(msg, cd, &ok);
for (int i = 0; i != translations.size(); ++i) {
+ QString str = translations.at(i);
+ str.replace(QChar(Translator::BinaryVariantSeparator),
+ QChar(Translator::TextVariantSeparator));
out << poEscapedString(prefix, QString::fromLatin1("msgstr[%1]").arg(i), noWrap,
- translations.at(i));
+ str);
}
}
first = false;
diff --git a/tools/linguist/shared/profileevaluator.cpp b/tools/linguist/shared/profileevaluator.cpp
index ef59543..47c1ec2 100644
--- a/tools/linguist/shared/profileevaluator.cpp
+++ b/tools/linguist/shared/profileevaluator.cpp
@@ -1949,9 +1949,9 @@ QStringList ProFileEvaluator::Private::values(const QString &variableName,
ret = QLatin1String("Windows");
} else if (type == QLatin1String("name")) {
DWORD name_length = 1024;
- TCHAR name[1024];
+ wchar_t name[1024];
if (GetComputerName(name, &name_length))
- ret = QString::fromUtf16((ushort*)name, name_length);
+ ret = QString::fromWCharArray(name);
} else if (type == QLatin1String("version") || type == QLatin1String("version_string")) {
QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
if (type == QLatin1String("version"))
diff --git a/tools/linguist/shared/qm.cpp b/tools/linguist/shared/qm.cpp
index 323bd29..9523fde 100644
--- a/tools/linguist/shared/qm.cpp
+++ b/tools/linguist/shared/qm.cpp
@@ -173,6 +173,7 @@ public:
bool save(QIODevice *iod);
void insert(const TranslatorMessage &msg, bool forceComment);
+ void insertIdBased(const TranslatorMessage &message);
void squeeze(TranslatorSaveMode mode);
@@ -238,17 +239,13 @@ Prefix Releaser::commonPrefix(const ByteTranslatorMessage &m1, const ByteTransla
void Releaser::writeMessage(const ByteTranslatorMessage &msg, QDataStream &stream,
TranslatorSaveMode mode, Prefix prefix) const
{
- for (int i = 0; i < msg.translations().count(); ++i) {
- QString str = msg.translations().at(i);
- str.replace(QChar(Translator::DefaultVariantSeparator),
- QChar(Translator::InternalVariantSeparator));
- stream << quint8(Tag_Translation) << str;
- }
+ for (int i = 0; i < msg.translations().count(); ++i)
+ stream << quint8(Tag_Translation) << msg.translations().at(i);
if (mode == SaveEverything)
prefix = HashContextSourceTextComment;
- // lrelease produces "wrong" .qm files for QByteArrays that are .isNull().
+ // lrelease produces "wrong" QM files for QByteArrays that are .isNull().
switch (prefix) {
default:
case HashContextSourceTextComment:
@@ -440,6 +437,16 @@ void Releaser::insert(const TranslatorMessage &message, bool forceComment)
insertInternal(message, forceComment, false);
}
+void Releaser::insertIdBased(const TranslatorMessage &message)
+{
+ QStringList tlns = message.translations();
+ for (int i = 0; i < tlns.size(); ++i)
+ if (tlns.at(i).isEmpty())
+ tlns[i] = message.sourceText();
+ ByteTranslatorMessage bmsg("", originalBytes(message.id(), false), "", tlns);
+ m_messages.insert(bmsg, 0);
+}
+
void Releaser::setNumerusRules(const QByteArray &rules)
{
m_numerusRules = rules;
@@ -592,8 +599,6 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd)
str[i] = QChar((str.at(i).unicode() >> 8) +
((str.at(i).unicode() << 8) & 0xff00));
}
- str.replace(QChar(Translator::InternalVariantSeparator),
- QChar(Translator::DefaultVariantSeparator));
translations << str;
m += len;
break;
@@ -695,11 +700,17 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData
int finished = 0;
int unfinished = 0;
int untranslated = 0;
+ int missingIds = 0;
+ int droppedData = 0;
for (int i = 0; i != translator.messageCount(); ++i) {
const TranslatorMessage &msg = translator.message(i);
TranslatorMessage::Type typ = msg.type();
if (typ != TranslatorMessage::Obsolete) {
+ if (cd.m_idBased && msg.id().isEmpty()) {
+ ++missingIds;
+ continue;
+ }
if (typ == TranslatorMessage::Unfinished) {
if (msg.translation().isEmpty()) {
++untranslated;
@@ -712,19 +723,34 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData
} else {
++finished;
}
- // Drop the comment in (context, sourceText, comment),
- // unless the context is empty,
- // unless (context, sourceText, "") already exists or
- // unless we already dropped the comment of (context,
- // sourceText, comment0).
- bool forceComment =
- msg.comment().isEmpty()
- || msg.context().isEmpty()
- || translator.contains(msg.context(), msg.sourceText(), QString());
- releaser.insert(msg, forceComment);
+ if (cd.m_idBased) {
+ if (!msg.context().isEmpty() || !msg.comment().isEmpty())
+ ++droppedData;
+ releaser.insertIdBased(msg);
+ } else {
+ // Drop the comment in (context, sourceText, comment),
+ // unless the context is empty,
+ // unless (context, sourceText, "") already exists or
+ // unless we already dropped the comment of (context,
+ // sourceText, comment0).
+ bool forceComment =
+ msg.comment().isEmpty()
+ || msg.context().isEmpty()
+ || translator.contains(msg.context(), msg.sourceText(), QString());
+ releaser.insert(msg, forceComment);
+ }
}
}
+ if (missingIds)
+ cd.appendError(QCoreApplication::translate("LRelease",
+ "Dropped %n message(s) which had no ID.", 0,
+ QCoreApplication::CodecForTr, missingIds));
+ if (droppedData)
+ cd.appendError(QCoreApplication::translate("LRelease",
+ "Excess context/disambiguation dropped from %n message(s).", 0,
+ QCoreApplication::CodecForTr, droppedData));
+
releaser.squeeze(cd.m_saveMode);
bool saved = releaser.save(&dev);
if (saved && cd.isVerbose()) {
diff --git a/tools/linguist/shared/qph.cpp b/tools/linguist/shared/qph.cpp
index 40f0386..4a29e0f 100644
--- a/tools/linguist/shared/qph.cpp
+++ b/tools/linguist/shared/qph.cpp
@@ -99,6 +99,8 @@ bool QPHReader::read(Translator &translator)
else if (m_currentField == DefinitionField)
m_currentDefinition += text();
} else if (isEndElement() && name() == QLatin1String("phrase")) {
+ m_currentTarget.replace(QChar(Translator::TextVariantSeparator),
+ QChar(Translator::BinaryVariantSeparator));
TranslatorMessage msg;
msg.setSourceText(m_currentSource);
msg.setTranslation(m_currentTarget);
@@ -159,7 +161,10 @@ static bool saveQPH(const Translator &translator, QIODevice &dev, ConversionData
foreach (const TranslatorMessage &msg, translator.messages()) {
t << "<phrase>\n";
t << " <source>" << protect(msg.sourceText()) << "</source>\n";
- t << " <target>" << protect(msg.translations().join(QLatin1String("@")))
+ QString str = msg.translations().join(QLatin1String("@"));
+ str.replace(QChar(Translator::BinaryVariantSeparator),
+ QChar(Translator::TextVariantSeparator));
+ t << " <target>" << protect(str)
<< "</target>\n";
if (!msg.context().isEmpty() || !msg.comment().isEmpty())
t << " <definition>" << msg.context() << msg.comment()
diff --git a/tools/linguist/shared/translator.h b/tools/linguist/shared/translator.h
index 2651af0..fb17fd1 100644
--- a/tools/linguist/shared/translator.h
+++ b/tools/linguist/shared/translator.h
@@ -65,6 +65,7 @@ public:
m_ignoreUnfinished(false),
m_sortContexts(false),
m_noUiLines(false),
+ m_idBased(false),
m_saveMode(SaveEverything)
{}
@@ -97,6 +98,7 @@ public:
bool m_ignoreUnfinished;
bool m_sortContexts;
bool m_noUiLines;
+ bool m_idBased;
TranslatorSaveMode m_saveMode;
};
@@ -190,9 +192,9 @@ public:
static void registerFileFormat(const FileFormat &format);
static QList<FileFormat> &registeredFileFormats();
- enum VariantSeparators {
- DefaultVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D
- InternalVariantSeparator = 0x9c // unicode "STRING TERMINATOR"
+ enum {
+ TextVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D
+ BinaryVariantSeparator = 0x9c // unicode "STRING TERMINATOR"
};
private:
diff --git a/tools/linguist/shared/ts.cpp b/tools/linguist/shared/ts.cpp
index 6c95dbd..3efce15 100644
--- a/tools/linguist/shared/ts.cpp
+++ b/tools/linguist/shared/ts.cpp
@@ -197,7 +197,7 @@ QString TSReader::readTransContents()
// ignore these, just whitespace
} else if (elementStarts(strlengthvariant)) {
if (!result.isEmpty())
- result += QChar(Translator::DefaultVariantSeparator);
+ result += QChar(Translator::BinaryVariantSeparator);
result += readContents();
} else {
handleError();
@@ -514,7 +514,7 @@ static void writeExtras(QTextStream &t, const char *indent,
static void writeVariants(QTextStream &t, const char *indent, const QString &input)
{
int offset;
- if ((offset = input.indexOf(QChar(Translator::DefaultVariantSeparator))) >= 0) {
+ if ((offset = input.indexOf(QChar(Translator::BinaryVariantSeparator))) >= 0) {
t << " variants=\"yes\">";
int start = 0;
forever {
@@ -524,7 +524,7 @@ static void writeVariants(QTextStream &t, const char *indent, const QString &inp
if (offset == input.length())
break;
start = offset + 1;
- offset = input.indexOf(QChar(Translator::DefaultVariantSeparator), start);
+ offset = input.indexOf(QChar(Translator::BinaryVariantSeparator), start);
if (offset < 0)
offset = input.length();
}
diff --git a/tools/linguist/shared/ts.dtd b/tools/linguist/shared/ts.dtd
index ab77f64..4d2cdeb 100644
--- a/tools/linguist/shared/ts.dtd
+++ b/tools/linguist/shared/ts.dtd
@@ -34,7 +34,7 @@
version CDATA #IMPLIED
sourcelanguage CDATA #IMPLIED
language CDATA #IMPLIED>
-<!-- The encoding to use in the .qm file by default. Default is ISO-8859-1. -->
+<!-- The encoding to use in the QM file by default. Default is ISO-8859-1. -->
<!ELEMENT defaultcodec (#PCDATA) >
<!ELEMENT context (name?, comment?, (context|message)+) >
<!ATTLIST context
@@ -54,7 +54,7 @@
<!ELEMENT message (location*, source?, oldsource?, comment?, oldcomment?, extracomment?, translatorcomment?, translation?, userdata?, extra-**) >
<!--
! If utf8 is true, the defaultcodec is overridden and the message is encoded
- ! in UTF-8 in the .qm file.
+ ! in UTF-8 in the QM file.
-->
<!ATTLIST message
id CDATA #IMPLIED
@@ -70,7 +70,7 @@
! is omitted, the "current" one is used. For the 1st location in a message,
! "current" is the filename used for the 1st location of the previous message.
! For subsequent locations, it is the filename used for the previous location.
- ! A single .ts file has either all absolute or all relative locations.
+ ! A single TS file has either all absolute or all relative locations.
-->
<!ATTLIST location
filename CDATA #IMPLIED
@@ -106,7 +106,7 @@
<!--
! The translation variants have a priority between 1 ("highest") and 9 ("lowest")
! Typically longer translations get a higher priority.
- ! If omitted, the order of appearance of the variants in the .ts files is used.
+ ! If omitted, the order of appearance of the variants in the TS files is used.
-->
<!ATTLIST lengthvariant
priority (1|2|3|4|5|6|7|8|9) #IMPLIED>
diff --git a/tools/linguist/shared/xliff.cpp b/tools/linguist/shared/xliff.cpp
index 61e4b9f..1313172 100644
--- a/tools/linguist/shared/xliff.cpp
+++ b/tools/linguist/shared/xliff.cpp
@@ -303,6 +303,8 @@ static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const
QString translation;
if (transit != transend) {
translation = *transit;
+ translation.replace(QChar(Translator::BinaryVariantSeparator),
+ QChar(Translator::TextVariantSeparator));
++transit;
puttrans = true;
}
@@ -598,8 +600,11 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN
m_sources.append(accum);
}
} else if (localName == QLatin1String("target")) {
- if (popContext(XC_restype_translation))
+ if (popContext(XC_restype_translation)) {
+ accum.replace(QChar(Translator::TextVariantSeparator),
+ QChar(Translator::BinaryVariantSeparator));
m_translations.append(accum);
+ }
} else if (localName == QLatin1String("context-group")) {
if (popContext(XC_context_group)) {
m_refs.append(TranslatorMessage::Reference(