mirror of https://github.com/GNOME/gimp.git
libgimp: add a new set_i18n() method to GimpPlugIn class.
Clearly the old logic for localizing plug-ins was "core plug-ins first": * In particular, we were defaulting to the "gimp*-std-plugins" domain, asking plug-ins to override it with libgimp function gimp_plug_in_set_translation_domain(). Obviously any third-party plug-in would have to call this function since their strings are most likely not the same as GIMP core plug-ins. * Moreover this was only for the localization of menu items, which means we had to duplicate work anyway (simplified for core C plug-ins only with the INIT_I18N macro). * Also plug-ins had to manage the location of the Gettext catalogs, which is simpler for core plug-ins with gimp_locale_directory(), but more annoying for third-party plug-ins which can be installed basically anywhere (assuming their message catalogs are in their directory, not centrally installed on the system, especially for non-UNIX-like packages, with relocatable GIMP, no central package system and so on). * Finally in this logic of centrally installed catalogs, we were requesting that the domain name is unique, which makes sense in a Linux world with well maintained packages to avoid name clashes, not in a world with people making plug-ins without knowing too much what's done by their neighbour. So now the new logic is: - By default, GIMP will search for a folder called locale/ on the same level as the plug-in executable. The Gettext domain will be the name of the executable folder (and it doesn't matter too much if it's not unique in such configuration). - This can be disabled by overriding set_i18n() to NULL or reimplementing it. All our core plug-ins will do this since they will continue to use the centrally installed "gimp*-std-plugins" domain (or "gimp*-python" for Python plug-ins). - When not disabled while the folder is not available, warning messages will be outputted to stderr, so that plug-in developers can easily detect what is missing and how to handle it (and how to easily support internationalization of their plug-in). - gimp_plug_in_set_translation_domain() is removed and a future commit is going to get rid of _gimp_plug_in_domain_register() because we are going to get rid of the core-side localization of menu items (with logic explained in the upcoming commit).
This commit is contained in:
parent
208d415a1a
commit
4b9d8a56cb
|
@ -704,7 +704,6 @@ EXPORTS
|
|||
gimp_plug_in_remove_temp_procedure
|
||||
gimp_plug_in_set_help_domain
|
||||
gimp_plug_in_set_pdb_error_handler
|
||||
gimp_plug_in_set_translation_domain
|
||||
gimp_procedure_add_argument
|
||||
gimp_procedure_add_argument_from_property
|
||||
gimp_procedure_add_aux_argument
|
||||
|
|
|
@ -37,6 +37,11 @@ void _gimp_plug_in_read_expect_msg (GimpPlugIn *plug_in,
|
|||
GimpWireMessage *msg,
|
||||
gint type);
|
||||
|
||||
gboolean _gimp_plug_in_set_i18n (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name,
|
||||
gchar **gettext_domain,
|
||||
gchar **catalog_dir);
|
||||
|
||||
GimpProcedure * _gimp_plug_in_create_procedure (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gimp.h"
|
||||
|
@ -166,6 +167,11 @@ static void gimp_plug_in_get_property (GObject *object,
|
|||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gboolean gimp_plug_in_real_set_i18n (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name,
|
||||
gchar **gettext_domain,
|
||||
gchar **catalog_dir);
|
||||
|
||||
static void gimp_plug_in_register (GimpPlugIn *plug_in,
|
||||
GList *procedures);
|
||||
|
||||
|
@ -203,6 +209,8 @@ static void gimp_plug_in_destroy_hashes (GimpPlugIn *plug_in);
|
|||
static void gimp_plug_in_destroy_proxies (GHashTable *hash_table,
|
||||
gboolean destroy_all);
|
||||
|
||||
static void gimp_plug_in_init_i18n (GimpPlugIn *plug_in);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GimpPlugIn, gimp_plug_in, G_TYPE_OBJECT)
|
||||
|
||||
|
@ -222,6 +230,8 @@ gimp_plug_in_class_init (GimpPlugInClass *klass)
|
|||
object_class->set_property = gimp_plug_in_set_property;
|
||||
object_class->get_property = gimp_plug_in_get_property;
|
||||
|
||||
klass->set_i18n = gimp_plug_in_real_set_i18n;
|
||||
|
||||
/**
|
||||
* GimpPlugIn:read-channel:
|
||||
*
|
||||
|
@ -373,46 +383,22 @@ gimp_plug_in_get_property (GObject *object,
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_plug_in_real_set_i18n (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name,
|
||||
gchar **gettext_domain,
|
||||
gchar **catalog_dir)
|
||||
{
|
||||
/* Default to enabling localization by gettext. It will have the good
|
||||
* side-effect of warning plug-in developers of the existence of the
|
||||
* ability through stderr if the catalog directory is missing.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
/**
|
||||
* gimp_plug_in_set_translation_domain:
|
||||
* @plug_in: A #GimpPlugIn.
|
||||
* @domain_name: The name of the textdomain (must be unique).
|
||||
* @domain_path: (nullable): A file pointing to the compiled message catalog
|
||||
* (may be %NULL).
|
||||
*
|
||||
* Sets a textdomain for localisation for the @plug_in.
|
||||
*
|
||||
* This function adds a textdomain to the list of domains Gimp
|
||||
* searches for strings when translating its menu entries. There is no
|
||||
* need to call this function for plug-ins that have their strings
|
||||
* included in the 'gimp-std-plugins' domain as that is used by
|
||||
* default. If the compiled message catalog is not in the standard
|
||||
* location, you may specify an absolute path to another
|
||||
* location.
|
||||
*
|
||||
* This function can only be called in the
|
||||
* [vfunc@PlugIn.query_procedures] function of a plug-in.
|
||||
*
|
||||
* Since: 3.0
|
||||
**/
|
||||
void
|
||||
gimp_plug_in_set_translation_domain (GimpPlugIn *plug_in,
|
||||
const gchar *domain_name,
|
||||
GFile *domain_path)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
|
||||
g_return_if_fail (domain_name != NULL);
|
||||
g_return_if_fail (domain_path == NULL || G_IS_FILE (domain_path));
|
||||
|
||||
g_free (plug_in->priv->translation_domain_name);
|
||||
plug_in->priv->translation_domain_name = g_strdup (domain_name);
|
||||
|
||||
g_set_object (&plug_in->priv->translation_domain_path, domain_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_plug_in_set_help_domain:
|
||||
* @plug_in: A #GimpPlugIn.
|
||||
|
@ -890,13 +876,133 @@ _gimp_plug_in_read_expect_msg (GimpPlugIn *plug_in,
|
|||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gimp_plug_in_set_i18n (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name,
|
||||
gchar **gettext_domain,
|
||||
gchar **catalog_dir)
|
||||
{
|
||||
gboolean use_gettext;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE);
|
||||
g_return_val_if_fail (gettext_domain && *gettext_domain == NULL, FALSE);
|
||||
g_return_val_if_fail (catalog_dir && *catalog_dir == NULL, FALSE);
|
||||
|
||||
if (! plug_in->priv->translation_domain_path ||
|
||||
! plug_in->priv->translation_domain_name)
|
||||
gimp_plug_in_init_i18n (plug_in);
|
||||
|
||||
if (! GIMP_PLUG_IN_GET_CLASS (plug_in)->set_i18n)
|
||||
{
|
||||
use_gettext = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
use_gettext = GIMP_PLUG_IN_GET_CLASS (plug_in)->set_i18n (plug_in,
|
||||
procedure_name,
|
||||
gettext_domain,
|
||||
catalog_dir);
|
||||
if (use_gettext)
|
||||
{
|
||||
if (! (*gettext_domain))
|
||||
*gettext_domain = g_strdup (plug_in->priv->translation_domain_name);
|
||||
|
||||
if (*catalog_dir)
|
||||
{
|
||||
if (g_path_is_absolute (*catalog_dir))
|
||||
{
|
||||
g_printerr ("[%s] The catalog directory set by set_i18n() is not relative: %s\n",
|
||||
procedure_name, *catalog_dir);
|
||||
g_printerr ("[%s] Localization disabled\n", procedure_name);
|
||||
|
||||
use_gettext = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *rootdir = g_path_get_dirname (gimp_get_progname ());
|
||||
GFile *root_file = g_file_new_for_path (rootdir);
|
||||
GFile *catalog_file;
|
||||
GFile *parent;
|
||||
|
||||
catalog_file = g_file_resolve_relative_path (root_file, *catalog_dir);
|
||||
|
||||
/* Verify that the catalog is a subdir of the plug-in folder.
|
||||
* We do not want to allow plug-ins to look outside their own
|
||||
* realm.
|
||||
*/
|
||||
parent = g_file_dup (catalog_file);
|
||||
do
|
||||
{
|
||||
if (g_file_equal (parent, root_file))
|
||||
break;
|
||||
g_clear_object (&parent);
|
||||
}
|
||||
while ((parent = g_file_get_parent (parent)));
|
||||
|
||||
if (parent == NULL)
|
||||
{
|
||||
g_printerr ("[%s] The catalog directory set by set_i18n() is not a subdirectory: %s\n",
|
||||
procedure_name, *catalog_dir);
|
||||
g_printerr ("[%s] Localization disabled\n", procedure_name);
|
||||
|
||||
use_gettext = FALSE;
|
||||
}
|
||||
|
||||
g_free (rootdir);
|
||||
g_object_unref (root_file);
|
||||
g_clear_object (&parent);
|
||||
g_object_unref (catalog_file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*catalog_dir = g_file_get_path (plug_in->priv->translation_domain_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_gettext && ! g_file_test (*catalog_dir, G_FILE_TEST_IS_DIR))
|
||||
{
|
||||
g_printerr ("[%s] The catalog directory does not exist: %s\n",
|
||||
procedure_name, *catalog_dir);
|
||||
g_printerr ("[%s] Override method set_i18n() for the plug-in to customize or disable localization.\n",
|
||||
procedure_name);
|
||||
g_printerr ("[%s] Localization disabled\n", procedure_name);
|
||||
|
||||
use_gettext = FALSE;
|
||||
}
|
||||
|
||||
if (! use_gettext)
|
||||
{
|
||||
g_clear_pointer (gettext_domain, g_free);
|
||||
g_clear_pointer (catalog_dir, g_free);
|
||||
}
|
||||
|
||||
return use_gettext;
|
||||
}
|
||||
|
||||
GimpProcedure *
|
||||
_gimp_plug_in_create_procedure (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name)
|
||||
{
|
||||
gchar *gettext_domain = NULL;
|
||||
gchar *catalog_dir = NULL;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
|
||||
g_return_val_if_fail (gimp_is_canonical_identifier (procedure_name), NULL);
|
||||
|
||||
if (_gimp_plug_in_set_i18n (plug_in, procedure_name, &gettext_domain, &catalog_dir))
|
||||
{
|
||||
bindtextdomain (gettext_domain, catalog_dir);
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
bind_textdomain_codeset (gettext_domain, "UTF-8");
|
||||
#endif
|
||||
textdomain (gettext_domain);
|
||||
|
||||
g_free (gettext_domain);
|
||||
g_free (catalog_dir);
|
||||
}
|
||||
|
||||
if (GIMP_PLUG_IN_GET_CLASS (plug_in)->create_procedure)
|
||||
return GIMP_PLUG_IN_GET_CLASS (plug_in)->create_procedure (plug_in,
|
||||
procedure_name);
|
||||
|
@ -932,12 +1038,6 @@ gimp_plug_in_register (GimpPlugIn *plug_in,
|
|||
|
||||
g_list_free_full (procedures, g_free);
|
||||
|
||||
if (plug_in->priv->translation_domain_name)
|
||||
{
|
||||
_gimp_plug_in_domain_register (plug_in->priv->translation_domain_name,
|
||||
plug_in->priv->translation_domain_path);
|
||||
}
|
||||
|
||||
if (plug_in->priv->help_domain_name)
|
||||
{
|
||||
_gimp_plug_in_help_register (plug_in->priv->help_domain_name,
|
||||
|
@ -1216,7 +1316,22 @@ gimp_plug_in_proc_run_internal (GimpPlugIn *plug_in,
|
|||
GPProcReturn *proc_return)
|
||||
{
|
||||
GimpValueArray *arguments;
|
||||
GimpValueArray *return_values = NULL;
|
||||
GimpValueArray *return_values = NULL;
|
||||
gchar *gettext_domain = NULL;
|
||||
gchar *catalog_dir = NULL;
|
||||
|
||||
if (_gimp_plug_in_set_i18n (plug_in, gimp_procedure_get_name (procedure),
|
||||
&gettext_domain, &catalog_dir))
|
||||
{
|
||||
bindtextdomain (gettext_domain, catalog_dir);
|
||||
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
|
||||
bind_textdomain_codeset (gettext_domain, "UTF-8");
|
||||
#endif
|
||||
textdomain (gettext_domain);
|
||||
|
||||
g_free (gettext_domain);
|
||||
g_free (catalog_dir);
|
||||
}
|
||||
|
||||
gimp_plug_in_push_procedure (plug_in, procedure);
|
||||
|
||||
|
@ -1493,3 +1608,27 @@ gimp_plug_in_destroy_proxies (GHashTable *hash_table,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_plug_in_init_i18n (GimpPlugIn *plug_in)
|
||||
{
|
||||
gchar *rootdir = g_path_get_dirname (gimp_get_progname ());
|
||||
GFile *root_file = g_file_new_for_path (rootdir);
|
||||
GFile *catalog_file = NULL;
|
||||
|
||||
g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
|
||||
|
||||
/* Default domain name is the program directory name. */
|
||||
g_free (plug_in->priv->translation_domain_name);
|
||||
plug_in->priv->translation_domain_name = g_path_get_basename (rootdir);
|
||||
|
||||
/* Default catalog path is the locale/ directory under the root
|
||||
* directory.
|
||||
*/
|
||||
catalog_file = g_file_resolve_relative_path (root_file, "locale");
|
||||
g_set_object (&plug_in->priv->translation_domain_path, catalog_file);
|
||||
|
||||
g_free (rootdir);
|
||||
g_object_unref (root_file);
|
||||
g_object_unref (catalog_file);
|
||||
}
|
||||
|
|
|
@ -127,6 +127,57 @@ struct _GimpPlugInClass
|
|||
*/
|
||||
void (* quit) (GimpPlugIn *plug_in);
|
||||
|
||||
/**
|
||||
* GimpPlugInClass::set_i18n:
|
||||
* @plug_in: a #GimpPlugIn.
|
||||
* @procedure_name: procedure name.
|
||||
* @gettext_domain: (out) (nullable): Gettext domain. If %NULL, it
|
||||
* defaults to the plug-in name as determined by the
|
||||
* directory the binary is called from.
|
||||
* @catalog_dir: (out) (nullable): relative path to a subdirectory
|
||||
* of the plug-in folder containing the compiled
|
||||
* Gettext message catalogs. If %NULL, it defaults to
|
||||
* "locale/".
|
||||
*
|
||||
* This method can be overridden by all plug-ins to customize
|
||||
* internationalization of the plug-in.
|
||||
*
|
||||
* This method will be called before initializing, querying or running
|
||||
* @procedure_name (respectively with [vfunc@PlugIn.init_procedures],
|
||||
* [vfunc@PlugIn.query_procedures] or with the `run()` function set in
|
||||
* `gimp_image_procedure_new()`).
|
||||
*
|
||||
* By default, GIMP plug-ins look up gettext compiled message catalogs
|
||||
* in the subdirectory `locale/` under the plug-in folder (same folder
|
||||
* as `gimp_get_progname()`) with a text domain equal to the plug-in
|
||||
* name (regardless @procedure_name). It is unneeded to override this
|
||||
* method if you follow this localization scheme.
|
||||
*
|
||||
* If you wish to disable localization or localize with another system,
|
||||
* simply set the method to %NULL, or possibly implement this method
|
||||
* to do something useful for your usage while returning %FALSE.
|
||||
*
|
||||
* If you wish to tweak the @gettext_domain or the @localedir, return
|
||||
* %TRUE and allocate appropriate @gettext_domain and/or @localedir
|
||||
* (these use the default if set %NULL).
|
||||
*
|
||||
* Note that @localedir must be a relative path, subdirectory of the
|
||||
* directory of `gimp_get_progname()`.
|
||||
*
|
||||
* When localizing your plug-in this way, GIMP also binds
|
||||
* @gettext_domain to the UTF-8 encoding.
|
||||
*
|
||||
* Returns: %TRUE if this plug-in will use Gettext localization. You
|
||||
* may return %FALSE if you wish to disable localization or
|
||||
* set it up differently.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
gboolean (* set_i18n) (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name,
|
||||
gchar **gettext_domain,
|
||||
gchar **catalog_dir);
|
||||
|
||||
/* Padding for future expansion */
|
||||
/*< private >*/
|
||||
void (* _gimp_reserved1) (void);
|
||||
|
@ -144,9 +195,6 @@ GQuark gimp_plug_in_error_quark (void);
|
|||
|
||||
GType gimp_plug_in_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void gimp_plug_in_set_translation_domain (GimpPlugIn *plug_in,
|
||||
const gchar *domain_name,
|
||||
GFile *domain_path);
|
||||
void gimp_plug_in_set_help_domain (GimpPlugIn *plug_in,
|
||||
const gchar *domain_name,
|
||||
GFile *domain_uri);
|
||||
|
|
Loading…
Reference in New Issue