Qt: Dynamic languages

- get language as soon as possible (before creating any Qt objects) to make all
  translations working
- dynamic list of supported languages
- runtime change of GUI language (no need to restart application)
- add flags icons support
- search for *.qm languages in buildin resources, then
  data dir called "languages" (main directory in sources or
  /usr/share/wireshark/languages), then user directory
  (UNIX: ~/.wireshark/languages); "languages" directory should contains
  files wireshark_xx.qm where xx is language code (en, en_GB, etc.),
  and optional xx.svg for flag icon
- try to fix some untranslated manually-created UI items
  (need manual reset text of those components)

Change-Id: I62ca8a8cddce47cec9dbcad6b0bd68b6cfd92229
Reviewed-on: https://code.wireshark.org/review/5041
Tested-by: Michal Labedzki <michal.labedzki@tieto.com>
Reviewed-by: Michal Labedzki <michal.labedzki@tieto.com>
This commit is contained in:
Michal Labedzki 2013-12-21 17:55:43 +01:00
parent 15e78de432
commit 5025bc258c
40 changed files with 603 additions and 154 deletions

View File

@ -216,16 +216,33 @@ http://www.parashift.com/c++-faq/mixing-c-and-cpp.html
3. Translations (i18n)
3.1 Make translation
Qt makes translating the Wireshark UI into different languages easy.
- Add your translation (ui/qt/wireshark_XX.ts) in ui/qt/Wireshark.pro, ui/qt/i18n.qrc,
ui/qt/Makefile.common and ui/qt/CMakeLists.txt .
- Add also in epan/prefs.c, in ui/qt/main.cpp add case in switch(prefs_p->gui_qt_language)
and in ui/qt/main_window_preferences_frame.ui (use qt-design) to add in prefs.
- Run "lupdate Wireshark.pro" to generate/update your translation file.
- Translate with Qt Linguist.
- Run "lrelease Wireshark.pro" to create/update wireshark_xx.qm file.
ui/qt/Makefile.common and ui/qt/CMakeLists.txt
- Please add flag (image) for your language in images/languages/XX.svg and image/languages/languages.qrc
- Run "lupdate ui/qt/Wireshark.pro" to generate/update your translation file.
or "lupdate ui/qt -ts ui/qt/wireshark_XX.ts" for specified translation
- Translate with Qt Linguist (in console: "linguist ui/qt/wireshark_XX.ts")
- Run "lrelease Wireshark.pro" or
"lrelease ui/qt/wireshark_XX.ts -qm ui/qt/wireshark_XX.qm" to create/update wireshark_XX.qm file.
- Push your translation to Gerrit for review ("git push").
Alternatively you can only put your QM and flag files in "languages" directory in
Wireshark user configuration directory (~/.wireshark/languages/ on unix)
More information about Qt Linguist
http://qt-project.org/doc/qt-4.8/linguist-manual.html
3.2 Developing
- Please avoid tr() in code, try add any strings in *.ui files; tr() on manually
created object (like QMenu) are not automatically retranslated, so you must
add a couple of code to manually translate them
NOTE: if your object life is short, so any time when your component needs to be shown
it is (re)created then it is ok to have tr() in code
- For creating submenu in context menu please follow solution from ui/qt/proto_tree.cpp
- Some new windows need also to override changeEvent() and do retranslateUi() like
summary_dialog.[ch] does

View File

@ -1261,18 +1261,6 @@ static const enum_val_t print_dest_vals[] = {
{ NULL, NULL, 0 }
};
static const enum_val_t gui_qt_language[] = {
{"Auto-Detect", "auto", 0},
{"English", "en", 1},
{"French", "fr", 2},
{"German", "de", 3},
{"Chinese", "zh_CN", 4},
{"Polish", "pl", 5},
{"Japanese", "ja_JP", 6},
{"Italian", "it", 7},
{NULL, NULL, -1}
};
static const enum_val_t st_sort_col_vals[] = {
{ "name", "Node name (topic/item)", ST_SORT_COL_NAME },
{ "count", "Item count", ST_SORT_COL_COUNT },
@ -2332,11 +2320,6 @@ prefs_register_modules(void)
10,
&prefs.gui_auto_scroll_percentage);
prefs_register_enum_preference(gui_module, "qt_language",
"Qt Language",
"Qt Language",
&prefs.gui_qt_language, gui_qt_language, FALSE);
/* User Interface : Layout */
gui_layout_module = prefs_register_subtree(gui_module, "Layout", "Layout", gui_layout_callback);
@ -2970,7 +2953,6 @@ pre_init_prefs(void)
prefs.gui_layout_content_1 = layout_pane_content_plist;
prefs.gui_layout_content_2 = layout_pane_content_pdetails;
prefs.gui_layout_content_3 = layout_pane_content_pbytes;
prefs.gui_qt_language = 0; /* (Auto-Detect) */
prefs.gui_packet_editor = FALSE;
prefs.col_list = NULL;

9
image/languages/de.svg Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="600" viewBox="0 0 50 30">
<desc>Flag of Germany</desc>
<rect id="black_stripe" width="50" height="30" y="0" x="0" fill="#000"/>
<rect id="red_stripe" width="50" height="20" y="10" x="0" fill="#D00"/>
<rect id="gold_stripe" width="50" height="10" y="20" x="0" fill="#FFCE00"/>
</svg>

After

Width:  |  Height:  |  Size: 503 B

10
image/languages/en.svg Normal file
View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 30" width="1200" height="600">
<clipPath id="t">
<path d="M30,15 h30 v15 z v15 h-30 z h-30 v-15 z v-15 h30 z"/>
</clipPath>
<path d="M0,0 v30 h60 v-30 z" fill="#00247d"/>
<path d="M0,0 L60,30 M60,0 L0,30" stroke="#fff" stroke-width="6"/>
<path d="M0,0 L60,30 M60,0 L0,30" clip-path="url(#t)" stroke="#cf142b" stroke-width="4"/>
<path d="M30,0 v30 M0,15 h60" stroke="#fff" stroke-width="10"/>
<path d="M30,0 v30 M0,15 h60" stroke="#cf142b" stroke-width="6"/>
</svg>

After

Width:  |  Height:  |  Size: 522 B

6
image/languages/fr.svg Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="700" viewBox="0 0 30 21">
<rect width="30" height="21" fill="#ED2939"/>
<rect width="20" height="21" fill="#fff"/>
<rect width="10" height="21" fill="#002395"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

6
image/languages/it.svg Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="1500" height="1000" viewBox="0 0 30 20">
<rect width="10" height="20" fill="#009246"/>
<rect width="10" height="20" x="10" fill="#fff"/>
<rect width="10" height="20" x="20" fill="#ce2b37"/>
</svg>

After

Width:  |  Height:  |  Size: 283 B

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600">
<rect fill="#a0a0a0" height="600" width="900"/>
<rect fill="#fff" x="6" y="6" width="888" height="588"/>
<circle fill="#be0026" cx="450" cy="300" r="180"/>
</svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@ -0,0 +1,11 @@
<RCC>
<qresource prefix="/languages">
<file>de.svg</file>
<file>en.svg</file>
<file>fr.svg</file>
<file>it.svg</file>
<file>ja_JP.svg</file>
<file>pl.svg</file>
<file>zh_CN.svg</file>
</qresource>
</RCC>

1
image/languages/pl.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="1280" height="800" id="Flag of Poland" viewBox="0 0 16 10"><rect width="16" height="10" fill="#fff"/><rect width="16" height="5" fill="#dc143c" y="5"/></svg>

After

Width:  |  Height:  |  Size: 243 B

15
image/languages/zh_CN.svg Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="1500" height="1000" viewBox="-5 -5 30 20">
<title>Flag of the People's Republic of China</title>
<rect fill="#de2910" x="-5" y="-5" width="30" height="20"/>
<defs>
<polygon id="s" points="0,-513674 301930,415571 -488533,-158734 488533,-158734 -301930,415571"
fill="#ffde00" transform="scale(0.0000019467600073)"/>
</defs>
<use xlink:href="#s" transform="scale(3)"/>
<use xlink:href="#s" transform="translate(5,-3) rotate(-120.963756)"/>
<use xlink:href="#s" transform="translate(7,-1) rotate(-98.130102)"/>
<use xlink:href="#s" transform="translate(7,2) rotate(-74.054604)"/>
<use xlink:href="#s" transform="translate(5,4) rotate(-51.3401917)"/>
</svg>

After

Width:  |  Height:  |  Size: 895 B

View File

@ -36,6 +36,7 @@ set(COMMON_UI_SRC
help_url.c
iface_lists.c
io_graph_item.c
language.c
packet_list_utils.c
persfilepath_opt.c
preference_utils.c

View File

@ -56,6 +56,7 @@ WIRESHARK_UI_SRC = \
follow.c \
iface_lists.c \
io_graph_item.c \
language.c \
help_url.c \
packet_list_utils.c \
persfilepath_opt.c \
@ -92,6 +93,7 @@ noinst_HEADERS = \
packet_list_utils.h \
iface_lists.h \
io_graph_item.h \
language.h \
main_statusbar.h \
persfilepath_opt.h \
preference_utils.h \

135
ui/language.c Normal file
View File

@ -0,0 +1,135 @@
/* language.c
* Language "preference" handling routines
* Copyright 2014, Michal Labedzki for Tieto Corporation
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdlib.h>
#include <errno.h>
#include <epan/epan.h>
#include <epan/prefs.h>
#include <epan/prefs-int.h>
#include <wsutil/filesystem.h>
#include <wsutil/file_util.h>
#include "ui/language.h"
#include "ui/simple_dialog.h"
#define LANGUAGE_FILE_NAME "language"
#define LANGUAGE_PREF_LANGUAGE "language"
char *language = NULL;
/* set one user's recent common file key/value pair */
static prefs_set_pref_e
read_language_pref(gchar *key, const gchar *value,
void *private_data _U_, gboolean return_range_errors _U_)
{
if (strcmp(key, LANGUAGE_PREF_LANGUAGE) == 0) {
if (language)
g_free(language);
if (!value || (value && !*value))
language = g_strdup("auto");
else
language = g_strdup(value);
}
return PREFS_SET_OK;
}
void
read_language_prefs(void)
{
char *rf_path;
FILE *rf;
rf_path = get_persconffile_path(LANGUAGE_FILE_NAME, FALSE);
if ((rf = ws_fopen(rf_path, "r")) != NULL) {
read_prefs_file(rf_path, rf, read_language_pref, NULL);
fclose(rf);
}
g_free(rf_path);
}
gboolean
write_language_prefs(void)
{
char *pf_dir_path;
char *rf_path;
FILE *rf;
/* To do:
* - Split output lines longer than MAX_VAL_LEN
* - Create a function for the preference directory check/creation
* so that duplication can be avoided with filter.c
*/
/* Create the directory that holds personal configuration files, if
necessary. */
if (create_persconffile_dir(&pf_dir_path) == -1) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Can't create directory\n\"%s\"\nfor language file: %s.", pf_dir_path,
g_strerror(errno));
g_free(pf_dir_path);
return FALSE;
}
rf_path = get_persconffile_path(LANGUAGE_FILE_NAME, FALSE);
if ((rf = ws_fopen(rf_path, "w")) == NULL) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Can't open recent file\n\"%s\": %s.", rf_path,
g_strerror(errno));
g_free(rf_path);
return FALSE;
}
g_free(rf_path);
fputs("# Language settings file for Wireshark " VERSION ".\n"
"#\n"
"# This file is regenerated each time Wireshark is quit.\n"
"# So be careful, if you want to make manual changes here.\n"
"\n", rf);
fprintf(rf, LANGUAGE_PREF_LANGUAGE ": %s\n", language);
fclose(rf);
return TRUE;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

53
ui/language.h Normal file
View File

@ -0,0 +1,53 @@
/* language.h
*
* Copyright 2014, Michal Labedzki for Tieto Corporation
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __LANGUAGE_H__
#define __LANGUAGE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern char *language;
extern void read_language_prefs(void);
extern int write_language_prefs(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* language.h */
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -280,6 +280,7 @@ endif()
set(WIRESHARK_QT_QRC
../../image/about.qrc
../../image/display_filter.qrc
../../image/languages/languages.qrc
../../image/layout.qrc
../../image/status.qrc
../../image/toolbar.qrc

View File

@ -261,6 +261,7 @@ MOC_SRC = $(MOC_HDRS:.h=.moc.cpp)
QRC_FILES = \
../../image/about.qrc \
../../image/display_filter.qrc \
../../image/languages/languages.qrc \
../../image/layout.qrc \
../../image/status.qrc \
../../image/toolbar.qrc \

View File

@ -496,6 +496,7 @@ win32 {
RESOURCES += \
../../image/about.qrc \
../../image/display_filter.qrc \
../../image/languages/languages.qrc \
../../image/layout.qrc \
../../image/status.qrc \
../../image/toolbar.qrc \

View File

@ -851,6 +851,22 @@ void CaptureInterfacesDialog::on_manage_clicked()
}
}
void CaptureInterfacesDialog::changeEvent(QEvent* event)
{
if (0 != event)
{
switch (event->type())
{
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
QDialog::changeEvent(event);
}
//
// InterfaceTreeItem
//

View File

@ -99,6 +99,7 @@ private slots:
void refreshInterfaceList();
void updateLocalInterfaces();
void on_browseButton_clicked();
void changeEvent(QEvent* event);
signals:
void startCapture();

View File

@ -327,6 +327,28 @@ void DisplayFilterEdit::displayFilterSuccess(bool success)
apply_button_->setEnabled(!success);
}
void DisplayFilterEdit::changeEvent(QEvent* event)
{
if (0 != event)
{
switch (event->type())
{
case QEvent::LanguageChange:
if (plain_) {
empty_filter_message_ = QString(tr("Enter a display filter %1")).
arg(UTF8_HORIZONTAL_ELLIPSIS);
} else {
empty_filter_message_ = QString(tr("Apply a display filter %1 <%2/>"))
.arg(UTF8_HORIZONTAL_ELLIPSIS).arg(DEFAULT_MODIFIER);
}
break;
default:
break;
}
}
SyntaxLineEdit::changeEvent(event);
}
/*
* Editor modelines
*

View File

@ -22,6 +22,7 @@
#ifndef DISPLAYFILTEREDIT_H
#define DISPLAYFILTEREDIT_H
#include <QEvent>
#include <QToolButton>
#include "syntax_line_edit.h"
@ -45,6 +46,7 @@ private slots:
void checkFilter(const QString &text);
void bookmarkClicked();
void clearFilter();
void changeEvent(QEvent* event);
private:
bool plain_;

View File

@ -101,6 +101,7 @@
#endif
#include "ui/console.h"
#include "ui/iface_lists.h"
#include "ui/language.h"
#include "ui/main_statusbar.h"
#include "ui/persfilepath_opt.h"
#include "ui/recent.h"
@ -141,7 +142,6 @@
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
#include <QTextCodec>
#endif
#include <QTranslator>
#include "conversation_dialog.h"
#include "endpoint_dialog.h"
@ -783,6 +783,13 @@ int main(int argc, char *argv[])
optind = optind_initial;
opterr = 1;
// Initialize our language
read_language_prefs();
locale = QString(language);
wsApp->loadLanguage(locale);
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Translator %s", locale.toStdString().c_str());
// Init the main window (and splash)
main_w = new(MainWindow);
main_w->show();
@ -884,46 +891,9 @@ int main(int argc, char *argv[])
}
splash_update(RA_PREFERENCES, NULL, NULL);
prefs_p = ws_app.readConfigurationFiles (&gdp_path, &dp_path);
// Initialize our language
/*TODO: Enhance... may be get the locale from the enum gui_qt_language */
switch(prefs_p->gui_qt_language){
case 1: /* English */
locale = "en";
break;
case 2: /* French */
locale = "fr";
break;
case 3: /* German */
locale = "de";
break;
case 4: /* Chinese */
locale = "zh_CN";
break;
case 5: /* Polish */
locale = "pl";
break;
case 6: /* Japanese */
locale = "ja_JP";
break;
case 7: /* Italian */
locale = "it";
break;
default: /* Auto-Detect */
locale = QLocale::system().name();
break;
}
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Translator %s", locale.toStdString().c_str());
QTranslator translator;
translator.load(QString(":/i18n/wireshark_") + locale);
wsApp->installTranslator(&translator);
QTranslator qtTranslator;
qtTranslator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
wsApp->installTranslator(&qtTranslator);
/* Now get our args */
while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {

View File

@ -248,6 +248,22 @@ void MainWelcome::resizeEvent(QResizeEvent *event)
QFrame::resizeEvent(event);
}
void MainWelcome::changeEvent(QEvent* event)
{
if (0 != event)
{
switch (event->type())
{
case QEvent::LanguageChange:
welcome_ui_->retranslateUi(this);
break;
default:
break;
}
}
QFrame::changeEvent(event);
}
/*
* Editor modelines
*

View File

@ -67,6 +67,7 @@ private slots:
void interfaceDoubleClicked(QTreeWidgetItem *item, int column);
void updateRecentFiles();
void openRecentItem(QListWidgetItem *item);
void changeEvent(QEvent* event);
};
#endif // MAIN_WELCOME_H

View File

@ -1765,19 +1765,24 @@ void MainWindow::updateForUnsavedChanges() {
void MainWindow::changeEvent(QEvent* event)
{
if(0 != event)
if (0 != event)
{
switch(event->type())
switch (event->type())
{
// this event is send if a translator is loaded
case QEvent::LanguageChange:
main_ui_->retranslateUi(this);
break;
case QEvent::LocaleChange:{
QString locale = QLocale::system().name();
locale.truncate(locale.lastIndexOf('_'));
wsApp->loadLanguage(locale);
}
break;
default:
break;
}
}
QMainWindow::changeEvent(event);
QMainWindow::changeEvent(event);
}
/* Update main window items based on whether there's a capture in progress. */

View File

@ -87,7 +87,7 @@ public:
protected:
bool eventFilter(QObject *obj, QEvent *event);
void keyPressEvent(QKeyEvent *event);
void closeEvent (QCloseEvent *event);
void closeEvent(QCloseEvent *event);
private:
// XXX Move to FilterUtils

View File

@ -2103,6 +2103,36 @@
<string>Show or hide the packet bytes</string>
</property>
</action>
<action name="actionFollow">
<property name="text">
<string>Follow...</string>
</property>
</action>
<action name="actionSCTP">
<property name="text">
<string>SCTP</string>
</property>
</action>
<action name="actionApply_as_Filter">
<property name="text">
<string>Apply as Filter</string>
</property>
</action>
<action name="actionPrepare_a_Filter">
<property name="text">
<string>Prepare a Filter</string>
</property>
</action>
<action name="actionCopy">
<property name="text">
<string>Copy</string>
</property>
</action>
<action name="actionBytes">
<property name="text">
<string>Bytes</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -19,10 +19,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "wireshark_application.h"
#include "main_window_preferences_frame.h"
#include "qt_ui_utils.h"
#include "ui_main_window_preferences_frame.h"
#include "ui/language.h"
#include <epan/prefs-int.h>
#include <wsutil/filesystem.h>
#include <QFileDialog>
#include <QDebug>
@ -45,7 +50,6 @@ MainWindowPreferencesFrame::MainWindowPreferencesFrame(QWidget *parent) :
pref_auto_scroll_percentage_ = prefFromPrefPtr(&prefs.gui_auto_scroll_percentage);
pref_toolbar_main_style_ = prefFromPrefPtr(&prefs.gui_toolbar_main_style);
pref_toolbar_filter_style_ = prefFromPrefPtr(&prefs.gui_toolbar_filter_style);
pref_qt_language_ = prefFromPrefPtr(&prefs.gui_qt_language);
QStyleOption style_opt;
QString indent_ss = QString(
@ -64,6 +68,44 @@ MainWindowPreferencesFrame::MainWindowPreferencesFrame(QWidget *parent) :
ui->maxFilterLineEdit->setMaximumWidth(num_entry_width);
ui->maxRecentLineEdit->setMaximumWidth(num_entry_width);
ui->autoScrollPercentageLineEdit->setMaximumWidth(num_entry_width);
QString globalLanguagesPath(QString(get_datafile_dir()) + "/languages/");
QString userLanguagesPath(gchar_free_to_qstring(get_persconffile_path("languages/", FALSE)));
QStringList filenames = QDir(":/i18n/").entryList(QStringList("wireshark_*.qm"));
filenames += QDir(globalLanguagesPath).entryList(QStringList("wireshark_*.qm"));
filenames += QDir(userLanguagesPath).entryList(QStringList("wireshark_*.qm"));
for (int i = 0; i < filenames.size(); i += 1) {
QString locale;
locale = filenames[i];
locale.truncate(locale.lastIndexOf('.'));
locale.remove(0, locale.indexOf('_') + 1);
QString lang = QLocale::languageToString(QLocale(locale).language());
QIcon ico = QIcon();
if (QFile::exists(QString(":/languages/%1.svg").arg(locale)))
ico.addFile(QString(":/languages/%1.svg").arg(locale));
if (QFile::exists(globalLanguagesPath + locale + ".svg"))
ico.addFile(globalLanguagesPath + locale + ".svg");
if (QFile::exists(userLanguagesPath + locale + ".svg"))
ico.addFile(userLanguagesPath + locale + ".svg");
ui->languageComboBox->addItem(ico, lang, locale);
}
ui->languageComboBox->setItemData(0, "auto");
ui->languageComboBox->model()->sort(0);
for (int i = 0; i < ui->languageComboBox->count(); i += 1) {
if (QString(language) == ui->languageComboBox->itemData(i).toString()) {
ui->languageComboBox->setCurrentIndex(i);
break;
}
}
}
MainWindowPreferencesFrame::~MainWindowPreferencesFrame()
@ -102,7 +144,14 @@ void MainWindowPreferencesFrame::updateWidgets()
ui->mainToolbarComboBox->setCurrentIndex(pref_toolbar_main_style_->stashed_val.enumval);
ui->filterToolbarComboBox->setCurrentIndex(pref_toolbar_filter_style_->stashed_val.enumval);
ui->languageComboBox->setCurrentIndex(pref_qt_language_->stashed_val.enumval);
QStringList filenames = QDir(":/i18n/").entryList(QStringList("wireshark_*.qm"));
for (int i = 0; i < ui->languageComboBox->count(); i += 1) {
if (QString(language) == ui->languageComboBox->itemData(i).toString()) {
ui->languageComboBox->setCurrentIndex(i);
break;
}
}
}
void MainWindowPreferencesFrame::on_geometryCheckBox_toggled(bool checked)
@ -186,7 +235,10 @@ void MainWindowPreferencesFrame::on_filterToolbarComboBox_currentIndexChanged(in
void MainWindowPreferencesFrame::on_languageComboBox_currentIndexChanged(int index)
{
pref_qt_language_->stashed_val.enumval = index;
if (language)
delete language;
language = strdup(ui->languageComboBox->itemData(index).toString().toStdString().c_str());
}
/*

View File

@ -56,7 +56,6 @@ private:
pref_t *pref_auto_scroll_percentage_;
pref_t *pref_toolbar_main_style_;
pref_t *pref_toolbar_filter_style_;
pref_t *pref_qt_language_;
void updateWidgets();
private slots:

View File

@ -312,51 +312,9 @@
</property>
<item>
<property name="text">
<string>Auto-Detect</string>
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>English</string>
</property>
</item>
<item>
<property name="text">
<string>Français</string>
</property>
</item>
<item>
<property name="text">
<string>Deutsch</string>
</property>
</item>
<item>
<property name="text">
<string>Chinese</string>
</property>
</item>
<item>
<property name="text">
<string>Polski</string>
</property>
</item>
<item>
<property name="text">
<string>Japanese</string>
</property>
</item>
<item>
<property name="text">
<string>Italiano</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>You need to restart Wireshark for this change to take effect</string>
</property>
</widget>
</item>
<item>
@ -389,7 +347,9 @@
</item>
</layout>
</widget>
<resources/>
<resources>
<include location="../../image/languages/languages.qrc"/>
</resources>
<connections/>
<buttongroups>
<buttongroup name="openInButtonGroup"/>

View File

@ -235,6 +235,7 @@ PacketList::PacketList(QWidget *parent) :
ctx_column_(-1)
{
QMenu *submenu, *subsubmenu;
QAction *action;
setItemsExpandable(false);
setRootIsDecorated(false);
@ -256,26 +257,36 @@ PacketList::PacketList(QWidget *parent) :
ctx_menu_.addAction(window()->findChild<QAction *>("actionEditPacketComment"));
ctx_menu_.addSeparator();
submenu = new QMenu(tr("Follow..."));
ctx_menu_.addMenu(submenu);
action = window()->findChild<QAction *>("actionFollow");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowTCPStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowUDPStream"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeFollowSSLStream"));
filter_actions_ << submenu->actions();
// " <menuitem name='FollowTCPStream' action='/Follow TCP Stream'/>\n"
// " <menuitem name='FollowUDPStream' action='/Follow UDP Stream'/>\n"
// " <menuitem name='FollowSSLStream' action='/Follow SSL Stream'/>\n"
submenu = new QMenu(tr("SCTP"));
action = window()->findChild<QAction *>("actionSCTP");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
ctx_menu_.addMenu(submenu);
submenu->addAction(window()->findChild<QAction *>("actionSCTPAnalyseThisAssociation"));
submenu->addAction(window()->findChild<QAction *>("actionSCTPShowAllAssociations"));
submenu->addAction(window()->findChild<QAction *>("actionSCTPFilterThisAssociation"));
filter_actions_ << submenu->actions();
ctx_menu_.addSeparator();
// " <menuitem name='ManuallyResolveAddress' action='/ManuallyResolveAddress'/>\n"
ctx_menu_.addSeparator();
submenu = new QMenu(tr("Apply as Filter"));
ctx_menu_.addMenu(submenu);
// ctx_menu_.addSeparator();
action = window()->findChild<QAction *>("actionApply_as_Filter");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndSelected"));
@ -283,8 +294,11 @@ PacketList::PacketList(QWidget *parent) :
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrNotSelected"));
filter_actions_ << submenu->actions();
submenu = new QMenu(tr("Prepare a Filter"));
ctx_menu_.addMenu(submenu);
action = window()->findChild<QAction *>("actionPrepare_a_Filter");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndSelected"));
@ -292,7 +306,11 @@ PacketList::PacketList(QWidget *parent) :
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrNotSelected"));
filter_actions_ << submenu->actions();
submenu = new QMenu(tr("Colorize with Filter"));
// action = window()->findChild<QAction *>("actionColorize_with_Filter");
// submenu = new QMenu();
// action->setMenu(submenu);
// ctx_menu_.addAction(action);
// " <menu name= 'ConversationFilter' action='/Conversation Filter'>\n"
// " <menuitem name='Ethernet' action='/Conversation Filter/Ethernet'/>\n"
// " <menuitem name='IP' action='/Conversation Filter/IP'/>\n"
@ -367,20 +385,25 @@ PacketList::PacketList(QWidget *parent) :
// " <menuitem name='FollowUDPStream' action='/Follow UDP Stream'/>\n"
// " <menuitem name='FollowSSLStream' action='/Follow SSL Stream'/>\n"
ctx_menu_.addSeparator();
// " <menu name= 'Copy' action='/Copy'>\n"
submenu = new QMenu(tr("Copy"));
ctx_menu_.addMenu(submenu);
action = window()->findChild<QAction *>("actionCopy");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
// " <menuitem name='SummaryTxt' action='/Copy/SummaryTxt'/>\n"
// " <menuitem name='SummaryCSV' action='/Copy/SummaryCSV'/>\n"
submenu->addAction(window()->findChild<QAction *>("actionEditCopyAsFilter"));
filter_actions_ << window()->findChild<QAction *>("actionEditCopyAsFilter");
submenu->addSeparator();
subsubmenu = new QMenu(tr("Bytes"));
submenu->addMenu(subsubmenu);
action = window()->findChild<QAction *>("actionBytes");
subsubmenu = new QMenu();
action->setMenu(subsubmenu);
submenu->addAction(action);
// " <menuitem name='OffsetHexText' action='/Copy/Bytes/OffsetHexText'/>\n"
// " <menuitem name='OffsetHex' action='/Copy/Bytes/OffsetHex'/>\n"
// " <menuitem name='PrintableTextOnly' action='/Copy/Bytes/PrintableTextOnly'/>\n"
ctx_menu_.addSeparator();
// ctx_menu_.addSeparator();
// " <menuitem name='HexStream' action='/Copy/Bytes/HexStream'/>\n"
// " <menuitem name='BinaryStream' action='/Copy/Bytes/BinaryStream'/>\n"
ctx_menu_.addSeparator();

View File

@ -31,8 +31,9 @@
#endif /* HAVE_LIBPCAP */
#include <epan/prefs-int.h>
#include <ui/language.h>
#include <ui/preference_utils.h>
#include <main_window.h>
#include "module_preferences_scroll_area.h"
#include "syntax_line_edit.h"
@ -797,6 +798,9 @@ void PreferencesDialog::on_buttonBox_accepted()
prefs_main_write();
write_language_prefs();
wsApp->loadLanguage(QString(language));
#ifdef HAVE_AIRPCAP
/*
* Load the Wireshark decryption keys (just set) and save

View File

@ -159,6 +159,7 @@ ProtoTree::ProtoTree(QWidget *parent) :
decode_as_(NULL)
{
QMenu *submenu, *subsubmenu;
QAction *action;
setAccessibleName(tr("Packet details"));
setUniformRowHeights(true);
@ -170,25 +171,32 @@ ProtoTree::ProtoTree(QWidget *parent) :
ctx_menu_.addAction(window()->findChild<QAction *>("actionViewCollapseAll"));
ctx_menu_.addSeparator();
// " <menuitem name='CreateAColumn' action='/Create a Column'/>\n"
ctx_menu_.addSeparator();
submenu = new QMenu(tr("Apply as Filter"));
ctx_menu_.addMenu(submenu);
action = window()->findChild<QAction *>("actionApply_as_Filter");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFAndNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzeAAFOrNotSelected"));
submenu = new QMenu(tr("Prepare a Filter"));
ctx_menu_.addMenu(submenu);
action = window()->findChild<QAction *>("actionPrepare_a_Filter");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFAndNotSelected"));
submenu->addAction(window()->findChild<QAction *>("actionAnalyzePAFOrNotSelected"));
submenu = new QMenu(tr("Colorize with Filter"));
ctx_menu_.addMenu(submenu);
// action = window()->findChild<QAction *>("actionColorize_with_Filter");
// submenu = new QMenu();
// action->setMenu(submenu);
// ctx_menu_.addAction(action);
// " <menuitem name='Color1' action='/Colorize with Filter/Color 1'/>\n"
// " <menuitem name='Color2' action='/Colorize with Filter/Color 2'/>\n"
// " <menuitem name='Color3' action='/Colorize with Filter/Color 3'/>\n"
@ -205,15 +213,21 @@ ProtoTree::ProtoTree(QWidget *parent) :
// " <menuitem name='FollowUDPStream' action='/Follow UDP Stream'/>\n"
// " <menuitem name='FollowSSLStream' action='/Follow SSL Stream'/>\n"
ctx_menu_.addSeparator();
submenu = new QMenu(tr("Copy"));
ctx_menu_.addMenu(submenu);
action = window()->findChild<QAction *>("actionCopy");
submenu = new QMenu();
action->setMenu(submenu);
ctx_menu_.addAction(action);
submenu->addAction(window()->findChild<QAction *>("actionEditCopyDescription"));
submenu->addAction(window()->findChild<QAction *>("actionEditCopyFieldName"));
submenu->addAction(window()->findChild<QAction *>("actionEditCopyValue"));
submenu->addSeparator();
submenu->addAction(window()->findChild<QAction *>("actionEditCopyAsFilter"));
subsubmenu = new QMenu(tr("Bytes"));
submenu->addMenu(subsubmenu);
action = window()->findChild<QAction *>("actionBytes");
subsubmenu = new QMenu();
action->setMenu(subsubmenu);
submenu->addAction(action);
subsubmenu->addSeparator();
// " <menu name= 'Bytes' action='/Copy/Bytes'>\n"
// " <menuitem name='OffsetHexText' action='/Copy/Bytes/OffsetHexText'/>\n"
@ -225,12 +239,12 @@ ProtoTree::ProtoTree(QWidget *parent) :
// " </menu>\n"
// " </menu>\n"
// " <menuitem name='ExportSelectedPacketBytes' action='/ExportSelectedPacketBytes'/>\n"
ctx_menu_.addSeparator();
// ctx_menu_.addSeparator();
// " <menuitem name='WikiProtocolPage' action='/WikiProtocolPage'/>\n"
// " <menuitem name='FilterFieldReference' action='/FilterFieldReference'/>\n"
// " <menuitem name='ProtocolHelp' action='/ProtocolHelp'/>\n"
// " <menuitem name='ProtocolPreferences' action='/ProtocolPreferences'/>\n"
ctx_menu_.addSeparator();
// ctx_menu_.addSeparator();
decode_as_ = window()->findChild<QAction *>("actionAnalyzeDecodeAs");
ctx_menu_.addAction(decode_as_);
// " <menuitem name='DisableProtocol' action='/DisableProtocol'/>\n"

View File

@ -44,9 +44,9 @@ protected:
void contextMenuEvent(QContextMenuEvent *event);
private:
QMenu ctx_menu_;
QAction *decode_as_;
QFont mono_font_;
QMenu ctx_menu_;
QAction *decode_as_;
QFont mono_font_;
signals:
void protoItemSelected(QString &);

View File

@ -340,6 +340,22 @@ void SearchFrame::on_cancelButton_clicked()
animatedHide();
}
void SearchFrame::changeEvent(QEvent* event)
{
if (0 != event)
{
switch (event->type())
{
case QEvent::LanguageChange:
sf_ui_->retranslateUi(this);
break;
default:
break;
}
}
AccordionFrame::changeEvent(event);
}
/*
* Editor modelines
*

View File

@ -61,12 +61,10 @@ private:
private slots:
void on_searchTypeComboBox_currentIndexChanged(int index);
void on_searchLineEdit_textChanged(const QString &search_string);
void on_findButton_clicked();
void on_cancelButton_clicked();
void changeEvent(QEvent* event);
};
#endif // SEARCH_FRAME_H

View File

@ -744,6 +744,22 @@ SummaryDialog::~SummaryDialog()
delete ui;
}
void SummaryDialog::changeEvent(QEvent* event)
{
if (0 != event)
{
switch (event->type())
{
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
QDialog::changeEvent(event);
}
/*
* Editor modelines

View File

@ -73,6 +73,7 @@ protected slots:
void HelpButton();
void CopyComment();
void on_tabWidget_currentChanged(int index);
void changeEvent(QEvent* event);
private:

View File

@ -61,6 +61,8 @@
#include <QEvent>
#include <QFileOpenEvent>
#include <QFontMetrics>
#include <QLibraryInfo>
#include <QLocale>
#include <QMutableListIterator>
#include <QTimer>
#include <QUrl>
@ -570,6 +572,7 @@ WiresharkApplication::WiresharkApplication(int &argc, char **argv) :
Q_INIT_RESOURCE(status);
Q_INIT_RESOURCE(toolbar);
Q_INIT_RESOURCE(wsicon);
Q_INIT_RESOURCE(languages);
#ifdef Q_OS_WIN
/* RichEd20.DLL is needed for native file dialog filter entries. */
@ -866,6 +869,43 @@ void WiresharkApplication::addRecentItem(const QString &filename, qint64 size, b
itemStatusFinished(filename, size, accessible);
}
static void switchTranslator(QTranslator& myTranslator, const QString& filename,
const QString& searchPath)
{
wsApp->removeTranslator(&myTranslator);
if (myTranslator.load(filename, searchPath))
wsApp->installTranslator(&myTranslator);
}
void WiresharkApplication::loadLanguage(const QString& newLanguage)
{
QLocale locale;
QString localeLanguage;
if (newLanguage.isEmpty() || newLanguage == "auto") {
localeLanguage = QLocale::system().name();
} else {
localeLanguage = newLanguage;
}
locale = QLocale(localeLanguage);
QLocale::setDefault(locale);
switchTranslator(wsApp->translator,
QString("wireshark_%1.qm").arg(localeLanguage), QString(":/i18n/"));
if (QFile::exists(QString("%1/%2/wireshark_%3.qm")
.arg(get_datafile_dir()).arg("languages").arg(localeLanguage)))
switchTranslator(wsApp->translator,
QString("wireshark_%1.qm").arg(localeLanguage), QString(get_datafile_dir()) + QString("/languages"));
if (QFile::exists(QString("%1/wireshark_%3.qm")
.arg(gchar_free_to_qstring(get_persconffile_path("languages", FALSE))).arg(localeLanguage)))
switchTranslator(wsApp->translator,
QString("wireshark_%1.qm").arg(localeLanguage), gchar_free_to_qstring(get_persconffile_path("languages", FALSE)));
switchTranslator(wsApp->translatorQt,
QString("qt_%1.qm").arg(localeLanguage),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
}
/*
* Editor modelines
*

View File

@ -43,6 +43,8 @@
#include <QSocketNotifier>
#include <QThread>
#include <QTimer>
#include <QTranslator>
// Recent items:
// - Read from prefs
@ -93,6 +95,10 @@ public:
const QIcon &normalIcon() const { return normal_icon_; }
const QIcon &captureIcon() const { return capture_icon_; }
QTranslator translator;
QTranslator translatorQt;
void loadLanguage(const QString& language);
private:
bool initialized_;
QFont mono_font_;