summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPatrick Storz <eduard.braun2@gmx.de>2019-08-03 23:34:27 +0000
committerPatrick Storz <eduard.braun2@gmx.de>2019-08-31 14:50:38 +0000
commitea05ba3338bec1517826614f27935a36c3b0f0f8 (patch)
treedce3126f09fe834a6bf165031d28c607dba73327 /src
parentRemove unused "nopref" variant of effects (diff)
downloadinkscape-ea05ba3338bec1517826614f27935a36c3b0f0f8.tar.gz
inkscape-ea05ba3338bec1517826614f27935a36c3b0f0f8.zip
Implement "translationdomain" attribute for extensions
Will allow extensions to ship their own message catalog used for translation of the extension#s strings. Needs to be set on the root <inkscape-extension> element of the .inx Currently supported values: - unset: use default textdomain (which happens to be 'inkscape') - 'inkscape': use Inkscape's message catalog - 'none': disable translation for the extension's strings
Diffstat (limited to 'src')
-rw-r--r--src/extension/effect.cpp28
-rw-r--r--src/extension/extension.cpp39
-rw-r--r--src/extension/extension.h23
-rw-r--r--src/extension/input.cpp31
-rw-r--r--src/extension/input.h4
-rw-r--r--src/extension/output.cpp31
-rw-r--r--src/extension/output.h4
-rw-r--r--src/extension/prefdialog/parameter.cpp8
-rw-r--r--src/extension/prefdialog/prefdialog.cpp4
-rw-r--r--src/ui/dialog/filedialogimpl-gtkmm.cpp10
-rw-r--r--src/ui/dialog/filedialogimpl-win32.cpp41
11 files changed, 140 insertions, 83 deletions
diff --git a/src/extension/effect.cpp b/src/extension/effect.cpp
index a38c3022a..a9088f88d 100644
--- a/src/extension/effect.cpp
+++ b/src/extension/effect.cpp
@@ -105,8 +105,8 @@ Effect::Effect (Inkscape::XML::Node * in_repr, Implementation::Implementation *
if (!hidden) {
if (_filters_list &&
- local_effects_menu &&
- local_effects_menu->attribute("name") &&
+ local_effects_menu &&
+ local_effects_menu->attribute("name") &&
!strcmp(local_effects_menu->attribute("name"), ("Filters"))) {
merge_menu(_filters_list->parent(), _filters_list, local_effects_menu->firstChild(), _menu_node);
} else if (_effects_list) {
@@ -127,24 +127,25 @@ Effect::merge_menu (Inkscape::XML::Node * base,
Inkscape::XML::Node * tomerge = nullptr;
Inkscape::XML::Node * submenu = nullptr;
- /* printf("Merge menu with '%s' '%s' '%s'\n",
- base != NULL ? base->name() : "NULL",
- pattern != NULL ? pattern->name() : "NULL",
- merge != NULL ? merge->name() : "NULL"); */
-
if (pattern == nullptr) {
// Merge the verb name
tomerge = merge;
- mergename = _(this->get_name());
+ mergename = get_translation(get_name());
} else {
- gchar const * menuname = pattern->attribute("name");
+ gchar const *menuname = pattern->attribute("name");
if (menuname == nullptr) menuname = pattern->attribute("_name");
if (menuname == nullptr) return;
-
+
Inkscape::XML::Document *xml_doc;
xml_doc = base->document();
tomerge = xml_doc->createElement("submenu");
- mergename = _(menuname);
+ if (_translation_enabled) {
+ mergename = get_translation(menuname);
+ } else {
+ // Even if the extension author requested the extension not to be translated,
+ // it still seems desirable to be able to put the extension into the existing (translated) submenus.
+ mergename = _(menuname);
+ }
tomerge->setAttribute("name", mergename, false);
}
@@ -247,7 +248,8 @@ Effect::prefs (Inkscape::UI::View::View * doc)
set_state(Extension::STATE_LOADED);
if (!loaded()) return false;
- _prefDialog = new PrefDialog(this->get_name(), nullptr, this);
+ Glib::ustring name = get_translation(this->get_name());
+ _prefDialog = new PrefDialog(name, nullptr, this);
_prefDialog->show();
return true;
@@ -286,7 +288,7 @@ Effect::effect (Inkscape::UI::View::View * doc)
/** \brief Sets which effect was called last
\param in_effect The effect that has been called
-
+
This function sets the static variable \c _last_effect and it
ensures that the last effect verb is sensitive.
diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp
index 85ea99ca8..05a5f4402 100644
--- a/src/extension/extension.cpp
+++ b/src/extension/extension.cpp
@@ -64,6 +64,17 @@ Extension::Extension (Inkscape::XML::Node *in_repr, Implementation::Implementati
imp = in_imp;
}
+ // get name of the translation catalog ("gettext textdomain") that the extension wants to use for translations
+ const char *translationdomain = repr->attribute("translationdomain");
+ if (translationdomain) {
+ _translationdomain = g_strdup(translationdomain);
+
+ // special keyword "none" means the extension author does not want translation of extension strings
+ if (!strcmp(translationdomain, "none")) {
+ _translation_enabled = false;
+ }
+ }
+
// Read XML tree and parse extension
Inkscape::XML::Node *child_repr = repr->firstChild();
while (child_repr) {
@@ -119,8 +130,6 @@ Extension::Extension (Inkscape::XML::Node *in_repr, Implementation::Implementati
throw extension_no_name();
}
db.register_ext (this);
-
- timer = nullptr;
}
/**
@@ -372,6 +381,30 @@ Extension::deactivated ()
return get_state() == STATE_DEACTIVATED;
}
+/** Gets a translation within the context of the current extension
+ *
+ * Query gettext for the translated version of the input string,
+ * handling the preferred translation domain of the extension internally.
+ *
+ * @param msgid String to translate
+ * @param msgctxt Context for the translation
+ *
+ * @return Translated string (or original string if extension is not supposed to be translated)
+ */
+const char *Extension::get_translation(const char *msgid, const char *msgctxt) {
+ if (!_translation_enabled) {
+ return msgid;
+ }
+
+ // Note: _translationdomain might be NULL, which is fine.
+ // We will simply default to the domain set via textdomain() in this case (which should be 'inkscape')
+ if (msgctxt) {
+ return g_dpgettext2(_translationdomain, msgctxt, msgid);
+ } else {
+ return g_dgettext(_translationdomain, msgid);
+ }
+}
+
Parameter *Extension::get_param(const gchar *name)
{
if (name == nullptr) {
@@ -746,7 +779,7 @@ Extension::get_info_widget()
info->add(*table);
int row = 0;
- add_val(_("Name:"), _(_name), table, &row);
+ add_val(_("Name:"), get_translation(_name), table, &row);
add_val(_("ID:"), _id, table, &row);
add_val(_("State:"), _state == STATE_LOADED ? _("Loaded") : _state == STATE_UNLOADED ? _("Unloaded") : _("Deactivated"), table, &row);
diff --git a/src/extension/extension.h b/src/extension/extension.h
index 23396fc27..c09fec3a5 100644
--- a/src/extension/extension.h
+++ b/src/extension/extension.h
@@ -99,18 +99,22 @@ public:
};
private:
- gchar *_id = nullptr; /**< The unique identifier for the Extension */
- gchar *_name = nullptr; /**< A user friendly name for the Extension */
- state_t _state = STATE_UNLOADED; /**< Which state the Extension is currently in */
- std::vector<Dependency *> _deps; /**< Dependencies for this extension */
- static std::ofstream error_file; /**< This is the place where errors get reported */
+ gchar *_id = nullptr; /**< The unique identifier for the Extension */
+ gchar *_name = nullptr; /**< A user friendly name for the Extension */
+ state_t _state = STATE_UNLOADED; /**< Which state the Extension is currently in */
+ std::vector<Dependency *> _deps; /**< Dependencies for this extension */
+ static std::ofstream error_file; /**< This is the place where errors get reported */
bool _gui;
protected:
- Inkscape::XML::Node *repr; /**< The XML description of the Extension */
- Implementation::Implementation * imp; /**< An object that holds all the functions for making this work */
- ExecutionEnv * execution_env; /**< Execution environment of the extension (currently only used by Effects) */
- ExpirationTimer * timer; /**< Timeout to unload after a given time */
+ Inkscape::XML::Node *repr; /**< The XML description of the Extension */
+ Implementation::Implementation * imp; /**< An object that holds all the functions for making this work */
+ ExecutionEnv * execution_env; /**< Execution environment of the extension
+ * (currently only used by Effects) */
+ ExpirationTimer * timer = nullptr; /**< Timeout to unload after a given time */
+ bool _translation_enabled = true; /**< Attempt translation of strings provided by the extension? */
+ const char *_translationdomain = nullptr; /**< Domainname of gettext textdomain that should
+ * be used for translation of the extension's strings */
public:
Extension (Inkscape::XML::Node * in_repr,
@@ -130,6 +134,7 @@ public:
Implementation::Implementation * get_imp () { return imp; };
void set_execution_env (ExecutionEnv * env) { execution_env = env; };
ExecutionEnv *get_execution_env () { return execution_env; };
+ const char *get_translation(const char* msgid, const char *msgctxt=nullptr);
/* Parameter Stuff */
private:
diff --git a/src/extension/input.cpp b/src/extension/input.cpp
index dd9485202..d28d8113a 100644
--- a/src/extension/input.cpp
+++ b/src/extension/input.cpp
@@ -182,23 +182,35 @@ Input::get_extension()
\return The name of the filetype supported
\brief Get the name of the filetype supported
*/
-gchar *
-Input::get_filetypename()
+const char *
+Input::get_filetypename(bool translated)
{
- if (filetypename != nullptr)
- return filetypename;
+ const char *name;
+
+ if (filetypename)
+ name = filetypename;
else
- return get_name();
+ name = get_name();
+
+ if (name && translated) {
+ return get_translation(name);
+ } else {
+ return name;
+ }
}
/**
\return Tooltip giving more information on the filetype
\brief Get the tooltip for more information on the filetype
*/
-gchar *
-Input::get_filetypetooltip()
+const char *
+Input::get_filetypetooltip(bool translated)
{
- return filetypetooltip;
+ if (filetypetooltip && translated) {
+ return get_translation(filetypetooltip);
+ } else {
+ return filetypetooltip;
+ }
}
/**
@@ -224,7 +236,8 @@ Input::prefs (const gchar *uri)
return true;
}
- PrefDialog * dialog = new PrefDialog(this->get_name(), controls);
+ Glib::ustring name = get_translation(this->get_name());
+ PrefDialog *dialog = new PrefDialog(name, controls);
int response = dialog->run();
dialog->hide();
diff --git a/src/extension/input.h b/src/extension/input.h
index 93b000388..6d5e8a2f3 100644
--- a/src/extension/input.h
+++ b/src/extension/input.h
@@ -51,8 +51,8 @@ public:
SPDocument * open (gchar const *uri);
gchar * get_mimetype ();
gchar * get_extension ();
- gchar * get_filetypename ();
- gchar * get_filetypetooltip ();
+ const char * get_filetypename (bool translated=false);
+ const char * get_filetypetooltip (bool translated=false);
bool prefs (gchar const *uri);
};
diff --git a/src/extension/output.cpp b/src/extension/output.cpp
index b4f483a91..05a0de997 100644
--- a/src/extension/output.cpp
+++ b/src/extension/output.cpp
@@ -148,23 +148,35 @@ Output::get_extension()
\return The name of the filetype supported
\brief Get the name of the filetype supported
*/
-gchar *
-Output::get_filetypename()
+const char *
+Output::get_filetypename(bool translated)
{
- if (filetypename != nullptr)
- return filetypename;
+ const char *name;
+
+ if (filetypename)
+ name = filetypename;
else
- return get_name();
+ name = get_name();
+
+ if (name && translated) {
+ return get_translation(name);
+ } else {
+ return name;
+ }
}
/**
\return Tooltip giving more information on the filetype
\brief Get the tooltip for more information on the filetype
*/
-gchar *
-Output::get_filetypetooltip()
+const char *
+Output::get_filetypetooltip(bool translated)
{
- return filetypetooltip;
+ if (filetypetooltip && translated) {
+ return get_translation(filetypetooltip);
+ } else {
+ return filetypetooltip;
+ }
}
/**
@@ -187,7 +199,8 @@ Output::prefs ()
return true;
}
- PrefDialog * dialog = new PrefDialog(this->get_name(), controls);
+ Glib::ustring title = get_translation(this->get_name());
+ PrefDialog *dialog = new PrefDialog(title, controls);
int response = dialog->run();
dialog->hide();
diff --git a/src/extension/output.h b/src/extension/output.h
index 5ce27a265..157a3f72d 100644
--- a/src/extension/output.h
+++ b/src/extension/output.h
@@ -48,8 +48,8 @@ public:
bool prefs ();
gchar * get_mimetype();
gchar * get_extension();
- gchar * get_filetypename();
- gchar * get_filetypetooltip();
+ const char * get_filetypename(bool translated=false);
+ const char * get_filetypetooltip(bool translated=false);
bool causes_dataloss() { return dataloss; };
};
diff --git a/src/extension/prefdialog/parameter.cpp b/src/extension/prefdialog/parameter.cpp
index 18d2a40ec..5716a3be8 100644
--- a/src/extension/prefdialog/parameter.cpp
+++ b/src/extension/prefdialog/parameter.cpp
@@ -325,13 +325,7 @@ Parameter *Parameter::get_param(const gchar */*name*/)
const char *Parameter::get_translation(const char* msgid) {
- // TODO: translation domain
-
- if (_context) {
- return g_dpgettext2(nullptr, _context, msgid);
- } else {
- return _(msgid);
- }
+ return _extension->get_translation(msgid, _context);
}
Glib::ustring const extension_pref_root = "/extensions/";
diff --git a/src/extension/prefdialog/prefdialog.cpp b/src/extension/prefdialog/prefdialog.cpp
index 17deb7a20..a1966ec8d 100644
--- a/src/extension/prefdialog/prefdialog.cpp
+++ b/src/extension/prefdialog/prefdialog.cpp
@@ -35,7 +35,7 @@ namespace Extension {
/** \brief Creates a new preference dialog for extension preferences
- \param name Name of the Extension whose dialog this is
+ \param name Name of the Extension whose dialog this is (should already be translated)
\param controls The extension specific widgets in the dialog
This function initializes the dialog with the name of the extension
@@ -43,7 +43,7 @@ namespace Extension {
them. It also places the passed-in widgets into the dialog.
*/
PrefDialog::PrefDialog (Glib::ustring name, Gtk::Widget * controls, Effect * effect) :
- Gtk::Dialog(_(name.c_str()), true),
+ Gtk::Dialog(name, true),
_name(name),
_button_ok(nullptr),
_button_cancel(nullptr),
diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp
index de6b18489..5874cac19 100644
--- a/src/ui/dialog/filedialogimpl-gtkmm.cpp
+++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp
@@ -330,7 +330,7 @@ void FileOpenDialogImplGtk::createFilterMenu()
Glib::ustring extension = imod->get_extension();
fileDialogExtensionToPattern(upattern, extension);
- Glib::ustring uname(_(imod->get_filetypename()));
+ Glib::ustring uname(imod->get_filetypename(true));
auto filter = Gtk::FileFilter::create();
filter->set_name(uname);
@@ -624,10 +624,10 @@ void FileSaveDialogImplGtk::fileTypeChangedCallback()
auto filter = Gtk::FileFilter::create();
filter->add_pattern(type.pattern);
set_filter(filter);
-
+
if (fromCB) {
//do not update if called from a name change
- fromCB = false;
+ fromCB = false;
return;
}
@@ -642,7 +642,7 @@ void FileSaveDialogImplGtk::fileNameChanged() {
if (extension && Glib::ustring(dynamic_cast<Inkscape::Extension::Output *>(extension)->get_extension()).casefold() == ext ) return;
if (knownExtensions.find(ext) == knownExtensions.end()) return;
fromCB = true;
- fileTypeComboBox.set_active_text(_(knownExtensions[ext]->get_filetypename()));
+ fileTypeComboBox.set_active_text(knownExtensions[ext]->get_filetypename(true));
}
void FileSaveDialogImplGtk::addFileType(Glib::ustring name, Glib::ustring pattern)
@@ -672,7 +672,7 @@ void FileSaveDialogImplGtk::createFileTypeMenu()
continue;
FileType type;
- type.name = (_(omod->get_filetypename()));
+ type.name = omod->get_filetypename(true);
type.pattern = "*";
Glib::ustring extension = omod->get_extension();
knownExtensions.insert(std::pair<Glib::ustring, Inkscape::Extension::Output*>(extension.casefold(), omod));
diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp
index 3964091cc..bd66b2d40 100644
--- a/src/ui/dialog/filedialogimpl-win32.cpp
+++ b/src/ui/dialog/filedialogimpl-win32.cpp
@@ -247,7 +247,7 @@ void FileOpenDialogImplWin32::createFilterMenu()
int extension_index = 0;
int filter_length = 1;
-
+
if (dialogType == CUSTOM_TYPE) {
return;
}
@@ -281,13 +281,11 @@ void FileOpenDialogImplWin32::createFilterMenu()
if (imod->deactivated()) continue;
// Type
- filter.name = g_utf8_to_utf16(_(imod->get_filetypename()),
- -1, NULL, &filter.name_length, NULL);
+ filter.name = g_utf8_to_utf16(imod->get_filetypename(true), -1, NULL, &filter.name_length, NULL);
// Extension
const gchar *file_extension_name = imod->get_extension();
- filter.filter = g_utf8_to_utf16(file_extension_name,
- -1, NULL, &filter.filter_length, NULL);
+ filter.filter = g_utf8_to_utf16(file_extension_name, -1, NULL, &filter.filter_length, NULL);
filter.mod = imod;
filter_list.push_back(filter);
@@ -309,7 +307,7 @@ void FileOpenDialogImplWin32::createFilterMenu()
// I don't know of any other way to define "bitmap" formats other than by listing them
// if you change it here, do the same change in filedialogimpl-gtkmm
- if (
+ if (
strncmp("image/png", imod->get_mimetype(), 9)==0 ||
strncmp("image/jpeg", imod->get_mimetype(), 10)==0 ||
strncmp("image/gif", imod->get_mimetype(), 9)==0 ||
@@ -322,7 +320,7 @@ void FileOpenDialogImplWin32::createFilterMenu()
strncmp("image/tiff", imod->get_mimetype(), 10)==0 ||
strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 ||
strncmp("image/x-tga", imod->get_mimetype(), 11)==0 ||
- strncmp("image/x-pcx", imod->get_mimetype(), 11)==0
+ strncmp("image/x-pcx", imod->get_mimetype(), 11)==0
) {
if(all_bitmaps_filter.length() > 0)
all_bitmaps_filter += ";*";
@@ -396,12 +394,12 @@ void FileOpenDialogImplWin32::createFilterMenu()
const gchar *all_files_filter_name = _("All Files");
const gchar *all_exe_files_filter_name = _("All Executable Files");
-
+
// Calculate the amount of memory required
int filter_count = 2; // 2 - All Files and All Executable Files
-
+
_extension_map = new Inkscape::Extension::Extension*[filter_count];
-
+
// Filter Executable Files
all_exe_files.name = g_utf8_to_utf16(all_exe_files_filter_name,
-1, NULL, &all_exe_files.name_length, NULL);
@@ -417,14 +415,14 @@ void FileOpenDialogImplWin32::createFilterMenu()
all_files.filter_length = 0;
all_files.mod = NULL;
filter_list.push_front(all_files);
-
+
filter_length += all_files.name_length + 3 +
all_exe_files.filter_length +
all_exe_files.name_length + 3 +
1;
// Add 3 for 2*2 \0s and a *, and 1 for a trailing \0
}
-
+
_filter = new wchar_t[filter_length];
wchar_t *filterptr = _filter;
@@ -546,11 +544,11 @@ UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData);
SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData);
pImpl = reinterpret_cast<FileOpenDialogImplWin32*>(ofn->lCustData);
-
+
// Make the window a bit wider
RECT rcRect;
GetWindowRect(hParentWnd, &rcRect);
-
+
// Don't show the preview when opening executable files
if ( pImpl->dialogType == EXE_TYPES) {
MoveWindow(hParentWnd, rcRect.left, rcRect.top,
@@ -577,7 +575,7 @@ UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
TBADDBITMAP tbAddBitmap = {NULL, reinterpret_cast<UINT_PTR>(pImpl->_show_preview_button_bitmap)};
const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd,
TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap);
-
+
TBBUTTON tbButton;
memset(&tbButton, 0, sizeof(TBBUTTON));
@@ -604,7 +602,7 @@ UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL);
SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData);
}
-
+
pImpl->_mutex->unlock();
pImpl->layout_dialog();
@@ -727,7 +725,7 @@ LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg,
WCHAR* noFileText=(WCHAR*)g_utf8_to_utf16(_("No file selected"),
-1, NULL, NULL, NULL);
FillRect(dc, &rcClient, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1));
- DrawTextW(dc, noFileText, -1, &rcClient,
+ DrawTextW(dc, noFileText, -1, &rcClient,
DT_CENTER | DT_VCENTER | DT_NOPREFIX);
g_free(noFileText);
}
@@ -1592,7 +1590,7 @@ FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent,
size_t last_slash_index = udir.find_last_of( '\\' );
size_t last_period_index = udir.find_last_of( '.' );
if (last_period_index > last_slash_index) {
- myFilename = udir.substr(0, last_period_index );
+ myFilename = udir.substr(0, last_period_index );
}
}
@@ -1638,8 +1636,7 @@ void FileSaveDialogImplWin32::createFilterMenu()
knownExtensions.insert(std::pair<Glib::ustring, Inkscape::Extension::Output*>(Glib::ustring(filter_extension).casefold(), omod));
// Type
- filter.name = g_utf8_to_utf16(
- _(omod->get_filetypename()), -1, NULL, &filter.name_length, NULL);
+ filter.name = g_utf8_to_utf16(omod->get_filetypename(true), -1, NULL, &filter.name_length, NULL);
filter.mod = omod;
@@ -1705,7 +1702,7 @@ void FileSaveDialogImplWin32::addFileType(Glib::ustring name, Glib::ustring patt
-1, NULL, &all_exe_files.filter_length, NULL);
all_exe_files.mod = NULL;
filter_list.push_front(all_exe_files);
-
+
filter_length = all_exe_files.name_length + all_exe_files.filter_length + 3; // Add 3 for two \0s and a *
knownExtensions.insert(std::pair<Glib::ustring, Inkscape::Extension::Output*>(Glib::ustring(all_exe_files_filter).casefold(), NULL));
@@ -1883,7 +1880,7 @@ UINT_PTR CALLBACK FileSaveDialogImplWin32::GetSaveFileName_hookproc(
CW_USEDEFAULT, CW_USEDEFAULT, rCB1.left-rST.left, rST.bottom-rST.top,
hParentWnd, NULL, hInstance, NULL);
g_free(title_label_str);
-
+
if(pImpl->_title_label) {
if(dlgFont) SendMessage(pImpl->_title_label, WM_SETFONT, (WPARAM)dlgFont, MAKELPARAM(FALSE, 0));
SetWindowPos(pImpl->_title_label, NULL, rST.left-rROOT.left, rST.top+ydelta-rROOT.top,