Skip to content
Permalink
Browse files
Address various localisation issues. Fixes #1203
See also #1275
  • Loading branch information
J5lx committed May 1, 2020
1 parent 5471da3 commit f9e5e5aba48070a3a5a6f81bc165e55a3df27ad6
Show file tree
Hide file tree
Showing 19 changed files with 76 additions and 76 deletions.
@@ -148,7 +148,7 @@ Status ActionCommands::exportMovie(bool isGif)
OnScopeExit(dialog->deleteLater());

dialog->init();

std::vector< std::pair<QString, QSize> > camerasInfo;
auto cameraLayers = mEditor->object()->getLayersByType< LayerCamera >();
for (LayerCamera* i : cameraLayers)
@@ -178,7 +178,7 @@ Status ActionCommands::exportMovie(bool isGif)

dialog->setDefaultRange(1, length, lengthWithSounds);
dialog->exec();

if (dialog->result() == QDialog::Rejected)
{
return Status::SAFE;
@@ -262,7 +262,7 @@ Status ActionCommands::exportImageSequence()
{
auto dialog = new ExportImageDialog(mParent, FileType::IMAGE_SEQUENCE);
OnScopeExit(dialog->deleteLater());

dialog->init();

std::vector< std::pair<QString, QSize> > camerasInfo;
@@ -665,7 +665,7 @@ Status ActionCommands::deleteCurrentLayer()

int ret = QMessageBox::warning(mParent,
tr("Delete Layer", "Windows title of Delete current layer pop-up."),
tr("Are you sure you want to delete layer: ") + strLayerName + " ?",
tr("Are you sure you want to delete layer: %1?").arg(strLayerName),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok);
if (ret == QMessageBox::Ok)
@@ -29,7 +29,7 @@ CheckUpdatesDialog::CheckUpdatesDialog()
mDetailLabel = new QLabel;
mDetailLabel->setWordWrap(true);

//If minimum and maximum both are set to 0, the bar shows a busy indicator instead of a percentage of steps.
//If minimum and maximum both are set to 0, the bar shows a busy indicator instead of a percentage of steps.
mProgressBar = new QProgressBar;
mProgressBar->setMaximum(0);
mProgressBar->setMinimum(0);
@@ -42,7 +42,7 @@ CheckUpdatesDialog::CheckUpdatesDialog()
QHBoxLayout* hButtonLayout = new QHBoxLayout;
hButtonLayout->addWidget(mDownloadButton);
hButtonLayout->addWidget(mCloseButton);

QVBoxLayout* vLayout = new QVBoxLayout;
vLayout->addWidget(mTitleLabel);
vLayout->addWidget(mDetailLabel);
@@ -67,7 +67,7 @@ CheckUpdatesDialog::~CheckUpdatesDialog()
}

void CheckUpdatesDialog::startChecking()
{
{
#ifdef NIGHTLY
nightlyBuildCheck();
#else
@@ -139,7 +139,7 @@ void CheckUpdatesDialog::networkRequestFinished(QNetworkReply* reply)
else
{
mTitleLabel->setText(tr("<b>Pencil2D is up to date</b>"));
mDetailLabel->setText(tr("Version") + " " APP_VERSION);
mDetailLabel->setText(tr("Version %1").arg(APP_VERSION));
mProgressBar->setRange(0, 1);
mProgressBar->setValue(1);
mDownloadButton->setEnabled(false);
@@ -154,7 +154,7 @@ bool CheckUpdatesDialog::compareVersion(QString currentVersion, QString latestVe
QString CheckUpdatesDialog::getVersionNumberFromXml(QString xml)
{
// XML source: http://github.com/pencil2d/pencil/releases.atom

QXmlStreamReader xmlReader(xml);

while (!xmlReader.atEnd() && !xmlReader.hasError())
@@ -243,12 +243,12 @@ QString FileDialog::defaultFileName( FileType fileType )
switch ( fileType )
{
case FileType::ANIMATION: return tr( "MyAnimation.pclx" );
case FileType::IMAGE: return "untitled.png";
case FileType::IMAGE_SEQUENCE: return "untitled.png";
case FileType::GIF: return "untitled.gif";
case FileType::MOVIE: return "untitled.mp4";
case FileType::SOUND: return "untitled.wav";
case FileType::PALETTE: return "untitled.xml";
case FileType::IMAGE: return tr( "untitled.png" );
case FileType::IMAGE_SEQUENCE: return tr( "untitled.png" );
case FileType::GIF: return tr( "untitled.gif" );
case FileType::MOVIE: return tr( "untitled.mp4" );
case FileType::SOUND: return tr( "untitled.wav" );
case FileType::PALETTE: return tr( "untitled.xml" );
}
return "";
}
@@ -351,12 +351,10 @@ Status ImportImageSeqDialog::validateKeySet(const PredefinedKeySet& keySet, cons

if (filepaths.isEmpty()) { status = Status::FAIL; }

for (int i = 0; i < filepaths.size(); i++)
if (keySet.isEmpty())
{
if (keySet.isEmpty()) {
status = Status::FAIL;
failedPathsString += filepaths[i] + ", ";
}
status = Status::FAIL;
failedPathsString = QLocale().createSeparatedList(filepaths);
}

if (status == Status::FAIL)
@@ -40,6 +40,7 @@ void installTranslator(PencilApplication& app)
{
strUserLocale = QLocale::system().name();
}
QLocale::setDefault(QLocale(strUserLocale));

strUserLocale.replace("-", "_");
QTranslator* qtTranslator = new QTranslator(&app);
@@ -364,7 +364,7 @@ void MainWindow2::createMenus()
mColorBox->toggleViewAction(),
mColorPalette->toggleViewAction(),
mTimeLine->toggleViewAction(),
mDisplayOptionWidget->toggleViewAction(),
mDisplayOptionWidget->toggleViewAction(),
mColorInspector->toggleViewAction(),
mOnionSkinWidget->toggleViewAction()
};
@@ -786,7 +786,7 @@ bool MainWindow2::autoSave()

QMessageBox msgBox(this);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle("AutoSave Reminder");
msgBox.setWindowTitle(tr("AutoSave Reminder"));
msgBox.setText(tr("The animation is not saved yet.\n Do you want to save now?"));
msgBox.addButton(tr("Never ask again", "AutoSave reminder button"), QMessageBox::RejectRole);
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
@@ -959,7 +959,7 @@ void MainWindow2::importGIF()
{
QMessageBox::warning(this,
tr("Warning"),
tr("was unable to import") + strImgFileLower,
tr("was unable to import %1").arg(strImgFileLower),
QMessageBox::Ok,
QMessageBox::Ok);
}
@@ -992,7 +992,7 @@ void MainWindow2::lockWidgets(bool shouldLock)
mOnionSkinWidget->setFeatures(feat);
mToolOptions->setFeatures(feat);
mToolBox->setFeatures(feat);
mTimeLine->setFeatures(feat);
mTimeLine->setFeatures(feat);
}

void MainWindow2::preferences()
@@ -1041,7 +1041,7 @@ bool MainWindow2::newObject()

bool MainWindow2::newObjectFromPresets(int presetIndex)
{
Object* object = nullptr;
Object* object = nullptr;
QString presetFilePath = (presetIndex > 0) ? PresetDialog::getPresetPath(presetIndex) : "";
if (!presetFilePath.isEmpty())
{
@@ -1223,7 +1223,7 @@ void MainWindow2::setupKeyboardShortcuts()
mColorBox->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_WHEEL));
mColorPalette->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_LIBRARY));
mTimeLine->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_TIMELINE));
mDisplayOptionWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_DISPLAY_OPTIONS));
mDisplayOptionWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_DISPLAY_OPTIONS));
mColorInspector->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_COLOR_INSPECTOR));
mOnionSkinWidget->toggleViewAction()->setShortcut(cmdKeySeq(CMD_TOGGLE_ONION_SKIN));

@@ -1453,7 +1453,7 @@ void MainWindow2::bindActionWithSetting(QAction* action, SETTING setting)
void MainWindow2::updateZoomLabel()
{
float zoom = mEditor->view()->scaling() * 100.f;
statusBar()->showMessage(QString("Zoom: %0%1").arg(static_cast<double>(zoom), 0, 'f', 1).arg("%"));
statusBar()->showMessage(tr("Zoom: %0%").arg(static_cast<double>(zoom), 0, 'f', 1));
}

void MainWindow2::changePlayState(bool isPlaying)
@@ -30,7 +30,7 @@ PopupColorPaletteWidget::PopupColorPaletteWidget( ScribbleArea *parent ) :
setGraphicsEffect(effect);

setAutoFillBackground(true);
setWindowTitle("Color palette");
setWindowTitle(tr("Color palette"));
setWindowFlags( ( (windowFlags()
| Qt::CustomizeWindowHint)
& ~Qt::WindowMaximizeButtonHint
@@ -40,7 +40,7 @@ PopupColorPaletteWidget::PopupColorPaletteWidget( ScribbleArea *parent ) :
QHBoxLayout *buttonsLayout = new QHBoxLayout();
mainLayout->addLayout(buttonsLayout);
closeButton = new QPushButton(this);
closeButton->setText("close/toggle");
closeButton->setText(tr("close/toggle"));
buttonsLayout->addWidget(closeButton);

// --- connections ---
@@ -43,9 +43,9 @@ struct PredefinedKeySet
switch(index)
{
case 0:
return "Files";
return QObject::tr("Files");
case 1:
return "KeyFrame Pos";
return QObject::tr("KeyFrame Pos");
default:
return "";
}
@@ -99,32 +99,32 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage)

QSettings settings(PENCIL2D, PENCIL2D);

ui->languageCombo->addItem(tr("Arabic ") + " (Arabic)", "ar");
ui->languageCombo->addItem(tr("Catalan ") + " (Catalan)", "ca");
ui->languageCombo->addItem(tr("Czech") + " (Czech)", "cs");
ui->languageCombo->addItem(tr("Danish") + " (Danish)", "da");
ui->languageCombo->addItem(tr("German") + " (German)", "de");
ui->languageCombo->addItem(tr("Greek") + " (Greek)", "el");
ui->languageCombo->addItem(tr("English") + " (English)", "en");
ui->languageCombo->addItem(tr("Spanish") + " (Spanish)", "es");
ui->languageCombo->addItem(tr("Estonian") + " (Estonian)", "et");
ui->languageCombo->addItem(tr("French") + " (French)", "fr");
ui->languageCombo->addItem(tr("Hebrew") + " (Hebrew)", "he");
ui->languageCombo->addItem(tr("Hungarian") + " (Hungarian)", "hu_HU");
ui->languageCombo->addItem(tr("Indonesian") + " (Indonesian)", "id");
ui->languageCombo->addItem(tr("Italian") + " (Italian)", "it");
ui->languageCombo->addItem(tr("Japanese") + " (Japanese)", "ja");
ui->languageCombo->addItem(tr("Kabyle") + " (Kabyle)", "kab");
ui->languageCombo->addItem(tr("Polish") + " (Polish)", "pl");
ui->languageCombo->addItem(tr("Portuguese - Portugal") + "(Portuguese - Portugal)", "pt");
ui->languageCombo->addItem(tr("Portuguese - Brazil") + "(Portuguese - Brazil)", "pt_BR");
ui->languageCombo->addItem(tr("Russian") + " (Russian)", "ru");
ui->languageCombo->addItem(tr("Slovenian") + " (Slovenian)", "sl");
ui->languageCombo->addItem(tr("Swedish") + " (Swedish)", "sv");
ui->languageCombo->addItem(tr("Turkish") + " (Turkish)", "tr");
ui->languageCombo->addItem(tr("Vietnamese") + " (Vietnamese)", "vi");
ui->languageCombo->addItem(tr("Chinese - China") + " (Chinese - China)", "zh_CN");
ui->languageCombo->addItem(tr("Chinese - Taiwan") + " (Chinese - Taiwan)", "zh_TW");
ui->languageCombo->addItem(tr("Arabic (%1)").arg("Arabic"), "ar");
ui->languageCombo->addItem(tr("Catalan (%1)").arg("Catalan"), "ca");
ui->languageCombo->addItem(tr("Czech (%1)").arg("Czech"), "cs");
ui->languageCombo->addItem(tr("Danish (%1)").arg("Danish"), "da");
ui->languageCombo->addItem(tr("German (%1)").arg("German"), "de");
ui->languageCombo->addItem(tr("Greek (%1)").arg("Greek"), "el");
ui->languageCombo->addItem(tr("English (%1)").arg("English"), "en");
ui->languageCombo->addItem(tr("Spanish (%1)").arg("Spanish"), "es");
ui->languageCombo->addItem(tr("Estonian (%1)").arg("Estonian"), "et");
ui->languageCombo->addItem(tr("French (%1)").arg("French"), "fr");
ui->languageCombo->addItem(tr("Hebrew (%1)").arg("Hebrew"), "he");
ui->languageCombo->addItem(tr("Hungarian (%1)").arg("Hungarian"), "hu_HU");
ui->languageCombo->addItem(tr("Indonesian (%1)").arg("Indonesian"), "id");
ui->languageCombo->addItem(tr("Italian (%1)").arg("Italian"), "it");
ui->languageCombo->addItem(tr("Japanese (%1)").arg("Japanese"), "ja");
ui->languageCombo->addItem(tr("Kabyle (%1)").arg("Kabyle"), "kab");
ui->languageCombo->addItem(tr("Polish (%1)").arg("Polish"), "pl");
ui->languageCombo->addItem(tr("Portuguese \u2013 Portugal (%1)").arg("Portuguese \u2013 Portugal"), "pt");
ui->languageCombo->addItem(tr("Portuguese \u2013 Brazil (%1)").arg("Portuguese \u2013 Brazil"), "pt_BR");
ui->languageCombo->addItem(tr("Russian (%1)").arg("Russian"), "ru");
ui->languageCombo->addItem(tr("Slovene (%1)").arg("Slovene"), "sl");
ui->languageCombo->addItem(tr("Swedish (%1)").arg("Swedish"), "sv");
ui->languageCombo->addItem(tr("Turkish (%1)").arg("Turkish"), "tr");
ui->languageCombo->addItem(tr("Vietnamese (%1)").arg("Vietnamese"), "vi");
ui->languageCombo->addItem(tr("Chinese \u2013 China (%1)").arg("Chinese \u2013 China"), "zh_CN");
ui->languageCombo->addItem(tr("Chinese \u2013 Taiwan (%1)").arg("Chinese \u2013 Taiwan"), "zh_TW");

int value = settings.value("windowOpacity").toInt();
ui->windowOpacityLevel->setValue(100 - value);
@@ -753,7 +753,7 @@ void ToolsPage::rotationIncrementChange(int value)
while (360 % angle != 0) {
angle++;
}
ui->rotationIncrementDisplay->setText(tr("%1 degree(s)", "", angle).arg(angle));
ui->rotationIncrementDisplay->setText(tr("%n degree(s)", "", angle));
mManager->set(SETTING::ROTATION_INCREMENT, angle);
}

@@ -39,7 +39,7 @@ ShortcutsPage::ShortcutsPage( QWidget* parent )
ui->setupUi(this);
m_treeModel = new QStandardItemModel(this);
m_treeModel->setColumnCount(2);
m_treeModel->setHorizontalHeaderLabels({ "Action", "Shortcut" });
m_treeModel->setHorizontalHeaderLabels({ tr("Action"), tr("Shortcut") });
treeModelLoadShortcutsSetting();

ui->treeView->setModel(m_treeModel);
@@ -132,7 +132,7 @@ void ShortcutsPage::saveShortcutsButtonClicked()

QString fileName = QFileDialog::getSaveFileName(this,
tr("Save Pencil2D Shortcut file"),
fDir + "/untitled.pcls",
fDir + "/" + tr("untitled.pcls"),
tr("Pencil2D Shortcut File(*.pcls)"));
settings.setValue("Shortcuts", fileName);
settings.endGroup();
@@ -74,7 +74,7 @@ void Editor::importMovie (QString filePath, int fps)
QDir::temp().mkdir("pencil");
QString tempPath = QDir::temp().absolutePath()+"/pencil/";

QProgressDialog progress("Importing movie...", "Abort", 0, 100, NULL);
QProgressDialog progress(tr("Importing movie..."), tr("Abort"), 0, 100, NULL);
progress.setWindowModality(Qt::WindowModal);
progress.show();
progress.setValue(10);
@@ -95,7 +95,7 @@ void Editor::importMovie(QString filePath, int fps)
QDir::temp().mkdir("pencil");
QString tempPath = QDir::temp().absolutePath()+"/pencil/";

QProgressDialog progress("Importing movie...", "Abort", 0, 100, NULL);
QProgressDialog progress(tr("Importing movie..."), tr("Abort"), 0, 100, NULL);
progress.setWindowModality(Qt::WindowModal);
progress.show();
progress.setValue(10);
@@ -50,7 +50,7 @@ void Editor::importMovie( QString filePath, int fps )

if ( QFile::exists( QDir::current().currentPath() + "/plugins/ffmpeg.exe" ) == true )
{
QProgressDialog progress( "Importing movie...", "Abort", 0, 100, NULL );
QProgressDialog progress( tr("Importing movie..."), tr("Abort"), 0, 100, NULL );
progress.setWindowModality( Qt::WindowModal );
progress.show();
progress.setValue( 10 );
@@ -25,7 +25,7 @@ GNU General Public License for more details.
ColourRef::ColourRef()
{
colour = Qt::green;
name = QString("Green");
name = QObject::tr("Green");
}

ColourRef::ColourRef(QColor theColour, QString theName)
@@ -43,7 +43,7 @@ void TimeControls::initUI()
mFpsBox->setValue(settings.value("fps").toInt());
mFpsBox->setMinimum(1);
mFpsBox->setMaximum(90);
mFpsBox->setSuffix(" fps");
mFpsBox->setSuffix(tr(" fps"));
mFpsBox->setToolTip(tr("Frames per second"));
mFpsBox->setFocusPolicy(Qt::WheelFocus);

@@ -288,7 +288,7 @@ void TimeLine::deleteCurrentLayer()

int ret = QMessageBox::warning(this,
tr("Delete Layer", "Windows title of Delete current layer pop-up."),
tr("Are you sure you want to delete layer: ") + strLayerName + " ?",
tr("Are you sure you want to delete layer: %1?").arg(strLayerName),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok);
if (ret == QMessageBox::Ok)
@@ -169,7 +169,8 @@ QString LayerManager::nameSuggestLayer(const QString& name)
int newIndex = 2;
QString newName = name;
do {
newName = name + " " + QString::number(newIndex++);
newName = tr("%1 %2", "Layer name template: base name (translated separately) + number")

This comment has been minimized.

Copy link
@chchwy

chchwy Jun 8, 2020

Member

@J5lx Just found this: any reason to translate tr("%1 %2")?

This comment has been minimized.

Copy link
@J5lx

J5lx Jun 8, 2020

Author Member

Allowing translators to put the number in a different place or use punctuation etc. in case that’s how their language works or necessary to make it sound natural. Basically another way of writing “bitmap/vector/sound layer %1”, except… less flexible? I’m actually not sure why I did this in such a roundabout way.

.arg(name).arg(QString::number(newIndex++));
} while (sLayers.contains(newName));
return newName;
}
@@ -129,25 +129,25 @@ Status MovieExporter::run(const Object* obj,
if (desc.strFileName.endsWith("gif", Qt::CaseInsensitive))
{
majorProgress(0.03f, 1.f);
progressMessage("Generating gif...");
progressMessage(QObject::tr("Generating GIF..."));
minorProgress(0.f);
STATUS_CHECK(generateGif(obj, ffmpegPath, desc.strFileName, minorProgress));
}
else
{
majorProgress(0.03f, 0.25f);
progressMessage("Assembling audio...");
progressMessage(QObject::tr("Assembling audio..."));
minorProgress(0.f);
STATUS_CHECK(assembleAudio(obj, ffmpegPath, minorProgress));
minorProgress(1.f);
majorProgress(0.25f, 1.f);
progressMessage("Generating movie...");
progressMessage(QObject::tr("Generating movie..."));
STATUS_CHECK(generateMovie(obj, ffmpegPath, desc.strFileName, minorProgress));
}
minorProgress(1.f);
majorProgress(1.f, 1.f);
progressMessage(QObject::tr("Done"));

clock_t t2 = clock() - t1;
qDebug("MOVIE = %.1f sec", static_cast<double>(t2 / CLOCKS_PER_SEC));

6 comments on commit f9e5e5a

@chchwy
Copy link
Member

@chchwy chchwy commented on f9e5e5a May 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks heaps for the updates.

Just one minor thing. Usually, I would avoid changing the translatable strings if the string itself doesn't change.
Like: tr("Arabic (%1)").arg("Arabic") to tr("Arabic ") + " (Arabic)"

Yes, it looks slick. but it also invalidates all the old translations.

@J5lx
Copy link
Member Author

@J5lx J5lx commented on f9e5e5a May 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I’m not sure that it’s always that simple. For example, throwing your example “Arabic (%1)” into Google Translate yields “العربية (٪ 1)”, which seems structurally different to me from what we had before. Perhaps some other languages have additional peculiarities as well. But you do have a point.

@chchwy
Copy link
Member

@chchwy chchwy commented on f9e5e5a May 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reverse order of Arabic is done by Qt (even with tr("Arabic ") + " (Arabic)"). We don't need to worry about it here.

@J5lx
Copy link
Member Author

@J5lx J5lx commented on f9e5e5a May 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay… that’s interesting. Personally, I still dislike the original solution because a) I don’t want to make assumptions about what sort of spacing and punctuation other languages use and b) there’s too much black magic going on for my taste (I couldn’t even find an explanation by googling). But if you feel like invalidating translations is the “greater evil”, feel free to revert that part of the commit (or let me know and I’ll do it).

@chchwy
Copy link
Member

@chchwy chchwy commented on f9e5e5a May 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't mean the change is evil. From the code perspective it's actually better. I have no intention to ask you to revert the change.

I just want everyone to be a bit more cautious to change translatable strings next time. We are an open source project by volunteers. Every time programmers invalidate a translation, there is no guarantee the string will be translated again anytime soon. For example, Italian was once 100% translated, but after years it's now only 36.77%. We could do our best to save the labour of translations.

@J5lx
Copy link
Member Author

@J5lx J5lx commented on f9e5e5a May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, looks like we were talking past each other. When I said “greater evil” I actually meant it in a figurative way, not a literal evil. I’m indeed aware that changing strings invalidates translations, but in this case I went through with the change because, as I explained above, I believed that the existing strings were making it difficult to translate them well into some languages.

Please sign in to comment.