File indexing completed on 2025-01-19 03:50:58
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2022-08-30 0007 * Description : translate metadata batch tool. 0008 * 0009 * SPDX-FileCopyrightText: 2021-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "translate.h" 0016 0017 // Qt includes 0018 0019 #include <QGridLayout> 0020 #include <QCheckBox> 0021 #include <QComboBox> 0022 #include <QWidget> 0023 #include <QListWidget> 0024 #include <QLabel> 0025 #include <QFile> 0026 #include <QMenu> 0027 0028 // KDE includes 0029 0030 #include <klocalizedstring.h> 0031 0032 // Local includes 0033 0034 #include "digikam_debug.h" 0035 #include "dimg.h" 0036 #include "dfileoperations.h" 0037 #include "donlinetranslator.h" 0038 #include "localizesettings.h" 0039 #include "localizeselector.h" 0040 #include "altlangstredit.h" 0041 0042 namespace DigikamBqmTranslatePlugin 0043 { 0044 0045 class Q_DECL_HIDDEN Translate::Private 0046 { 0047 0048 public: 0049 0050 enum Entries 0051 { 0052 Title = 0x01, 0053 Caption = 0x02, 0054 Copyrights = 0x04, 0055 UsageTerms = 0x08 0056 }; 0057 0058 public: 0059 0060 explicit Private() 0061 : titleCB (nullptr), 0062 captionCB (nullptr), 0063 copyrightsCB (nullptr), 0064 usageTermsCB (nullptr), 0065 trLabel (nullptr), 0066 tagsLabel (nullptr), 0067 trSelectorList(nullptr), 0068 changeSettings(true) 0069 { 0070 } 0071 0072 QCheckBox* titleCB; 0073 QCheckBox* captionCB; 0074 QCheckBox* copyrightsCB; 0075 QCheckBox* usageTermsCB; 0076 0077 QLabel* trLabel; 0078 QLabel* tagsLabel; 0079 0080 LocalizeSelectorList* trSelectorList; 0081 0082 bool changeSettings; 0083 }; 0084 0085 Translate::Translate(QObject* const parent) 0086 : BatchTool(QLatin1String("Translate"), MetadataTool, parent), 0087 d (new Private) 0088 { 0089 } 0090 0091 Translate::~Translate() 0092 { 0093 delete d; 0094 } 0095 0096 BatchTool* Translate::clone(QObject* const parent) const 0097 { 0098 return new Translate(parent); 0099 } 0100 0101 void Translate::registerSettingsWidget() 0102 { 0103 QWidget* const panel = new QWidget; 0104 QGridLayout* const grid = new QGridLayout(panel); 0105 0106 d->tagsLabel = new QLabel(panel); 0107 d->titleCB = new QCheckBox(i18nc("@option:check metadata entry", "Title"), panel); 0108 d->captionCB = new QCheckBox(i18nc("@option:check metadata entry", "Caption"), panel); 0109 d->copyrightsCB = new QCheckBox(i18nc("@option:check metadata entry", "Copyrights"), panel); 0110 d->usageTermsCB = new QCheckBox(i18nc("@option:check metadata entry", "Usage Terms"), panel); 0111 0112 d->trSelectorList = new LocalizeSelectorList(panel); 0113 d->trSelectorList->setTitle(i18nc("@label", "Translate to:")); 0114 0115 grid->addWidget(d->tagsLabel, 0, 0, 1, 2); 0116 grid->addWidget(d->titleCB, 1, 0, 1, 2); 0117 grid->addWidget(d->captionCB, 2, 0, 1, 2); 0118 grid->addWidget(d->copyrightsCB, 3, 0, 1, 2); 0119 grid->addWidget(d->usageTermsCB, 4, 0, 1, 2); 0120 grid->addWidget(d->trSelectorList, 5, 0, 1, 2); 0121 grid->setColumnStretch(0, 10); 0122 grid->setRowStretch(6, 10); 0123 0124 slotLocalizeChanged(); 0125 0126 m_settingsWidget = panel; 0127 0128 connect(d->titleCB, SIGNAL(toggled(bool)), 0129 this, SLOT(slotSettingsChanged())); 0130 0131 connect(d->captionCB, SIGNAL(toggled(bool)), 0132 this, SLOT(slotSettingsChanged())); 0133 0134 connect(d->copyrightsCB, SIGNAL(toggled(bool)), 0135 this, SLOT(slotSettingsChanged())); 0136 0137 connect(d->usageTermsCB, SIGNAL(toggled(bool)), 0138 this, SLOT(slotSettingsChanged())); 0139 0140 connect(d->trSelectorList, SIGNAL(signalSettingsChanged()), 0141 this, SLOT(slotSettingsChanged())); 0142 0143 connect(LocalizeSettings::instance(), &LocalizeSettings::signalSettingsChanged, 0144 this, &Translate::slotLocalizeChanged); 0145 0146 BatchTool::registerSettingsWidget(); 0147 } 0148 0149 void Translate::slotLocalizeChanged() 0150 { 0151 d->tagsLabel->setText(i18nc("@label", "Entries to Translate with %1:", 0152 DOnlineTranslator::engineName(LocalizeSettings::instance()->settings().translatorEngine))); 0153 } 0154 0155 BatchToolSettings Translate::defaultSettings() 0156 { 0157 BatchToolSettings settings; 0158 0159 settings.insert(QLatin1String("Title"), false); 0160 settings.insert(QLatin1String("Caption"), false); 0161 settings.insert(QLatin1String("Copyrights"), false); 0162 settings.insert(QLatin1String("UsageTerms"), false); 0163 settings.insert(QLatin1String("TrLangs"), QStringList() << QLatin1String("en-US")); 0164 0165 return settings; 0166 } 0167 0168 void Translate::slotAssignSettings2Widget() 0169 { 0170 d->changeSettings = false; 0171 0172 d->titleCB->setChecked(settings()[QLatin1String("Title")].toBool()); 0173 d->captionCB->setChecked(settings()[QLatin1String("Caption")].toBool()); 0174 d->copyrightsCB->setChecked(settings()[QLatin1String("Copyrights")].toBool()); 0175 d->usageTermsCB->setChecked(settings()[QLatin1String("UsageTerms")].toBool()); 0176 0177 QStringList langs = settings()[QLatin1String("TrLangs")].toStringList(); 0178 0179 d->trSelectorList->clearLanguages(); 0180 0181 Q_FOREACH (const QString& lg, langs) 0182 { 0183 d->trSelectorList->addLanguage(lg); 0184 } 0185 0186 d->changeSettings = true; 0187 } 0188 0189 void Translate::slotSettingsChanged() 0190 { 0191 if (d->changeSettings) 0192 { 0193 BatchToolSettings settings; 0194 0195 settings.insert(QLatin1String("Title"), d->titleCB->isChecked()); 0196 settings.insert(QLatin1String("Caption"), d->captionCB->isChecked()); 0197 settings.insert(QLatin1String("Copyrights"), d->copyrightsCB->isChecked()); 0198 settings.insert(QLatin1String("UsageTerms"), d->usageTermsCB->isChecked()); 0199 0200 QStringList langs = d->trSelectorList->languagesList(); 0201 settings.insert(QLatin1String("TrLangs"), langs); 0202 0203 BatchTool::slotSettingsChanged(settings); 0204 } 0205 } 0206 0207 bool Translate::toolOperations() 0208 { 0209 bool ret = true; 0210 QScopedPointer<DMetadata> meta(new DMetadata); 0211 0212 if (image().isNull()) 0213 { 0214 if (!meta->load(inputUrl().toLocalFile())) 0215 { 0216 return false; 0217 } 0218 } 0219 else 0220 { 0221 meta->setData(image().getMetadata()); 0222 } 0223 0224 bool titleStage = settings()[QLatin1String("Title")].toBool(); 0225 bool captionStage = settings()[QLatin1String("Caption")].toBool(); 0226 bool copyrightsStage = settings()[QLatin1String("Copyrights")].toBool(); 0227 bool usageTermsStage = settings()[QLatin1String("UsageTerms")].toBool(); 0228 QStringList langs = settings()[QLatin1String("TrLangs")].toStringList(); 0229 0230 Q_FOREACH (const QString& trLang, langs) 0231 { 0232 if (titleStage) 0233 { 0234 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Translate Title"; 0235 ret &= insertTranslation(Private::Title, trLang, meta.data()); 0236 } 0237 0238 if (captionStage) 0239 { 0240 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Translate Caption"; 0241 ret &= insertTranslation(Private::Caption, trLang, meta.data()); 0242 } 0243 0244 if (copyrightsStage) 0245 { 0246 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Translate Copyrights"; 0247 ret &= insertTranslation(Private::Copyrights, trLang, meta.data()); 0248 } 0249 0250 if (usageTermsStage) 0251 { 0252 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Translate Usage Terms"; 0253 ret &= insertTranslation(Private::UsageTerms, trLang, meta.data()); 0254 } 0255 0256 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Title :" << meta->getXmpTagStringListLangAlt("Xmp.dc.title", false); 0257 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Caption :" << meta->getXmpTagStringListLangAlt("Xmp.dc.description", false); 0258 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "CopyRights:" << meta->getXmpTagStringListLangAlt("Xmp.dc.rights", false); 0259 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "UsageTerms:" << meta->getXmpTagStringListLangAlt("Xmp.xmpRights.UsageTerms", false); 0260 0261 if (image().isNull()) 0262 { 0263 QFile::remove(outputUrl().toLocalFile()); 0264 ret &= DFileOperations::copyFile(inputUrl().toLocalFile(), outputUrl().toLocalFile()); 0265 0266 if (ret && (titleStage || captionStage || copyrightsStage || usageTermsStage)) 0267 { 0268 ret &= meta->save(outputUrl().toLocalFile()); 0269 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Save metadata to file:" << ret; 0270 } 0271 } 0272 else 0273 { 0274 if (titleStage || captionStage || copyrightsStage || usageTermsStage) 0275 { 0276 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Save metadata to image"; 0277 image().setMetadata(meta->data()); 0278 } 0279 0280 ret &= savefromDImg(); 0281 } 0282 } 0283 0284 return ret; 0285 } 0286 0287 bool Translate::insertTranslation(int entry, const QString& trLang, DMetadata* const meta) const 0288 { 0289 bool ret = true; 0290 CaptionsMap captions; 0291 DMetadata::AltLangMap map; 0292 0293 switch (entry) 0294 { 0295 case Private::Title: 0296 { 0297 captions = meta->getItemTitles(); 0298 map = captions.toAltLangMap(); 0299 break; 0300 } 0301 0302 case Private::Caption: 0303 { 0304 captions = meta->getItemComments(); 0305 map = captions.toAltLangMap(); 0306 break; 0307 } 0308 0309 case Private::Copyrights: 0310 { 0311 map = meta->getXmpTagStringListLangAlt("Xmp.dc.rights", false); 0312 break; 0313 } 0314 0315 case Private::UsageTerms: 0316 { 0317 map = meta->getXmpTagStringListLangAlt("Xmp.xmpRights.UsageTerms", false); 0318 break; 0319 } 0320 } 0321 0322 if (!map.isEmpty() && map.contains(QLatin1String("x-default"))) 0323 { 0324 QString sc = map.value(QLatin1String("x-default")); 0325 0326 if (!sc.isEmpty()) 0327 { 0328 QString tr; 0329 QString error; 0330 ret = s_inlineTranslateString(sc, trLang, tr, error); 0331 0332 if (ret) 0333 { 0334 switch (entry) 0335 { 0336 case Private::Title: 0337 { 0338 CaptionValues val = captions[QLatin1String("x-default")]; 0339 val.caption = tr; 0340 captions[trLang] = val; 0341 meta->setItemTitles(captions); 0342 break; 0343 } 0344 0345 case Private::Caption: 0346 { 0347 CaptionValues val = captions[QLatin1String("x-default")]; 0348 val.caption = tr; 0349 captions[trLang] = val; 0350 meta->setItemComments(captions); 0351 break; 0352 } 0353 0354 case Private::Copyrights: 0355 { 0356 map[trLang] = tr; 0357 meta->setXmpTagStringListLangAlt("Xmp.dc.rights", map); 0358 break; 0359 } 0360 0361 case Private::UsageTerms: 0362 { 0363 map[trLang] = tr; 0364 meta->setXmpTagStringListLangAlt("Xmp.xmpRights.UsageTerms", map); 0365 break; 0366 } 0367 } 0368 } 0369 else 0370 { 0371 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "Cannot process online translation from" 0372 << meta->getFilePath() 0373 << " - Error:" << error; 0374 } 0375 } 0376 else 0377 { 0378 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "No x-default language found from" << meta->getFilePath(); 0379 } 0380 } 0381 else 0382 { 0383 qCDebug(DIGIKAM_DPLUGIN_BQM_LOG) << "No alternative language string found from" << meta->getFilePath(); 0384 } 0385 0386 return ret; 0387 } 0388 0389 } // namespace DigikamBqmTranslatePlugin 0390 0391 #include "moc_translate.cpp"