Tons more improvements

ubuntu/noble
Aaron Rainbolt 4 months ago
parent 5da00ab878
commit 49ec545222

1
.gitignore vendored

@ -0,0 +1 @@
CMakeLists.txt.user

@ -12,47 +12,50 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)
set(TS_FILES translations/lubuntu-update_en_US.ts)
set(TS_FILES
src/translations/lubuntu-update_en_US.ts
src/translations/lubuntu-update_es_ES.ts
src/translations/lubuntu-update_zh_CN.ts
)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
orchestrator.h
orchestrator.cpp
aptmanager.h
aptmanager.cpp
conffilewidget.h
conffilewidget.cpp
conffilewidget.ui
diffdisplaydialog.h
diffdisplaydialog.cpp
diffdisplaydialog.ui
conffilehandlerdialog.h
conffilehandlerdialog.cpp
conffilehandlerdialog.ui
ipcfilewatcher.h
ipcfilewatcher.cpp
src/main.cpp
src/mainwindow.cpp
src/mainwindow.h
src/mainwindow.ui
src/orchestrator.h
src/orchestrator.cpp
src/aptmanager.h
src/aptmanager.cpp
src/conffilewidget.h
src/conffilewidget.cpp
src/conffilewidget.ui
src/diffdisplaydialog.h
src/diffdisplaydialog.cpp
src/diffdisplaydialog.ui
src/conffilehandlerdialog.h
src/conffilehandlerdialog.cpp
src/conffilehandlerdialog.ui
src/ipcfilewatcher.h
src/ipcfilewatcher.cpp
${TS_FILES}
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(lubuntu-update
MANUAL_FINALIZATION
${PROJECT_SOURCES}
resources.qrc
)
set(TRANSLATION_RESOURCES "src/translations.qrc")
configure_file(${TRANSLATION_RESOURCES} translations.qrc COPYONLY)
qt5_add_translation(QM_FILES ${TS_FILES})
qt5_add_resources(QM_RESOURCES ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
else()
add_executable(lubuntu-update
${PROJECT_SOURCES}
resources.qrc
)
add_custom_target(translations ALL DEPENDS ${QM_FILES})
add_executable(lubuntu-update
${PROJECT_SOURCES}
${QM_RESOURCES}
src/resources.qrc
)
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()
add_dependencies(lubuntu-update translations)
target_link_libraries(lubuntu-update PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
@ -70,8 +73,6 @@ install(TARGETS lubuntu-update
# has gotten into /usr/libexec you're compromised anyway, so not much to worry
# about. Therefore we always, *always* install this script into /usr/libexec/,
# no matter where the rest of the program goes.
install(FILES lubuntu-update-backend DESTINATION /usr/libexec/)
install(FILES src/lubuntu-update-backend DESTINATION /usr/libexec/)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(lubuntu-update)
endif()
install(FILES lubuntu-update.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications/)

@ -22,8 +22,32 @@ Qt Creator is recommended for editing the code. It is present in Ubuntu's offici
## Missing features
* The Details button is hidden and does nothing. Eventually it should display a list of packages, the old version of them, the new version of them, and a link to their Launchpad page.
* Double-clicking on a package doesn't show detailed information for it yet.
* There's no support for release upgrading. This is currently unnecessary as this updater is only going to be shipped in Noble and later, but it will become a big deal in the (potentially near) future.
* There's no support for doing an `apt update` for checking for recent updates. This seems rather important *now*.
* Most of the internal strings aren't translatable...
* ...and the bit of translation support there is, is totally untested and quite possibly not functioning properly. Borrow from what we did with lubuntu-installer-prompt to fix this.
* The translation support is mostly untested, though it should work.
## Translations
Run the `gen_ts.sh` script after making any code modifications to ensure that the translations files are up-to-date for translators to work on.
To add a new language to be translated:
* Open the `gen_ts.sh` script and add the locale code for the new language to the `langList` array.
* Run the script after doing this - a new template .ts file will be generated under `src/translations/`.
* Next, add the new template file to the `TS_FILES` list in `CMakeLists.txt` - it will be named `src/translations/lubuntu-update_locale_CODE.ts`, where `locale_CODE` is the locale code of the added language.
* Finally, add a line in the src/translations.qrc resource file to include the new translation file. The line should look like `<file alias="locale_CODE">lubuntu-update_locale_CODE.qm</file>`, where `locale_CODE` is the locale code of the added language. This line should go inside the `<qresource>` tag.
For instance, if I were to add Chinese to the list of languages that could be translated into, I would do this:
vim gen_ts.sh
# add this code to the langList array:
# 'zh_CN'
./gen_ts.sh
vim CMakeLists.txt
# add this line to the TS_FILES list:
# src/translations/lubuntu-update_zh_CN.ts
vim src/translations.qrc
# add this line to the list of file resources:
# <file alias="zh_CN">lubuntu-update_zh_CN.qm</file>
The program will now pick up the added language at build time. Any translations added to the newly created .ts file will be shown to program users who select the new language.

@ -0,0 +1,11 @@
#!/bin/bash
langList=('en_US' 'es_ES' 'zh_CN')
for i in ${langList[@]}; do
targetFile="translations/lubuntu-update_$i.ts"
if [ ! -e $targetFile ]; then
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>" > $targetFile
echo "<!DOCTYPE TS>" >> $targetFile
echo "<TS version=\"2.1\" language=\"$i\"></TS>" >> $targetFile
fi
done
lupdate *.cpp *.h *.ui -ts translations/*

@ -30,8 +30,19 @@ void AptManager::applyFullUpgrade()
// Note that the lubuntu-update-backend script sets LC_ALL=C in it already, so we don't need to add that here.
aptProcess->setArguments(QStringList() << "/usr/libexec/lubuntu-update-backend" << "doupdate");
aptProcess->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(aptProcess, &QProcess::readyRead, this, &AptManager::handleProcessBuffer);
QObject::connect(aptProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AptManager::handleProcessBuffer);
QObject::connect(aptProcess, &QProcess::readyRead, this, &AptManager::handleUpdateProcessBuffer);
QObject::connect(aptProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AptManager::handleUpdateProcessBuffer);
aptProcess->start();
}
void AptManager::checkForUpdates()
{
aptProcess = new QProcess();
aptProcess->setProgram("/usr/bin/lxqt-sudo");
aptProcess->setArguments(QStringList() << "/usr/libexec/lubuntu-update-backend" << "checkupdate");
aptProcess->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(aptProcess, &QProcess::readyRead, this, &AptManager::handleCheckUpdateProcessBuffer);
QObject::connect(aptProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AptManager::handleCheckUpdateProcessBuffer);
aptProcess->start();
}
@ -56,7 +67,7 @@ void AptManager::doneWithConffiles()
aptProcess->closeWriteChannel();
}
void AptManager::handleProcessBuffer()
void AptManager::handleUpdateProcessBuffer()
{
int maxWaitTime = 20;
while (!aptProcess->canReadLine() && maxWaitTime > 0) {
@ -149,6 +160,27 @@ void AptManager::handleProcessBuffer()
}
}
void AptManager::handleCheckUpdateProcessBuffer()
{
/*
* We don't have the busy wait here because the apt output when doing
* `apt-get update` is somewhat ill-formed and difficult to fix, and
* busy-waiting was resulting in *awful* progress bar choppiness.
*/
char lineBuf[2048];
while(aptProcess->canReadLine()) {
aptProcess->readLine(lineBuf, 2048);
QString line = QString(lineBuf);
emit logLineReady(line);
}
if (aptProcess->state() == QProcess::NotRunning) {
emit checkUpdatesComplete();
aptProcess->deleteLater();
}
}
QList<QStringList> AptManager::getUpdateInfo()
{
/*

@ -17,18 +17,21 @@ public:
AptManager(QObject *parent = nullptr);
static QList<QStringList> getUpdateInfo();
void applyFullUpgrade();
void checkForUpdates();
void keepConffile(QString conffile);
void replaceConffile(QString conffile);
void doneWithConffiles();
signals:
void updateComplete();
void checkUpdatesComplete();
void progressUpdated(int progress);
void logLineReady(QString logLine);
void conffileListReady(QStringList conffileList);
private slots:
void handleProcessBuffer();
void handleUpdateProcessBuffer();
void handleCheckUpdateProcessBuffer();
private:
static void parseAptLine(QString line, bool *gettingInstallPackages, bool *gettingUpgradePackages, bool *gettingUninstallPackages, bool *gettingHeldPackages, bool *gettingPackageList);

@ -4,8 +4,6 @@
#include <QProcess>
#include <QDebug>
ConffileWidget::ConffileWidget(QString filename, QWidget *parent) :
QWidget(parent),
ui(new Ui::ConffileWidget)

@ -8,7 +8,7 @@ if [ "$1" = 'pkgver' ]; then
shift
while [ "$1" != '' ]; do
source="$(apt-cache show "$1" | grep 'Source:' | cut -d' ' -f2)"
version="$(apt-cache show lubuntu-default-settings | grep Version: | head -n1 | cut -d' ' -f2)"
version="$(apt-cache show "$1" | grep Version: | head -n1 | cut -d' ' -f2)"
if [ "$source" = '' ]; then
echo "$1"
else
@ -17,6 +17,8 @@ if [ "$1" = 'pkgver' ]; then
echo "$version"
shift
done
elif [ "$1" = 'checkupdate' ]; then
apt-get -o Apt::Color='0' -o Dpkg::Use-Pty='0' update
elif [ "$1" = 'doupdate' ]; then
# Prepare to be able to grep through the logs
rm /run/lubuntu-update-apt-log || true

@ -16,7 +16,7 @@ int main(int argc, char *argv[])
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "lubuntu-update_" + QLocale(locale).name();
const QString baseName = QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
a.installTranslator(&translator);
break;

@ -17,12 +17,11 @@ MainWindow::MainWindow(QWidget *parent)
ui->progressBar->setVisible(false);
ui->logView->setVisible(false);
// FIXME: Implement the Details screen and attach this button to it rather than disabling it.
ui->detailsButton->setVisible(false);
connect(ui->installButton, &QPushButton::clicked, this, &MainWindow::onInstallButtonClicked);
connect(ui->checkUpdatesButton, &QPushButton::clicked, this, &MainWindow::onCheckUpdatesButtonClicked);
connect(ui->closeButton, &QPushButton::clicked, this, &MainWindow::onCloseButtonClicked);
connect(aptManager, &AptManager::updateComplete, this, &MainWindow::onUpdateCompleted);
connect(aptManager, &AptManager::checkUpdatesComplete, this, &MainWindow::onCheckUpdatesCompleted);
connect(aptManager, &AptManager::progressUpdated, this, &MainWindow::onProgressUpdate);
connect(aptManager, &AptManager::logLineReady, this, &MainWindow::onLogLineReady);
connect(aptManager, &AptManager::conffileListReady, this, &MainWindow::onConffileListReady);
@ -39,9 +38,9 @@ void MainWindow::setUpdateInfo(QList<QStringList> updateInfo)
// The progress bar and log view are shown after the user chooses to begin installing updates
ui->progressBar->setVisible(false);
ui->logView->setVisible(false);
ui->detailsButton->setEnabled(true);
ui->closeButton->setEnabled(true);
ui->installButton->setEnabled(false); // Correct, it starts out false, we turn it to true if there are any updates.
ui->checkUpdatesButton->setEnabled(true);
for (int i = 0;i < 4;i++) {
if (updateInfo[i].count() > 0) {
@ -51,16 +50,16 @@ void MainWindow::setUpdateInfo(QList<QStringList> updateInfo)
QTreeWidgetItem *installItem;
switch (i) {
case 0:
installItem = new QTreeWidgetItem(QStringList() << "To be installed");
installItem = new QTreeWidgetItem(QStringList() << tr("To be installed"));
break;
case 1:
installItem = new QTreeWidgetItem(QStringList() << "To be upgraded");
installItem = new QTreeWidgetItem(QStringList() << tr("To be upgraded"));
break;
case 2:
installItem = new QTreeWidgetItem(QStringList() << "To be removed");
installItem = new QTreeWidgetItem(QStringList() << tr("To be removed"));
break;
case 3:
installItem = new QTreeWidgetItem(QStringList() << "Held back (usually temporarily)");
installItem = new QTreeWidgetItem(QStringList() << tr("Held back (usually temporarily)"));
break;
}
@ -71,7 +70,7 @@ void MainWindow::setUpdateInfo(QList<QStringList> updateInfo)
ui->packageView->addTopLevelItem(installItem);
}
ui->statLabel->setText(QString("%1 package(s) will be updated. %2 of these updates are security-related.")
ui->statLabel->setText(tr("%1 package(s) will be updated. %2 of these updates are security-related.")
.arg(QString::number(updateInfo[0].count() + updateInfo[1].count() + updateInfo[2].count()),
QString::number(updateInfo[4].count())));
}
@ -102,14 +101,30 @@ void MainWindow::closeEvent(QCloseEvent *event)
void MainWindow::onInstallButtonClicked()
{
ui->logView->clear();
ui->progressBar->setVisible(true);
ui->logView->setVisible(true);
ui->installButton->setEnabled(false);
ui->detailsButton->setEnabled(false);
ui->checkUpdatesButton->setEnabled(false);
ui->closeButton->setEnabled(false);
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(100);
aptManager->applyFullUpgrade();
}
void MainWindow::onCheckUpdatesButtonClicked()
{
ui->logView->clear();
ui->progressBar->setVisible(true);
ui->logView->setVisible(true);
ui->installButton->setEnabled(false);
ui->checkUpdatesButton->setEnabled(false);
ui->closeButton->setEnabled(false);
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(0);
aptManager->checkForUpdates();
}
void MainWindow::onCloseButtonClicked()
{
hide();
@ -118,12 +133,19 @@ void MainWindow::onCloseButtonClicked()
void MainWindow::onUpdateCompleted()
{
ui->closeButton->setEnabled(true);
ui->checkUpdatesButton->setEnabled(true);
ui->installButton->setEnabled(false);
ui->progressBar->setVisible(false);
ui->statLabel->setText("Update installation complete.");
ui->statLabel->setText(tr("Update installation complete."));
emit updatesInstalled(); // this tells the orchestrator to hide the tray icon
}
void MainWindow::onCheckUpdatesCompleted()
{
ui->closeButton->setEnabled(true); // unlocks the updater so that the orchestrator actually can update things
emit updatesRefreshed(); // this tells the orchestrator to re-scan for updates
}
void MainWindow::onProgressUpdate(int progress)
{
ui->progressBar->setValue(progress);

@ -25,14 +25,17 @@ public:
signals:
void updatesInstalled();
void updatesRefreshed();
protected slots:
void closeEvent(QCloseEvent *event) override;
private slots:
void onInstallButtonClicked();
void onCheckUpdatesButtonClicked();
void onCloseButtonClicked();
void onUpdateCompleted();
void onCheckUpdatesCompleted();
void onProgressUpdate(int progress);
void onLogLineReady(QString logLine);
void onConffileListReady(QStringList conffileList);

@ -86,9 +86,9 @@ font: 9pt &quot;Monospace&quot;;</string>
</widget>
</item>
<item>
<widget class="QPushButton" name="detailsButton">
<widget class="QPushButton" name="checkUpdatesButton">
<property name="text">
<string>Details</string>
<string>Check for Updates</string>
</property>
</widget>
</item>

@ -15,6 +15,7 @@ Orchestrator::Orchestrator(QObject *parent)
connect(checkTimer, &QTimer::timeout, this, &Orchestrator::checkForUpdates);
connect(trayIcon, &QSystemTrayIcon::activated, this, &Orchestrator::displayUpdater);
connect(&updaterWindow, &MainWindow::updatesInstalled, this, &Orchestrator::handleUpdatesInstalled);
connect(&updaterWindow, &MainWindow::updatesRefreshed, this, &Orchestrator::handleUpdatesRefreshed);
checkTimer->start(21600000); // check four times a day, at least one of those times unattended-upgrades should have refreshed the apt database
@ -34,7 +35,7 @@ void Orchestrator::checkForUpdates()
trayIcon->show();
// Yes, we do intentionally use updateInfo[1], then updateInfo[0], then updateInfo[2]. The updateInfo array is populated in a different order than the one we display in.
trayIcon->showMessage("",
QString("Updates available!\n\n%1 to upgrade, %2 to install, and %3 to remove.\n\nClick the tray icon to install the updates.")
tr("Updates available!\n\n%1 to upgrade, %2 to install, and %3 to remove.\n\nClick the tray icon to install the updates.")
.arg(QString::number(updateInfo[1].count()), QString::number(updateInfo[0].count()), QString::number(updateInfo[2].count())));
}
}
@ -58,3 +59,9 @@ void Orchestrator::handleUpdatesInstalled()
}
trayIcon->hide();
}
void Orchestrator::handleUpdatesRefreshed()
{
checkForUpdates();
displayUpdater();
}

@ -21,6 +21,7 @@ public slots:
private slots:
void checkForUpdates();
void handleUpdatesInstalled();
void handleUpdatesRefreshed();
private:
QTimer *checkTimer;

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/i18n">
<file alias="en_US">lubuntu-update_en_US.qm</file>
<file alias="es_ES">lubuntu-update_es_ES.qm</file>
<file alias="zh_CN">lubuntu-update_zh_CN.qm</file>
</qresource>
</RCC>

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>ConffileHandlerDialog</name>
<message>
<location filename="../conffilehandlerdialog.ui" line="14"/>
<source>Configuration File Conflicts</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilehandlerdialog.ui" line="24"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some of the newly installed updates have updated configuration files. &lt;/p&gt;&lt;p&gt;Please choose what to do with these files.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilehandlerdialog.ui" line="81"/>
<source>Done</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ConffileWidget</name>
<message>
<location filename="../conffilewidget.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="20"/>
<source>Filename</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="40"/>
<source>Keep old</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="47"/>
<source>Replace with new</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="54"/>
<source>Show diff</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DiffDisplayDialog</name>
<message>
<location filename="../diffdisplaydialog.ui" line="14"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../diffdisplaydialog.ui" line="24"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Lines that start with a &amp;quot;+&amp;quot; only exist in the &lt;span style=&quot; font-weight:700;&quot;&gt;new&lt;/span&gt; file.&lt;/p&gt;&lt;p&gt;Lines that start with a &amp;quot;-&amp;quot; only exist in the &lt;span style=&quot; font-weight:700;&quot;&gt;old&lt;/span&gt; file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../diffdisplaydialog.ui" line="56"/>
<source>Done</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>Lubuntu Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="25"/>
<source>0 package(s) will be updated. 0 of these updates are security-related.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="33"/>
<source>Packages</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="80"/>
<source>Install Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="91"/>
<source>Check for Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="98"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="53"/>
<source>To be installed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="56"/>
<source>To be upgraded</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="59"/>
<source>To be removed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="62"/>
<source>Held back (usually temporarily)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="73"/>
<source>%1 package(s) will be updated. %2 of these updates are security-related.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="139"/>
<source>Update installation complete.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Orchestrator</name>
<message>
<location filename="../orchestrator.cpp" line="38"/>
<source>Updates available!
%1 to upgrade, %2 to install, and %3 to remove.
Click the tray icon to install the updates.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="es_ES">
<context>
<name>ConffileHandlerDialog</name>
<message>
<location filename="../conffilehandlerdialog.ui" line="14"/>
<source>Configuration File Conflicts</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilehandlerdialog.ui" line="24"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some of the newly installed updates have updated configuration files. &lt;/p&gt;&lt;p&gt;Please choose what to do with these files.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilehandlerdialog.ui" line="81"/>
<source>Done</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ConffileWidget</name>
<message>
<location filename="../conffilewidget.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="20"/>
<source>Filename</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="40"/>
<source>Keep old</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="47"/>
<source>Replace with new</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="54"/>
<source>Show diff</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DiffDisplayDialog</name>
<message>
<location filename="../diffdisplaydialog.ui" line="14"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../diffdisplaydialog.ui" line="24"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Lines that start with a &amp;quot;+&amp;quot; only exist in the &lt;span style=&quot; font-weight:700;&quot;&gt;new&lt;/span&gt; file.&lt;/p&gt;&lt;p&gt;Lines that start with a &amp;quot;-&amp;quot; only exist in the &lt;span style=&quot; font-weight:700;&quot;&gt;old&lt;/span&gt; file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../diffdisplaydialog.ui" line="56"/>
<source>Done</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>Lubuntu Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="25"/>
<source>0 package(s) will be updated. 0 of these updates are security-related.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="33"/>
<source>Packages</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="80"/>
<source>Install Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="91"/>
<source>Check for Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="98"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="53"/>
<source>To be installed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="56"/>
<source>To be upgraded</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="59"/>
<source>To be removed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="62"/>
<source>Held back (usually temporarily)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="73"/>
<source>%1 package(s) will be updated. %2 of these updates are security-related.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="139"/>
<source>Update installation complete.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Orchestrator</name>
<message>
<location filename="../orchestrator.cpp" line="38"/>
<source>Updates available!
%1 to upgrade, %2 to install, and %3 to remove.
Click the tray icon to install the updates.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
<name>ConffileHandlerDialog</name>
<message>
<location filename="../conffilehandlerdialog.ui" line="14"/>
<source>Configuration File Conflicts</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilehandlerdialog.ui" line="24"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some of the newly installed updates have updated configuration files. &lt;/p&gt;&lt;p&gt;Please choose what to do with these files.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilehandlerdialog.ui" line="81"/>
<source>Done</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ConffileWidget</name>
<message>
<location filename="../conffilewidget.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="20"/>
<source>Filename</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="40"/>
<source>Keep old</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="47"/>
<source>Replace with new</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../conffilewidget.ui" line="54"/>
<source>Show diff</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DiffDisplayDialog</name>
<message>
<location filename="../diffdisplaydialog.ui" line="14"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../diffdisplaydialog.ui" line="24"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Lines that start with a &amp;quot;+&amp;quot; only exist in the &lt;span style=&quot; font-weight:700;&quot;&gt;new&lt;/span&gt; file.&lt;/p&gt;&lt;p&gt;Lines that start with a &amp;quot;-&amp;quot; only exist in the &lt;span style=&quot; font-weight:700;&quot;&gt;old&lt;/span&gt; file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../diffdisplaydialog.ui" line="56"/>
<source>Done</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="14"/>
<source>Lubuntu Update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="25"/>
<source>0 package(s) will be updated. 0 of these updates are security-related.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="33"/>
<source>Packages</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="80"/>
<source>Install Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="91"/>
<source>Check for Updates</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="98"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="53"/>
<source>To be installed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="56"/>
<source>To be upgraded</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="59"/>
<source>To be removed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="62"/>
<source>Held back (usually temporarily)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="73"/>
<source>%1 package(s) will be updated. %2 of these updates are security-related.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="139"/>
<source>Update installation complete.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Orchestrator</name>
<message>
<location filename="../orchestrator.cpp" line="38"/>
<source>Updates available!
%1 to upgrade, %2 to install, and %3 to remove.
Click the tray icon to install the updates.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US"></TS>
Loading…
Cancel
Save