[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kcm-grub2] /: *ADDED: Translation support for the GRUB menu.
From: Konstantinos Smanis <konstantinos.smanis () gmail ! com>
Date: 2013-10-24 12:09:37
Message-ID: E1VZJjN-0005XQ-Rb () scm ! kde ! org
[Download RAW message or body]
Git commit bc64b83fb19171a2cf3d420304c612f192a29c5f by Konstantinos Smanis.
Committed on 24/10/2013 at 11:47.
Pushed by ksmanis into branch 'master'.
*ADDED: Translation support for the GRUB menu.
There are two translatable points in GRUB:
1. The GRUB menu which is shown when booting. To be more specific, this
includes /only/ the instructions shown below the rectangular frame
containing the menu. This translation is triggered with a
'set lang=foobar' command in the GRUB menu file (/boot/grub/grub.cfg
by default), where foobar is a translation catalog (*.mo) contained
in the GRUB locale dir (/boot/grub/locale by default). The above
command is usually generated by scripts in the /etc/grub.d/
directory which process the 'LANG' [environment] variable.
2. The strings found in the GRUB menu file. To be more specific, this
includes entries' titles, echo commands etc. These strings are
generated by grub-mkconfig. This translation is triggered with the
'LANGUAGE' [environment] variable.
The above variables can be either set in the environment running
grub-mkconfig or in GRUB's configuration file (/etc/default/grub by
default) for a more permanent effect.
Unfortunately, after extensive testing in various distributions (Debian,
Kubuntu, Fedora, openSUSE) there are some limitations concerning the
use of these variables:
1. LANGUAGE should be set exclusively from the list of translation
catalogs in GRUB's locale dir.
2. LANG should be set exclusively from the list of locales as returned
by 'locale -a'.
If LANG is not an available locale, LANGUAGE will be cancelled out. So,
in order for a full translation of the GRUB boot menu, we set LANGUAGE
to a proper locale, use the user's current locale as LANG (it will be
later manually overwritten so we don't mind; we just want a locale that
truely exists) and finally 'set lang=' with the same locale we used in
LANGUAGE.
This is not a very clean solution, but up to this point this is the best
I could make out from this situation that could work on as many distros
as possible. If anyone has more information on this, please let me know.
M +4 -0 cmake/modules/GRUBPaths.cmake
M +1 -0 config.h.cmake
M +2 -1 src/common.h
M +39 -0 src/helper/helper.cpp
M +1 -0 src/helper/helper.h
M +51 -2 src/kcm_grub2.cpp
M +4 -0 src/kcm_grub2.h
M +70 -56 ui/kcm_grub2.ui
http://commits.kde.org/kcm-grub2/bc64b83fb19171a2cf3d420304c612f192a29c5f
diff --git a/cmake/modules/GRUBPaths.cmake b/cmake/modules/GRUBPaths.cmake
index 7c30e1d..1ab4b6d 100644
--- a/cmake/modules/GRUBPaths.cmake
+++ b/cmake/modules/GRUBPaths.cmake
@@ -10,6 +10,7 @@ elseif(NOT (GRUB_INSTALL_EXE OR GRUB_MKCONFIG_EXE OR GRUB_PROBE_EXE OR GRUB_SET_
set(GRUB_CONFIG "/etc/default/grub" CACHE FILEPATH "GRUB configuration file path.")
set(GRUB_ENV "/boot/grub/grubenv" CACHE FILEPATH "GRUB environment file path.")
set(GRUB_MEMTEST "/etc/grub.d/20_memtest86+" CACHE FILEPATH "GRUB memtest file path.")
+ set(GRUB_LOCALE "/boot/grub/locale/" CACHE PATH "GRUB locale path.")
else(GRUB_INSTALL_EXE AND GRUB_MKCONFIG_EXE AND GRUB_PROBE_EXE AND GRUB_SET_DEFAULT_EXE)
unset(GRUB_INSTALL_EXE CACHE)
unset(GRUB_MKCONFIG_EXE CACHE)
@@ -24,6 +25,7 @@ elseif(NOT (GRUB_INSTALL_EXE OR GRUB_MKCONFIG_EXE OR GRUB_PROBE_EXE OR GRUB_SET_
set(GRUB_CONFIG "/etc/default/grub" CACHE FILEPATH "GRUB configuration file path.")
set(GRUB_ENV "/boot/grub2/grubenv" CACHE FILEPATH "GRUB environment file path.")
set(GRUB_MEMTEST "/etc/grub.d/20_memtest86+" CACHE FILEPATH "GRUB memtest file path.")
+ set(GRUB_LOCALE "/boot/grub2/locale/" CACHE PATH "GRUB locale path.")
else(GRUB_INSTALL_EXE AND GRUB_MKCONFIG_EXE AND GRUB_PROBE_EXE AND GRUB_SET_DEFAULT_EXE)
unset(GRUB_INSTALL_EXE CACHE)
unset(GRUB_MKCONFIG_EXE CACHE)
@@ -38,6 +40,7 @@ elseif(NOT (GRUB_INSTALL_EXE OR GRUB_MKCONFIG_EXE OR GRUB_PROBE_EXE OR GRUB_SET_
set(GRUB_CONFIG "/etc/default/burg" CACHE FILEPATH "GRUB configuration file path.")
set(GRUB_ENV "/boot/burg/burgenv" CACHE FILEPATH "GRUB environment file path.")
set(GRUB_MEMTEST "/etc/burg.d/20_memtest86+" CACHE FILEPATH "GRUB memtest file path.")
+ set(GRUB_LOCALE "/boot/burg/locale/" CACHE PATH "GRUB locale path.")
else(GRUB_INSTALL_EXE AND GRUB_MKCONFIG_EXE AND GRUB_PROBE_EXE AND GRUB_SET_DEFAULT_EXE)
message(FATAL_ERROR "Could not automatically resolve GRUB paths. Please specify all of \
them manually.")
endif(GRUB_INSTALL_EXE AND GRUB_MKCONFIG_EXE AND GRUB_PROBE_EXE AND GRUB_SET_DEFAULT_EXE)
@@ -56,4 +59,5 @@ message(STATUS "GRUB_MENU: ${GRUB_MENU}")
message(STATUS "GRUB_CONFIG: ${GRUB_CONFIG}")
message(STATUS "GRUB_ENV: ${GRUB_ENV}")
message(STATUS "GRUB_MEMTEST: ${GRUB_MEMTEST}")
+message(STATUS "GRUB_LOCALE: ${GRUB_LOCALE}")
message(STATUS "--------------------------------------------------------------------------")
diff --git a/config.h.cmake b/config.h.cmake
index 2270142..f5db630 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -17,5 +17,6 @@
#define GRUB_CONFIG "@GRUB_CONFIG@"
#define GRUB_ENV "@GRUB_ENV@"
#define GRUB_MEMTEST "@GRUB_MEMTEST@"
+#define GRUB_LOCALE "@GRUB_LOCALE@"
#endif
diff --git a/src/common.h b/src/common.h
index 153d876..92412da 100644
--- a/src/common.h
+++ b/src/common.h
@@ -27,7 +27,8 @@ enum LoadOperation {
ConfigurationFile = 0x2,
EnvironmentFile = 0x4,
MemtestFile = 0x8,
- Vbe = 0x10
+ Vbe = 0x10,
+ Locales = 0x20
};
Q_DECLARE_FLAGS(LoadOperations, LoadOperation)
Q_DECLARE_OPERATORS_FOR_FLAGS(LoadOperations)
diff --git a/src/helper/helper.cpp b/src/helper/helper.cpp
index a40f879..34cb3a7 100644
--- a/src/helper/helper.cpp
+++ b/src/helper/helper.cpp
@@ -67,6 +67,33 @@ ActionReply Helper::executeCommand(const QStringList &command)
reply.addData("output", process.readAll());
return reply;
}
+bool Helper::setLang(const QString &lang)
+{
+ QFile file(GRUB_MENU);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ kError() << "Failed to open file for reading:" << GRUB_MENU;
+ kError() << "Error code:" << file.error();
+ kError() << "Error description:" << file.errorString();
+ return false;
+ }
+ QString fileContents = QString::fromUtf8(file.readAll().constData());
+ file.close();
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ kError() << "Failed to open file for writing:" << GRUB_MENU;
+ kError() << "Error code:" << file.error();
+ kError() << "Error description:" << file.errorString();
+ return false;
+ }
+ fileContents.replace(QRegExp(QLatin1String("(\\n\\s*set\\s+lang=)\\S*\\n")), \
QString(QLatin1String("\\1%1\n")).arg(lang)); + if (file.write(fileContents.toUtf8()) == -1) {
+ kError() << "Failed to write data to file:" << GRUB_MENU;
+ kError() << "Error code:" << file.error();
+ kError() << "Error description:" << file.errorString();
+ return false;
+ }
+ file.close();
+ return true;
+}
ActionReply Helper::defaults(QVariantMap args)
{
@@ -182,6 +209,9 @@ ActionReply Helper::load(QVariantMap args)
reply.addData("gfxmodes", gfxmodes);
}
#endif
+ if (operations.testFlag(Locales)) {
+ reply.addData(QLatin1String("locales"), QDir(GRUB_LOCALE).entryList(QStringList() << \
QLatin1String("*.mo"), QDir::Files).replaceInStrings(QRegExp(QLatin1String("\\.mo$")), QString())); + \
} return reply;
}
ActionReply Helper::save(QVariantMap args)
@@ -213,10 +243,19 @@ ActionReply Helper::save(QVariantMap args)
QFile::setPermissions(GRUB_MEMTEST, permissions);
}
+ if (args.contains(QLatin1String("LANG"))) {
+ qputenv("LANG", args.value(QLatin1String("LANG")).toByteArray());
+ }
ActionReply grub_mkconfigReply = executeCommand(QStringList() << GRUB_MKCONFIG_EXE << "-o" << \
GRUB_MENU); if (grub_mkconfigReply.failed()) {
return grub_mkconfigReply;
}
+ if (args.contains(QLatin1String("LANGUAGE"))) {
+ if (!setLang(args.value(QLatin1String("LANGUAGE")).toString())) {
+ kError() << "An error occured while setting the language for the GRUB menu.";
+ kError() << "The GRUB menu will not be properly translated!";
+ }
+ }
ActionReply grub_set_defaultReply = executeCommand(QStringList() << GRUB_SET_DEFAULT_EXE << \
rawDefaultEntry); if (grub_set_defaultReply.failed()) {
diff --git a/src/helper/helper.h b/src/helper/helper.h
index 11e8935..e63b41f 100644
--- a/src/helper/helper.h
+++ b/src/helper/helper.h
@@ -29,6 +29,7 @@ public:
Helper();
private:
ActionReply executeCommand(const QStringList &command);
+ bool setLang(const QString &lang);
public Q_SLOTS:
ActionReply defaults(QVariantMap args);
ActionReply install(QVariantMap args);
diff --git a/src/kcm_grub2.cpp b/src/kcm_grub2.cpp
index 68a0ef9..87c7cc5 100644
--- a/src/kcm_grub2.cpp
+++ b/src/kcm_grub2.cpp
@@ -185,6 +185,13 @@ void KCMGRUB2::load()
kWarning() << "Invalid GRUB_TIMEOUT value";
}
+ showLocales();
+ int languageIndex = \
ui->kcombobox_language->findData(unquoteWord(m_settings.value(QLatin1String("LANGUAGE")))); + if \
(languageIndex != -1) { + ui->kcombobox_language->setCurrentIndex(languageIndex);
+ } else {
+ kWarning() << "Invalid LANGUAGE value";
+ }
ui->checkBox_recovery->setChecked(unquoteWord(m_settings.value("GRUB_DISABLE_RECOVERY")).compare("true") \
!= 0); ui->checkBox_memtest->setVisible(m_memtest);
ui->checkBox_memtest->setChecked(m_memtestOn);
@@ -305,6 +312,14 @@ void KCMGRUB2::save()
m_settings["GRUB_TIMEOUT"] = "-1";
}
}
+ if (m_dirtyBits.testBit(grubLocaleDirty)) {
+ int langIndex = ui->kcombobox_language->currentIndex();
+ if (langIndex > 0) {
+ m_settings[QLatin1String("LANGUAGE")] = \
ui->kcombobox_language->itemData(langIndex).toString(); + } else {
+ m_settings.remove(QLatin1String("LANGUAGE"));
+ }
+ }
if (m_dirtyBits.testBit(grubDisableRecoveryDirty)) {
if (ui->checkBox_recovery->isChecked()) {
m_settings.remove("GRUB_DISABLE_RECOVERY");
@@ -453,6 +468,10 @@ void KCMGRUB2::save()
saveAction.setHelperID("org.kde.kcontrol.kcmgrub2");
saveAction.addArgument("rawConfigFileContents", configFileContents.toLocal8Bit());
saveAction.addArgument("rawDefaultEntry", !m_entries.isEmpty() ? grubDefault : \
m_settings.value("GRUB_DEFAULT").toLocal8Bit()); + if (ui->kcombobox_language->currentIndex() > 0) {
+ saveAction.addArgument(QLatin1String("LANG"), qgetenv("LANG"));
+ saveAction.addArgument(QLatin1String("LANGUAGE"), m_settings.value(QLatin1String("LANGUAGE")));
+ }
if (m_dirtyBits.testBit(memtestDirty)) {
saveAction.addArgument("memtest", ui->checkBox_memtest->isChecked());
}
@@ -529,6 +548,11 @@ void KCMGRUB2::slotGrubTimeoutChanged()
m_dirtyBits.setBit(grubTimeoutDirty);
emit changed(true);
}
+void KCMGRUB2::slotGrubLanguageChanged()
+{
+ m_dirtyBits.setBit(grubLocaleDirty);
+ emit changed(true);
+}
void KCMGRUB2::slotGrubDisableRecoveryChanged()
{
m_dirtyBits.setBit(grubDisableRecoveryDirty);
@@ -880,6 +904,7 @@ void KCMGRUB2::setupConnections()
connect(ui->radioButton_timeout, SIGNAL(clicked(bool)), this, SLOT(slotGrubTimeoutChanged()));
connect(ui->spinBox_timeout, SIGNAL(valueChanged(int)), this, SLOT(slotGrubTimeoutChanged()));
+ connect(ui->kcombobox_language, SIGNAL(activated(int)), this, SLOT(slotGrubLanguageChanged()));
connect(ui->checkBox_recovery, SIGNAL(clicked(bool)), this, SLOT(slotGrubDisableRecoveryChanged()));
connect(ui->checkBox_memtest, SIGNAL(clicked(bool)), this, SLOT(slotMemtestChanged()));
connect(ui->checkBox_osProber, SIGNAL(clicked(bool)), this, SLOT(slotGrubDisableOsProberChanged()));
@@ -926,7 +951,7 @@ bool KCMGRUB2::readFile(const QString &fileName, QByteArray &fileContents)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- kDebug() << "Failed to read file:" << fileName;
+ kDebug() << "Failed to open file for reading:" << fileName;
kDebug() << "Error code:" << file.error();
kDebug() << "Error description:" << file.errorString();
kDebug() << "The helper will now attempt to read this file.";
@@ -964,6 +989,11 @@ void KCMGRUB2::readAll()
#if HAVE_HD
operations |= Vbe;
#endif
+ if (QFileInfo(GRUB_LOCALE).isReadable()) {
+ m_locales = QDir(GRUB_LOCALE).entryList(QStringList() << QLatin1String("*.mo"), \
QDir::Files).replaceInStrings(QRegExp(QLatin1String("\\.mo$")), QString()); + } else {
+ operations |= Locales;
+ }
if (operations) {
Action loadAction("org.kde.kcontrol.kcmgrub2.load");
@@ -1018,9 +1048,28 @@ void KCMGRUB2::readAll()
if (operations.testFlag(Vbe)) {
m_resolutions = reply.data().value(QLatin1String("gfxmodes")).toStringList();
}
+ if (operations.testFlag(Locales)) {
+ m_locales = reply.data().value(QLatin1String("locales")).toStringList();
+ }
}
}
+void KCMGRUB2::showLocales()
+{
+ ui->kcombobox_language->clear();
+ ui->kcombobox_language->addItem(i18nc("@item:inlistbox", "No translation"), QString());
+
+ Q_FOREACH(const QString &locale, m_locales) {
+ QString language = KGlobal::locale()->languageCodeToName(locale);
+ if (language.isEmpty()) {
+ language = KGlobal::locale()->languageCodeToName(locale.split('@').first());
+ if (language.isEmpty()) {
+ language = \
KGlobal::locale()->languageCodeToName(locale.split('@').first().split('_').first()); + }
+ }
+ ui->kcombobox_language->addItem(QString("%1 (%2)").arg(language, locale), locale);
+ }
+}
void KCMGRUB2::sortResolutions()
{
for (int i = 0; i < m_resolutions.size(); i++) {
@@ -1212,7 +1261,7 @@ void KCMGRUB2::parseSettings(const QString &config)
m_settings.clear();
while (!stream.atEnd()) {
line = stream.readLine().trimmed();
- if (line.startsWith(QLatin1String("GRUB_"))) {
+ if (line.contains(QRegExp(QLatin1String("^(GRUB_|LANGUAGE=)")))) {
m_settings[line.section('=', 0, 0)] = line.section('=', 1);
}
}
diff --git a/src/kcm_grub2.h b/src/kcm_grub2.h
index 014847f..92b39ab 100644
--- a/src/kcm_grub2.h
+++ b/src/kcm_grub2.h
@@ -56,6 +56,7 @@ private Q_SLOTS:
void slotGrubHiddenTimeoutQuietChanged();
void slotGrubTimeoutToggled(bool checked);
void slotGrubTimeoutChanged();
+ void slotGrubLanguageChanged();
void slotGrubDisableRecoveryChanged();
void slotMemtestChanged();
void slotGrubDisableOsProberChanged();
@@ -87,6 +88,7 @@ private:
bool readFile(const QString &fileName, QByteArray &fileContents);
void readAll();
+ void showLocales();
void sortResolutions();
void showResolutions();
@@ -103,6 +105,7 @@ private:
grubHiddenTimeoutDirty,
grubHiddenTimeoutQuietDirty,
grubTimeoutDirty,
+ grubLocaleDirty,
grubDisableRecoveryDirty,
memtestDirty,
grubDisableOsProberDirty,
@@ -132,6 +135,7 @@ private:
bool m_memtestOn;
QHash<QString, QString> m_devices;
QStringList m_resolutions;
+ QStringList m_locales;
};
#endif
diff --git a/ui/kcm_grub2.ui b/ui/kcm_grub2.ui
index 8a4bc41..1d84e8c 100644
--- a/ui/kcm_grub2.ui
+++ b/ui/kcm_grub2.ui
@@ -20,7 +20,48 @@
<attribute name="title">
<string comment="@title:tab Refers to settings.">General</string>
</attribute>
- <layout class="QGridLayout" name="gridLayout_5">
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="groupBox_default">
+ <property name="title">
+ <string comment="@title:group">Default Entry</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_default">
+ <property name="text">
+ <string comment="@label:listbox">Default Entry:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="KComboBox" name="kcombobox_default">
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="KPushButton" name="kpushbutton_remove">
+ <property name="text">
+ <string comment="@action:button">Remove Old Entries</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QCheckBox" name="checkBox_savedefault">
+ <property name="text">
+ <string comment="@option:check">The next booted entry will become default</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_timeout">
<property name="title">
@@ -153,40 +194,41 @@
</layout>
</widget>
</item>
- <item row="3" column="0">
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>43</height>
- </size>
- </property>
- </spacer>
- </item>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox_entries">
<property name="title">
<string comment="@title:group">Generated Entries</string>
</property>
- <layout class="QGridLayout" name="gridLayout_4">
+ <layout class="QFormLayout" name="formLayout_6">
<item row="0" column="0">
+ <widget class="QLabel" name="label_language">
+ <property name="text">
+ <string>Language:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="KComboBox" name="kcombobox_language">
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="checkBox_recovery">
<property name="text">
<string comment="@option:check">Generate recovery entries</string>
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="checkBox_memtest">
<property name="text">
<string comment="@option:check">Generate memtest entries</string>
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="checkBox_osProber">
<property name="text">
<string comment="@option:check">Probe for operating systems</string>
@@ -196,46 +238,18 @@
</layout>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QGroupBox" name="groupBox_default">
- <property name="title">
- <string comment="@title:group">Default Entry</string>
+ <item row="3" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
</property>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="label_default">
- <property name="text">
- <string comment="@label:listbox">Default Entry:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="KComboBox" name="kcombobox_default">
- <property name="sizeAdjustPolicy">
- <enum>QComboBox::AdjustToContents</enum>
- </property>
- </widget>
- </item>
- <item>
- <widget class="KPushButton" name="kpushbutton_remove">
- <property name="text">
- <string comment="@action:button">Remove Old Entries</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0" colspan="2">
- <widget class="QCheckBox" name="checkBox_savedefault">
- <property name="text">
- <string comment="@option:check">The next booted entry will become default</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>43</height>
+ </size>
+ </property>
+ </spacer>
</item>
</layout>
</widget>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic