mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-03 01:13:24 +00:00
ScriptFu: fix #12837 i18n for independent scripts
See /scripts/test/test-i18n.scm, which has tests and documents use cases. Some incidental refactoring and editing of comments.
This commit is contained in:
parent
6dfd27b271
commit
ea238e4e5a
22 changed files with 866 additions and 120 deletions
|
@ -52,6 +52,18 @@ G_DEFINE_TYPE (ScriptFuInterpreter, script_fu_interpreter, GIMP_TYPE_PLUG_IN)
|
|||
*/
|
||||
static gchar * path_to_this_script;
|
||||
|
||||
|
||||
/* For any plugin interpreted by self, these are the names, not always enforced:
|
||||
* plugin file name is plugin-<foo>.scm (it has shebang)
|
||||
* progname is the same (not the name of the interpreter)
|
||||
* plugin name is plugin-<foo>
|
||||
* PDB procedure name is plugin-<foo>
|
||||
* run_func in Scheme is named plugin-<foo> (not script-fu-<foo>)
|
||||
* C run func called by GIMP is e.g. script_fu_run_image_procedure
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Connect to Gimp. See libgimp/gimp.c.
|
||||
*
|
||||
* Can't use GIMP_MAIN macro, it doesn't omit argv[0].
|
||||
|
@ -84,6 +96,79 @@ int main (int argc, char *argv[])
|
|||
g_debug ("Exit script-fu-interpreter.");
|
||||
}
|
||||
|
||||
/* A callback from GIMP.
|
||||
* A method of GimpPlugin.
|
||||
* GIMP calls often, before any phase (query, create, init, run.)
|
||||
*
|
||||
* It is only necessary before the create phase,
|
||||
* when we declare args and menu item possibly requiring i18n.
|
||||
* FUTURE: avoid this work for phases other than create and run.
|
||||
*
|
||||
* Since it is *before* the create phase,
|
||||
* SF has not read the script and interpreted it's registration functions,
|
||||
* especially a call to script-fu-register-i18n
|
||||
* We must do that to get the declared i18n domain and catalog.
|
||||
*/
|
||||
static gboolean
|
||||
script_fu_set_i18n (GimpPlugIn *plug_in,
|
||||
const gchar *procedure_name,
|
||||
gchar **gettext_domain,
|
||||
gchar **catalog_dir)
|
||||
{
|
||||
gchar *declared_i18n_domain = NULL;
|
||||
gchar *declared_i18n_catalog = NULL;
|
||||
gboolean result;
|
||||
|
||||
/* assert that *gettext_domain and *catalog_dir are NULL and don't need free. */
|
||||
|
||||
g_debug ("%s", G_STRFUNC);
|
||||
|
||||
/* Get script author's declared i18n into local vars.*/
|
||||
script_fu_interpreter_get_i18n ( plug_in,
|
||||
procedure_name,
|
||||
path_to_this_script,
|
||||
&declared_i18n_domain,
|
||||
&declared_i18n_catalog);
|
||||
|
||||
/* Convert script declared i18n keywords to other values. */
|
||||
if (declared_i18n_domain == NULL ||
|
||||
g_strcmp0 (declared_i18n_domain, "None") == 0)
|
||||
{
|
||||
/* The script has not called script-fu-register-i18n.
|
||||
* OR with domain_name of "None".
|
||||
* Return FALSE to mean: no translations.
|
||||
*/
|
||||
*gettext_domain = NULL;
|
||||
result = FALSE;
|
||||
}
|
||||
else if ( g_strcmp0 (declared_i18n_domain, "Standard") == 0)
|
||||
{
|
||||
/* Script author wants default domain name and catalog.
|
||||
* Set to NULL, and return TRUE tells GimpPlugin to use default.
|
||||
*/
|
||||
*gettext_domain = NULL;
|
||||
*catalog_dir = NULL;
|
||||
result = TRUE; /* want translation. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Script author provided non-standard domain and catalog.
|
||||
* Return allocated copy to caller.
|
||||
*/
|
||||
*gettext_domain = g_strdup (declared_i18n_domain);
|
||||
*catalog_dir = g_strdup (declared_i18n_catalog);
|
||||
result = TRUE; /* want translation. */
|
||||
}
|
||||
|
||||
g_debug ("%s returns %d domain %s catalog %s",
|
||||
G_STRFUNC, result, declared_i18n_domain, declared_i18n_catalog);
|
||||
|
||||
g_free (declared_i18n_domain);
|
||||
g_free (declared_i18n_catalog);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
script_fu_interpreter_class_init (ScriptFuInterpreterClass *klass)
|
||||
{
|
||||
|
@ -92,17 +177,12 @@ script_fu_interpreter_class_init (ScriptFuInterpreterClass *klass)
|
|||
plug_in_class->query_procedures = script_fu_interpreter_query_procedures;
|
||||
plug_in_class->create_procedure = script_fu_interpreter_create_procedure;
|
||||
|
||||
/* Do not override virtual method set_i18n.
|
||||
/* Override virtual method set_i18n.
|
||||
* Default implementation finds translations in:
|
||||
* GIMP's .../plug-ins/<plugin_name>/locale/<lang>/LC_MESSAGES/<plugin_name>.mo
|
||||
*
|
||||
* For any plugin interpreted by self:
|
||||
* plugin file name is plugin-<foo>.scm (it has shebang)
|
||||
* progname is the same (not the name of the interpreter)
|
||||
* plugin name is plugin-<foo>
|
||||
* PDB procedure name is plugin-<foo>
|
||||
* run_func in Scheme is named plugin-<foo> (not script-fu-<foo>)
|
||||
* and throws error to console when not exists.
|
||||
*/
|
||||
plug_in_class->set_i18n = script_fu_set_i18n;
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,7 +201,7 @@ script_fu_interpreter_query_procedures (GimpPlugIn *plug_in)
|
|||
{
|
||||
GList *result = NULL;
|
||||
|
||||
g_debug ("queried");
|
||||
g_debug ("%s", G_STRFUNC);
|
||||
|
||||
/* Init ui, gegl, babl.
|
||||
* Need gegl in registration phase, to get defaults for color formal args.
|
||||
|
@ -154,7 +234,5 @@ script_fu_interpreter_create_procedure (GimpPlugIn *plug_in,
|
|||
*/
|
||||
gimp_ui_init ("script-fu-interpreter");
|
||||
|
||||
return script_fu_interpreter_create_proc_at_path (plug_in,
|
||||
proc_name,
|
||||
path_to_this_script);
|
||||
return script_fu_interpreter_create_proc (plug_in, proc_name, path_to_this_script);
|
||||
}
|
||||
|
|
|
@ -43,19 +43,36 @@
|
|||
* When we call script_fu_init_embedded_interpreter(),
|
||||
* the passed paths should include the path to /scripts
|
||||
* because that is the location of scripts for initialization and compatibility
|
||||
* (script-fu.init, plug-in-compat.init and script-fu-compat.init,
|
||||
* which are really scheme files.)
|
||||
* e.g. init.scm.
|
||||
*
|
||||
* scrip-fu-interpreter always inits embedded interpreter(allow_register=TRUE)
|
||||
* In the "run" phase, you don't need script-fu-register to be defined, but its harmless.
|
||||
*
|
||||
* The usual sequence of phases and callbacks from GimpPlugin is:
|
||||
* query phase
|
||||
* set_i18n script_fu_interpreter_get_i18n
|
||||
* query procedures script_fu_interpreter_list_defined_proc_names
|
||||
* run phase
|
||||
* set_i18n script_fu_interpreter_get_i18n
|
||||
* create procedure script_fu_interpreter_create_proc
|
||||
* set_i18n script_fu_interpreter_get_i18n
|
||||
* run procedure (calls directly a C func defined in script-fu-run-func.c)
|
||||
* We only init interpreter and load scripts once per phase.
|
||||
*/
|
||||
|
||||
static GFile *script_fu_get_plugin_parent_path (const gchar *path_to_this_script);
|
||||
static void script_fu_free_path_list (GList **list);
|
||||
|
||||
static void script_fu_interpreter_init_inner (void);
|
||||
static void script_fu_interpreter_load_script (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *path_to_script);
|
||||
static void script_fu_interpreter_init_and_load_script (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *path_to_script);
|
||||
|
||||
/* Return a list of PDB procedure names defined in all .scm files in
|
||||
* the parent dir of the given path, which is a filename of the one being queried.
|
||||
* This is called in the "query" phase, and subsequently the interpreter will exit.
|
||||
*
|
||||
* Each .scm file may contain many calls to script-fu-register, which defines a PDB procedure.
|
||||
* All .scm files in the parent dir are searched.
|
||||
|
@ -74,14 +91,9 @@ script_fu_interpreter_list_defined_proc_names (GimpPlugIn *plug_in,
|
|||
GList *name_list = NULL; /* list of strings */
|
||||
GList *path_list = NULL; /* list of GFile */
|
||||
|
||||
/* path_list is /scripts dir etc. from which we will load compat and init scripts.
|
||||
* second argument TRUE means define script-fu-register into the interpreter.
|
||||
*/
|
||||
path_list = script_fu_search_path ();
|
||||
script_fu_init_embedded_interpreter (path_list, TRUE, GIMP_RUN_NONINTERACTIVE, FALSE);
|
||||
script_fu_free_path_list (&path_list);
|
||||
script_fu_interpreter_init_inner();
|
||||
|
||||
/* Reuse path_list, now a list of one path, the parent dir of the queried script. */
|
||||
/* List one path, the parent dir of the queried script. */
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_this_script));
|
||||
name_list = script_fu_find_scripts_list_proc_names (plug_in, path_list);
|
||||
|
@ -93,31 +105,14 @@ script_fu_interpreter_list_defined_proc_names (GimpPlugIn *plug_in,
|
|||
return name_list;
|
||||
}
|
||||
|
||||
|
||||
/* Create a PDB proc of type PLUGIN with the given name.
|
||||
* Unlike extension-script-fu, create proc of type PLUGIN.
|
||||
*
|
||||
* We are in "create procedure" phase of call from GIMP.
|
||||
* Create a PDB procedure that the script-fu-interpreter wraps.
|
||||
*
|
||||
* A GimpPDBProcedure has a run function, here script_fu_script_proc()
|
||||
* of this outer interpreter.
|
||||
* Sometime after the create, GIMP calls the run func, passing a name aka command.
|
||||
* In ScriptFu, the same name is used for the PDB proc and the Scheme function
|
||||
* which is the inner run func defined in the script.
|
||||
* script_fu_script_proc calls the TinyScheme interpreter to evaluate
|
||||
* the inner run func in the script.
|
||||
*/
|
||||
GimpProcedure *
|
||||
script_fu_interpreter_create_proc_at_path (GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_this_script
|
||||
)
|
||||
script_fu_interpreter_create_proc (GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_script)
|
||||
{
|
||||
GimpProcedure *procedure = NULL;
|
||||
GList *path_list = NULL; /* list of GFile */
|
||||
|
||||
g_debug ("script_fu_interpreter_create_proc_at_path, name: %s", proc_name);
|
||||
g_debug ("%s name: %s", G_STRFUNC, proc_name);
|
||||
|
||||
/* Require proc_name is a suitable name for a PDB procedure eg "script-fu-test".
|
||||
* (Not tested for canonical name "script-fu-<something>")
|
||||
|
@ -130,35 +125,118 @@ script_fu_interpreter_create_proc_at_path (GimpPlugIn *plug_in,
|
|||
* Otherwise, we simply won't find the proc_name defined in any .scm file,
|
||||
* and will fail gracefully, returning NULL.
|
||||
*/
|
||||
|
||||
path_list = script_fu_search_path ();
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_this_script));
|
||||
/* path_list are the /scripts dir, for .init and compat.scm, plus the path to this.
|
||||
* second arg TRUE means define script-fu-register so it is effective.
|
||||
/* Load scripts.
|
||||
* We loaded scripts prior for callback gimp_plugin_set_18n,
|
||||
* but then i18n was not in effect.
|
||||
* Load again, but now i18n will translate GUI strings for declared args.
|
||||
*/
|
||||
script_fu_init_embedded_interpreter (path_list, TRUE, GIMP_RUN_NONINTERACTIVE, FALSE);
|
||||
script_fu_interpreter_load_script (plug_in, path_to_script);
|
||||
|
||||
/* Reuse path_list, now a list of only the path to this script. */
|
||||
script_fu_free_path_list (&path_list);
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_this_script));
|
||||
/* Assert loaded scripts has proc_name. Else this fails, returns NULL. */
|
||||
procedure = script_fu_create_PDB_proc_plugin (plug_in, proc_name);
|
||||
|
||||
procedure = script_fu_find_scripts_create_PDB_proc_plugin (plug_in, path_list, proc_name);
|
||||
script_fu_free_path_list (&path_list);
|
||||
|
||||
/* When procedure is not NULL, assert:
|
||||
* some .scm was evaluated.
|
||||
* the script defined many PDB procedures locally, i.e. in script-tree
|
||||
* we created a single PDB procedure (but not put it in the GIMP PDB)
|
||||
*
|
||||
* Ensure procedure is-a GimpProcedure or NULL.
|
||||
* GIMP is the caller and will put non-NULL procedure in the PDB.
|
||||
*/
|
||||
/* When procedure is not NULL, the caller GIMP will it in the PDB. */
|
||||
return procedure;
|
||||
}
|
||||
|
||||
|
||||
/* Return i18n domain and catalog declared by script at path.
|
||||
* Returns NULL when script did not call script-fu-register-i18n.
|
||||
* Returned strings are new allocated.
|
||||
* Returned strings are returned at the given handles.
|
||||
*
|
||||
* This is only used by the interpreter.
|
||||
* extension-script-fu does not let old-style scripts in /scripts
|
||||
* declare i18n; such scripts use only the shared translations gimp30-script-fu.mo.
|
||||
*
|
||||
* This is called twice when GIMP is running the procedure:
|
||||
* 1. before create
|
||||
* 2. before run
|
||||
* For the first call, we initialize the interpreter and load the script.
|
||||
* For the second call, the script is still loaded,
|
||||
* and we return the same results as the first call.
|
||||
*/
|
||||
void
|
||||
script_fu_interpreter_get_i18n (GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_this_script,
|
||||
gchar **i18n_domain, /* OUT handles */
|
||||
gchar **i18n_catalog)
|
||||
{
|
||||
/* As discussed above, this may be called many times in same interpreter session.
|
||||
* Only init interpreter once.
|
||||
*/
|
||||
if (! script_fu_is_scripts_loaded ())
|
||||
{
|
||||
script_fu_interpreter_init_and_load_script (plug_in, path_to_this_script);
|
||||
}
|
||||
|
||||
/* This will allocate strings and set the handles. */
|
||||
return script_fu_get_i18n_for_proc (proc_name, i18n_domain, i18n_catalog);
|
||||
}
|
||||
|
||||
/* Load plugin .scm files from directory at path.
|
||||
* Side effects on the interpreter's tree of scripts.
|
||||
*
|
||||
* This may load many files which define many PDB procedures.
|
||||
* This does not install the PDB procedures defined by the scripts.
|
||||
*
|
||||
* This can be called sequentially but the effect is not cumulative:
|
||||
* it frees any scripts already loaded into internal tree.
|
||||
* A second call reloads the tree.
|
||||
*/
|
||||
static void
|
||||
script_fu_interpreter_load_script (GimpPlugIn *plug_in,
|
||||
const gchar *path_to_script)
|
||||
{
|
||||
GList *path_list = NULL; /* list of GFile */
|
||||
|
||||
/* Convert file name to list of one parent path.
|
||||
* A SF independently interpreted file must be in its own dir,
|
||||
* and load_scripts wants a dir, not a file.
|
||||
*/
|
||||
path_list = g_list_append (path_list,
|
||||
script_fu_get_plugin_parent_path (path_to_script));
|
||||
|
||||
/* Get scripts into global state: scripts_tree. */
|
||||
(void) script_fu_load_scripts_into_tree (plug_in, path_list);
|
||||
|
||||
script_fu_free_path_list (&path_list);
|
||||
|
||||
/* Not ensure script_fu_is_scripts_loaded(),
|
||||
* when the path is bad or is to a file that is not a valid SF script file.
|
||||
* Not ensure that the file declared any particular procedure name.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Init the SF interpreter and load plugin script files at path.
|
||||
*
|
||||
* Is an error to call more than once.
|
||||
*
|
||||
* The path is to a directory expected to contain one or more plugin .scm file.
|
||||
*
|
||||
* Initting the interpreter also "loads" non-plugin .scm files,
|
||||
* where "load" means in Scheme: read and evaluate.
|
||||
*/
|
||||
/* FUTURE we should not need to pass plug_in. See script_fu_remove_script */
|
||||
static void
|
||||
script_fu_interpreter_init_and_load_script (GimpPlugIn *plug_in,
|
||||
const gchar *path_to_script)
|
||||
{
|
||||
if (script_fu_is_scripts_loaded ())
|
||||
{
|
||||
g_error ("%s interpreter already init", G_STRFUNC);
|
||||
return;
|
||||
}
|
||||
|
||||
script_fu_interpreter_init_inner();
|
||||
|
||||
script_fu_interpreter_load_script (plug_in, path_to_script);
|
||||
}
|
||||
|
||||
|
||||
/* Return GFile of the parent directory of this plugin, whose filename is given.
|
||||
*
|
||||
* Caller must free the GFile.
|
||||
|
@ -190,3 +268,41 @@ script_fu_free_path_list (GList **list)
|
|||
/* !!! g_steal_pointer takes a handle. */
|
||||
g_list_free_full (g_steal_pointer (list), g_object_unref);
|
||||
}
|
||||
|
||||
/* Init the TinyScheme interpreter
|
||||
* and the ScriptFu interpreter that wraps it.
|
||||
*
|
||||
* Side effects only, on the state of the interpreter.
|
||||
*
|
||||
* Ensures:
|
||||
* Innermost TinyScheme interpreter is initialized.
|
||||
* It has loaded init.scm (and some other scripts in /scripts/init)
|
||||
* The ScriptFu registration functions are defined
|
||||
* (and other functions unique to ScriptFu outer interpreter.)
|
||||
*
|
||||
* It has NOT loaded plugin scripts:
|
||||
* in /scripts, served by extension-script-fu
|
||||
* in /plug-ins, served by independent interpreter
|
||||
*/
|
||||
static void
|
||||
script_fu_interpreter_init_inner (void)
|
||||
{
|
||||
GList *path_list = NULL; /* list of GFile */
|
||||
|
||||
g_debug ("%s", G_STRFUNC);
|
||||
|
||||
path_list = script_fu_search_path ();
|
||||
/* path_list is /scripts dir which has subdir /init of compat and init scripts. */
|
||||
|
||||
/* Second argument TRUE means define script-fu-register
|
||||
* and other registration functions into the interpreter.
|
||||
* So that plugin scripts WILL load IN THE FUTURE.
|
||||
* This does not load any plugins,
|
||||
* but subsequently, the interpreter will recognize registration functions
|
||||
* when interpreter loads a plugin .scm file.
|
||||
*
|
||||
* Fourth argument FALSE means use no progress reporting.
|
||||
*/
|
||||
script_fu_init_embedded_interpreter (path_list, TRUE, GIMP_RUN_NONINTERACTIVE, FALSE);
|
||||
script_fu_free_path_list (&path_list);
|
||||
}
|
||||
|
|
|
@ -21,9 +21,15 @@
|
|||
GList *script_fu_interpreter_list_defined_proc_names (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *path_to_this_plugin);
|
||||
GimpProcedure *script_fu_interpreter_create_proc_at_path (
|
||||
GimpProcedure *script_fu_interpreter_create_proc (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_this_script);
|
||||
const gchar *path_to_script);
|
||||
void script_fu_interpreter_get_i18n (
|
||||
GimpPlugIn *plug_in,
|
||||
const gchar *proc_name,
|
||||
const gchar *path_to_this_script,
|
||||
gchar **i18n_domain,
|
||||
gchar **i18n_catalog);
|
||||
|
||||
#endif /* __SCRIPT_FU_INTERPRETER_H__ */
|
||||
|
|
|
@ -112,6 +112,8 @@ static pointer script_fu_register_call_procedure (scheme
|
|||
pointer a);
|
||||
static pointer script_fu_menu_register_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_register_i18n_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_use_v3_call (scheme *sc,
|
||||
pointer a);
|
||||
static pointer script_fu_use_v2_call (scheme *sc,
|
||||
|
@ -553,6 +555,7 @@ ts_define_procedure (sc, "load-extension", scm_load_ext);
|
|||
ts_define_procedure (sc, "script-fu-register-filter", script_fu_register_call_filter);
|
||||
ts_define_procedure (sc, "script-fu-register-procedure", script_fu_register_call_procedure);
|
||||
ts_define_procedure (sc, "script-fu-menu-register", script_fu_menu_register_call);
|
||||
ts_define_procedure (sc, "script-fu-register-i18n", script_fu_register_i18n_call);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -560,6 +563,7 @@ ts_define_procedure (sc, "load-extension", scm_load_ext);
|
|||
ts_define_procedure (sc, "script-fu-register-filter", script_fu_nil_call);
|
||||
ts_define_procedure (sc, "script-fu-register-procedure", script_fu_nil_call);
|
||||
ts_define_procedure (sc, "script-fu-menu-register", script_fu_nil_call);
|
||||
ts_define_procedure (sc, "script-fu-register-i18n", script_fu_nil_call);
|
||||
}
|
||||
|
||||
ts_define_procedure (sc, "script-fu-use-v3", script_fu_use_v3_call);
|
||||
|
@ -2346,6 +2350,13 @@ script_fu_menu_register_call (scheme *sc,
|
|||
return script_fu_add_menu (sc, a);
|
||||
}
|
||||
|
||||
static pointer
|
||||
script_fu_register_i18n_call (scheme *sc,
|
||||
pointer a)
|
||||
{
|
||||
return script_fu_add_i18n (sc, a);
|
||||
}
|
||||
|
||||
static pointer
|
||||
script_fu_use_v3_call (scheme *sc,
|
||||
pointer a)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "script-fu-types.h" /* SFScript */
|
||||
#include "scheme-wrapper.h" /* tinyscheme_init etc, */
|
||||
#include "script-fu-scripts.h" /* script_fu_find_scripts */
|
||||
#include "script-fu-script.h" /* script_fu_script_get_i18n */
|
||||
#include "script-fu-interface.h" /* script_fu_interface_is_active */
|
||||
#include "script-fu-proc-factory.h"
|
||||
|
||||
|
@ -105,21 +106,38 @@ script_fu_init_embedded_interpreter (GList *paths,
|
|||
tinyscheme_init (paths, allow_register);
|
||||
ts_set_run_mode (run_mode);
|
||||
/*
|
||||
* Ensure the embedded interpreter is running
|
||||
* and has loaded its internal Scheme scripts
|
||||
* and has defined existing PDB procs as Scheme foreign functions
|
||||
* (is ready to interpret PDB-like function calls in scheme scripts.)
|
||||
* Ensure the embedded interpreter is running and:
|
||||
* loaded its internal Scheme scripts e.g. init.scm
|
||||
* defined existing PDB procs as Scheme foreign functions
|
||||
* (is ready to interpret PDB-like function calls in scheme scripts.)
|
||||
* has loaded other init and compat scripts in /scripts/init
|
||||
* e.g. script-fu-compat.scm
|
||||
*
|
||||
* scripts/...init and scripts/...compat.scm are loaded
|
||||
* iff paths includes the "/scripts" dir.
|
||||
*
|
||||
* The .scm file(s) for plugins are loaded
|
||||
* iff paths includes their parent directory (e.g. /scripts)
|
||||
* Loaded does not imply yet registered in the PDB
|
||||
* (yet, they soon might be for some phases of the plugin.)
|
||||
* The .scm file(s) for plugins in /scripts are NOT loaded.
|
||||
* Any util scripts in /scripts are NOT loaded, e.g. script-fu-utils.scm.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Load script files at paths.
|
||||
* Side effect: create state script_tree.
|
||||
* Requires interpreter initialized.
|
||||
*/
|
||||
void
|
||||
script_fu_load_scripts_into_tree (GimpPlugIn *plugin,
|
||||
GList *paths)
|
||||
{
|
||||
script_fu_scripts_load_into_tree (plugin, paths);
|
||||
}
|
||||
|
||||
/* Has the interpreter been initialized and a script loaded
|
||||
* i.e. interpreted for registration into interpreter state: script_tree.
|
||||
*/
|
||||
gboolean
|
||||
script_fu_is_scripts_loaded (void)
|
||||
{
|
||||
return script_fu_scripts_are_loaded ();
|
||||
}
|
||||
|
||||
void
|
||||
script_fu_set_print_flag (gboolean should_print)
|
||||
{
|
||||
|
@ -337,13 +355,16 @@ script_fu_is_init_directory (GFile *dir)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Create a PDB procedure from the SFScript for the given proc name.
|
||||
* Does not register into the PDB.
|
||||
* Requires scripts already loaded i.e. SFScript exist.
|
||||
*/
|
||||
GimpProcedure *
|
||||
script_fu_find_scripts_create_PDB_proc_plugin (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *name)
|
||||
script_fu_create_PDB_proc_plugin (GimpPlugIn *plug_in,
|
||||
const gchar *name)
|
||||
{
|
||||
/* Delegate to factory. */
|
||||
return script_fu_proc_factory_make_PLUGIN (plug_in, paths, name);
|
||||
return script_fu_proc_factory_make_PLUGIN (plug_in, name);
|
||||
}
|
||||
|
||||
GList *
|
||||
|
@ -353,3 +374,13 @@ script_fu_find_scripts_list_proc_names (GimpPlugIn *plug_in,
|
|||
/* Delegate to factory. */
|
||||
return script_fu_proc_factory_list_names (plug_in, paths);
|
||||
}
|
||||
|
||||
/* Requires scripts already loaded. */
|
||||
void
|
||||
script_fu_get_i18n_for_proc (const gchar *proc_name,
|
||||
gchar **declared_i18n_domain,
|
||||
gchar **declared_i18n_catalog)
|
||||
{
|
||||
SFScript *script = script_fu_find_script (proc_name);
|
||||
script_fu_script_get_i18n (script, declared_i18n_domain, declared_i18n_catalog);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,9 @@ void script_fu_init_embedded_interpreter (GList *paths,
|
|||
gboolean allow_register,
|
||||
GimpRunMode run_mode,
|
||||
gboolean report_progress);
|
||||
void script_fu_load_scripts_into_tree (GimpPlugIn *plugin,
|
||||
GList *paths);
|
||||
gboolean script_fu_is_scripts_loaded (void);
|
||||
|
||||
void script_fu_set_print_flag (gboolean should_print);
|
||||
void script_fu_redirect_output_to_gstr (GString *output);
|
||||
|
@ -52,10 +55,14 @@ void script_fu_run_read_eval_print_loop (void);
|
|||
void script_fu_register_quit_callback (void (*func) (void));
|
||||
void script_fu_register_post_command_callback (void (*func) (void));
|
||||
|
||||
GimpProcedure *script_fu_find_scripts_create_PDB_proc_plugin (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *name);
|
||||
GList *script_fu_find_scripts_list_proc_names (GimpPlugIn *plug_in,
|
||||
GList *paths);
|
||||
|
||||
GimpProcedure *script_fu_create_PDB_proc_plugin (GimpPlugIn *plug_in,
|
||||
const gchar *name);
|
||||
void script_fu_get_i18n_for_proc (const gchar *proc_name,
|
||||
gchar **declared_i18n_domain,
|
||||
gchar **declared_i18n_catalog);
|
||||
|
||||
|
||||
#endif /* __SCRIPT_FU_LIB_H__ */
|
||||
|
|
|
@ -50,34 +50,22 @@ static void script_fu_add_menu_to_procedure (GimpProcedure *procedure,
|
|||
|
||||
|
||||
/* Create and return a single PDB procedure of type PLUGIN,
|
||||
* for the given proc name, by reading the script file in the given paths.
|
||||
* for the given proc name, from script_tree already loaded.
|
||||
* Also add a menu for the procedure.
|
||||
*
|
||||
* PDB proc of type PLUGIN has permanent lifetime, unlike type TEMPORARY.
|
||||
*
|
||||
* The list of paths is usually just one directory, a subdir of /plug-ins.
|
||||
* The directory may contain many .scm files.
|
||||
* The plugin manager only queries one .scm file,
|
||||
* having the same name as its parent dir and and having execute permission.
|
||||
* But here we read all the .scm files in the directory.
|
||||
* Each .scm file may register (and define run func for) many PDB procedures.
|
||||
*
|
||||
* Here, one name is passed, and though we load all the .scm files,
|
||||
* we only create a PDB procedure for the passed name.
|
||||
* Loaded .scm file(s) may have defined many procedures.
|
||||
* Create a PDB procedure only for the one passed name.
|
||||
*/
|
||||
GimpProcedure *
|
||||
script_fu_proc_factory_make_PLUGIN (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *proc_name)
|
||||
{
|
||||
SFScript * script = NULL;
|
||||
GimpProcedure * procedure = NULL;
|
||||
|
||||
/* Reads all .scm files at paths, even though only one is pertinent.
|
||||
* The returned script_tree is also in the state of the interpreter,
|
||||
* we don't need the result here.
|
||||
*/
|
||||
(void) script_fu_find_scripts_into_tree (plug_in, paths);
|
||||
/* Require SFScripts already defined, one or more. */
|
||||
|
||||
/* Get the pertinent script from the tree. */
|
||||
script = script_fu_find_script (proc_name);
|
||||
|
@ -138,7 +126,7 @@ script_fu_proc_factory_list_names (GimpPlugIn *plug_in,
|
|||
GTree * script_tree = NULL;
|
||||
|
||||
/* Load (eval) all .scm files in all dirs in paths. */
|
||||
script_tree = script_fu_find_scripts_into_tree (plug_in, paths);
|
||||
script_tree = script_fu_scripts_load_into_tree (plug_in, paths);
|
||||
|
||||
/* Iterate over the tree, adding each script name to result list */
|
||||
g_tree_foreach (script_tree,
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#define __SCRIPT_FU_PDB_PROC_FACTORY_H__
|
||||
|
||||
GimpProcedure *script_fu_proc_factory_make_PLUGIN (GimpPlugIn *plug_in,
|
||||
GList *paths,
|
||||
const gchar *name);
|
||||
GList *script_fu_proc_factory_list_names (GimpPlugIn *plug_in,
|
||||
GList *paths);
|
||||
|
|
|
@ -80,6 +80,8 @@ script_fu_script_new (const gchar *name,
|
|||
script->copyright = g_strdup (copyright);
|
||||
script->date = g_strdup (date);
|
||||
script->image_types = g_strdup (image_types);
|
||||
script->i18n_domain_name = NULL;
|
||||
script->i18n_catalog_relative_path = NULL;
|
||||
|
||||
script->n_args = n_args;
|
||||
script->args = g_new0 (SFArg, script->n_args);
|
||||
|
@ -103,6 +105,8 @@ script_fu_script_free (SFScript *script)
|
|||
g_free (script->copyright);
|
||||
g_free (script->date);
|
||||
g_free (script->image_types);
|
||||
g_free (script->i18n_domain_name);
|
||||
g_free (script->i18n_catalog_relative_path);
|
||||
|
||||
for (i = 0; i < script->n_args; i++)
|
||||
{
|
||||
|
@ -746,3 +750,35 @@ script_fu_script_get_is_old_style (SFScript *script)
|
|||
{
|
||||
return script->is_old_style;
|
||||
}
|
||||
|
||||
/* Set script's i18n from strings owned by inner interpreter.
|
||||
* First free any existing data since might have been set already:
|
||||
* a script author may mistakenly call script-fu-register-i18n twice
|
||||
* for the same procedure.
|
||||
*/
|
||||
void
|
||||
script_fu_script_set_i18n (SFScript *script,
|
||||
gchar *domain,
|
||||
gchar *catalog)
|
||||
{
|
||||
g_free (script->i18n_domain_name);
|
||||
g_free (script->i18n_catalog_relative_path);
|
||||
script->i18n_domain_name = g_strdup (domain);
|
||||
script->i18n_catalog_relative_path = g_strdup (catalog);
|
||||
}
|
||||
|
||||
/* Return a copy of script's i18n, to the handles.
|
||||
*
|
||||
* Require *handles is NULL, not already allocated.
|
||||
*
|
||||
* May return NULL, when script author has not called script-fu-register-i18n.
|
||||
*/
|
||||
void
|
||||
script_fu_script_get_i18n (SFScript *script,
|
||||
gchar **domain,
|
||||
gchar **catalog)
|
||||
{
|
||||
*domain = g_strdup (script->i18n_domain_name);
|
||||
*catalog = g_strdup (script->i18n_catalog_relative_path);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,4 +65,11 @@ void script_fu_script_set_drawable_arity_none (SFScript *scrip
|
|||
void script_fu_script_set_is_old_style (SFScript *script);
|
||||
gboolean script_fu_script_get_is_old_style (SFScript *script);
|
||||
|
||||
void script_fu_script_set_i18n (SFScript *script,
|
||||
gchar *domain,
|
||||
gchar *catalog);
|
||||
void script_fu_script_get_i18n (SFScript *script,
|
||||
gchar **domain,
|
||||
gchar **catalog);
|
||||
|
||||
#endif /* __SCRIPT_FU_SCRIPT__ */
|
||||
|
|
|
@ -73,10 +73,34 @@ static GList *script_menu_list = NULL;
|
|||
* Function definitions
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* A method on the internal tree of scripts.
|
||||
*
|
||||
* Uninstall any PDB procedures declared by the scripts,
|
||||
* and free the tree of scripts.
|
||||
*
|
||||
* For some phases of the plugin protocol
|
||||
* the PDB procedures declared by the scripts were not installed.
|
||||
* In other words, uninstall is a try that may have no effect.
|
||||
*/
|
||||
static void
|
||||
script_fu_scripts_clear_tree ( GimpPlugIn *plug_in)
|
||||
{
|
||||
if (script_tree != NULL)
|
||||
{
|
||||
g_tree_foreach (script_tree,
|
||||
(GTraverseFunc) script_fu_remove_script,
|
||||
plug_in);
|
||||
g_tree_destroy (script_tree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Traverse list of paths, finding .scm files.
|
||||
* Load and eval any found script texts.
|
||||
* Script texts will call Scheme functions script-fu-register
|
||||
* and script-fu-menu-register,
|
||||
* Script texts will call ScriptFu registration functions
|
||||
* e.g. script-fu-register and script-fu-menu-register,
|
||||
* which insert a SFScript record into script_tree,
|
||||
* and insert a SFMenu record into script_menu_list.
|
||||
* These are side effects on the state of the outer (SF) interpreter.
|
||||
|
@ -85,20 +109,29 @@ static GList *script_menu_list = NULL;
|
|||
* The other result (script_menu_list) is not returned, see script_fu_get_menu_list.
|
||||
*
|
||||
* Caller should free script_tree and script_menu_list,
|
||||
* This should only be called once.
|
||||
* but we usually don't, the interpreter just exits.
|
||||
*
|
||||
* This can be called more than once but does not accumulate into the tree:
|
||||
* it clears the tree on every call before reloading it.
|
||||
*
|
||||
* When we load plugin script files (.scm)
|
||||
* the list of paths can be just one directory,
|
||||
* a plugin's subdir of /plug-ins (independent interpreter).
|
||||
* The plugin manager only queries one .scm file,
|
||||
* having the same name as its parent dir and and having execute permission.
|
||||
*
|
||||
* But the list of paths can be many:
|
||||
* the sys and user /scripts dirs(extension-script-fu).
|
||||
*
|
||||
* Any dir in the paths may contain many .scm files.
|
||||
* We read all the .scm files in the directory.
|
||||
* Each .scm file may register (and define run func for) many PDB procedures.
|
||||
*/
|
||||
GTree *
|
||||
script_fu_find_scripts_into_tree ( GimpPlugIn *plug_in,
|
||||
script_fu_scripts_load_into_tree ( GimpPlugIn *plug_in,
|
||||
GList *paths)
|
||||
{
|
||||
/* Clear any existing scripts */
|
||||
if (script_tree != NULL)
|
||||
{
|
||||
g_tree_foreach (script_tree,
|
||||
(GTraverseFunc) script_fu_remove_script,
|
||||
plug_in);
|
||||
g_tree_destroy (script_tree);
|
||||
}
|
||||
script_fu_scripts_clear_tree (plug_in);
|
||||
|
||||
script_tree = g_tree_new ((GCompareFunc) g_utf8_collate);
|
||||
|
||||
|
@ -138,7 +171,7 @@ void
|
|||
script_fu_find_scripts (GimpPlugIn *plug_in,
|
||||
GList *path)
|
||||
{
|
||||
script_fu_find_scripts_into_tree (plug_in, path);
|
||||
script_fu_scripts_load_into_tree (plug_in, path);
|
||||
|
||||
/* Now that all scripts are read in and sorted, tell gimp about them */
|
||||
g_tree_foreach (script_tree,
|
||||
|
@ -335,6 +368,97 @@ script_fu_add_menu (scheme *sc,
|
|||
return sc->NIL;
|
||||
}
|
||||
|
||||
/* For a call to script-fu-register-i18n,
|
||||
* marshall scheme values into local SFScript struct.
|
||||
*
|
||||
* Returns sc->NIL on success, else a foreign_error.
|
||||
* Many kinds of failure will not prevent the plugin from registering and working,
|
||||
* only prevent the plugin from being translated properly.
|
||||
*
|
||||
* Although the set_18n callback is called many times in the same interpreter session,
|
||||
* before create proc and run proc, the script is only interpreted for it's registrations once.
|
||||
* However, an ill-formed script can call script-fu-register-i18n
|
||||
* many times for the same procedure, see below.
|
||||
*/
|
||||
pointer
|
||||
script_fu_add_i18n (scheme *sc,
|
||||
pointer a)
|
||||
{
|
||||
SFScript *script;
|
||||
const gchar *proc_name;
|
||||
|
||||
gchar *i18n_domain = NULL;
|
||||
gchar *i18n_catalog_relative_path = NULL;
|
||||
|
||||
g_debug ("%s", G_STRFUNC);
|
||||
|
||||
/* Check arg count */
|
||||
if (sc->vptr->list_length (sc, a) < 2)
|
||||
return foreign_error (sc, "script-fu-register-i18n takes two or three args", 0);
|
||||
|
||||
/* PDB procedure name. */
|
||||
if (sc->vptr->is_string (sc->vptr->pair_car (a)))
|
||||
{
|
||||
proc_name = sc->vptr->string_value (sc->vptr->pair_car (a));
|
||||
a = sc->vptr->pair_cdr (a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return foreign_error (sc, "script-fu-register-i18n requires first arg is string script name", 0);
|
||||
}
|
||||
|
||||
script = script_fu_find_script (proc_name);
|
||||
|
||||
if (! script)
|
||||
return foreign_error (sc, "script-fu-register-i18n called with invalid procedure name", 0);
|
||||
|
||||
/* Not an error to interpret script-fu-register-i18n twice for the same procedure.
|
||||
* When there are two calls to script-fu-register-i18n for the same procedure
|
||||
* in one script, the latter will have effect.
|
||||
*/
|
||||
if (script->i18n_domain_name != NULL || script->i18n_catalog_relative_path != NULL)
|
||||
g_warning ("%s called twice for same procedure %s", G_STRFUNC, proc_name);
|
||||
|
||||
/* i18n domain name */
|
||||
if (sc->vptr->is_string (sc->vptr->pair_car (a)))
|
||||
{
|
||||
i18n_domain = sc->vptr->string_value (sc->vptr->pair_car (a));
|
||||
a = sc->vptr->pair_cdr (a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return foreign_error (sc, "script-fu-register-i18n requires second arg is string domain name", 0);
|
||||
}
|
||||
|
||||
/* optional catalog path */
|
||||
if (a != sc->NIL)
|
||||
{
|
||||
if (sc->vptr->is_string (sc->vptr->pair_car (a)))
|
||||
{
|
||||
i18n_catalog_relative_path = sc->vptr->string_value (sc->vptr->pair_car (a));
|
||||
a = sc->vptr->pair_cdr (a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return foreign_error (sc, "script-fu-register-i18n requires optional third arg is catalog path", 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call setter from local vars, strings owned by inner interpreter TS. */
|
||||
script_fu_script_set_i18n (script, i18n_domain, i18n_catalog_relative_path);
|
||||
|
||||
return sc->NIL; /* success */
|
||||
}
|
||||
|
||||
/* Have one or more SFScript (global data structs) been created?
|
||||
* i.e. one or more script files loaded, i.e. interpreted for their registration functions.
|
||||
* Returns a state of the interpreter.
|
||||
*/
|
||||
gboolean
|
||||
script_fu_scripts_are_loaded (void)
|
||||
{
|
||||
return (script_tree != NULL);
|
||||
}
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
@ -478,8 +602,11 @@ script_fu_install_menu (SFMenu *menu)
|
|||
g_slice_free (SFMenu, menu);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function is a GTraverseFunction.
|
||||
/* Traverse list of scripts, uninstalling from PDB and
|
||||
* freeing the script data.
|
||||
* Then free the list, now empty of content.
|
||||
*
|
||||
* This function has type GTraverseFunction.
|
||||
*/
|
||||
static gboolean
|
||||
script_fu_remove_script (gpointer foo G_GNUC_UNUSED,
|
||||
|
@ -489,6 +616,8 @@ script_fu_remove_script (gpointer foo G_GNUC_UNUSED,
|
|||
GimpPlugIn *plug_in = data;
|
||||
GList *list;
|
||||
|
||||
g_debug ("%s", G_STRFUNC);
|
||||
|
||||
for (list = scripts; list; list = g_list_next (list))
|
||||
{
|
||||
SFScript *script = list->data;
|
||||
|
|
|
@ -28,9 +28,12 @@ pointer script_fu_add_script_regular (scheme *sc,
|
|||
pointer a);
|
||||
pointer script_fu_add_menu (scheme *sc,
|
||||
pointer a);
|
||||
pointer script_fu_add_i18n (scheme *sc,
|
||||
pointer a);
|
||||
|
||||
GTree * script_fu_find_scripts_into_tree (GimpPlugIn *plug_in,
|
||||
GTree * script_fu_scripts_load_into_tree (GimpPlugIn *plug_in,
|
||||
GList *path);
|
||||
gboolean script_fu_scripts_are_loaded (void);
|
||||
SFScript * script_fu_find_script (const gchar *name);
|
||||
GList * script_fu_get_menu_list (void);
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ typedef struct
|
|||
gchar *copyright;
|
||||
gchar *date;
|
||||
gchar *image_types;
|
||||
gchar *i18n_domain_name;
|
||||
gchar *i18n_catalog_relative_path;
|
||||
|
||||
gint n_args;
|
||||
SFArg *args;
|
||||
|
|
|
@ -15,5 +15,8 @@ EXPORTS
|
|||
script_fu_register_quit_callback
|
||||
script_fu_register_post_command_callback
|
||||
script_fu_search_path
|
||||
script_fu_find_scripts_create_PDB_proc_plugin
|
||||
script_fu_create_PDB_proc_plugin
|
||||
script_fu_find_scripts_list_proc_names
|
||||
script_fu_is_scripts_loaded
|
||||
script_fu_load_scripts_into_tree
|
||||
script_fu_get_i18n_for_proc
|
||||
|
|
|
@ -189,3 +189,6 @@
|
|||
|
||||
(script-fu-menu-register "script-fu-test-sphere-v3"
|
||||
"<Image>/Filters/Development/Plug-In Examples")
|
||||
|
||||
; Use the translations data common to all Scheme plugins distributed with GIMP.
|
||||
(script-fu-register-i18n "script-fu-test-sphere-v3" "gimp30-script-fu" )
|
||||
|
|
|
@ -15,6 +15,10 @@ elif get_option('buildtype') != 'debug'
|
|||
endif
|
||||
|
||||
|
||||
# test of i18n is in its own subdir
|
||||
subdir('testi18n')
|
||||
|
||||
|
||||
# scripts interpreted by extension-script-fu, installed to /scripts
|
||||
scripts = [
|
||||
'contactsheet.scm',
|
||||
|
|
2
plug-ins/script-fu/scripts/test/testi18n/LINGUAS
Normal file
2
plug-ins/script-fu/scripts/test/testi18n/LINGUAS
Normal file
|
@ -0,0 +1,2 @@
|
|||
es
|
||||
de
|
17
plug-ins/script-fu/scripts/test/testi18n/de.po
Normal file
17
plug-ins/script-fu/scripts/test/testi18n/de.po
Normal file
|
@ -0,0 +1,17 @@
|
|||
# A file for testing.
|
||||
# For domain "scriptfu-test"
|
||||
|
||||
# Not actually from translators, hacked together by Lloyd Konneker
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
#: source line not identified, is used in test-i18n.scm
|
||||
msgid "Orientation"
|
||||
msgstr "Orientflugel"
|
||||
|
||||
msgid "Elevation"
|
||||
msgstr "Eleveflugel"
|
17
plug-ins/script-fu/scripts/test/testi18n/es.po
Normal file
17
plug-ins/script-fu/scripts/test/testi18n/es.po
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
# A file for testing.
|
||||
# For domain "scriptfu-test"
|
||||
|
||||
# Not actually from translators, hacked together by Lloyd Konneker
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
#: source line not identified, is used in test-i18n.scm
|
||||
msgid "Orientation"
|
||||
msgstr "Orientación"
|
||||
|
||||
msgid "Elevation"
|
||||
msgstr "Elevación"
|
44
plug-ins/script-fu/scripts/test/testi18n/meson.build
Normal file
44
plug-ins/script-fu/scripts/test/testi18n/meson.build
Normal file
|
@ -0,0 +1,44 @@
|
|||
# test i18n plugins
|
||||
|
||||
# Not for translators: translation data is mocked up
|
||||
|
||||
# scripts interpreted by gimp-script-fu-interpreter
|
||||
scripts_independent = [
|
||||
{ 'name': 'test-i18n' },
|
||||
{ 'name': 'test-i18n-more' },
|
||||
]
|
||||
|
||||
foreach plugin : scripts_independent
|
||||
name = plugin.get('name')
|
||||
srcs = plugin.get('srcs', name + '.scm')
|
||||
|
||||
install_data(srcs,
|
||||
install_dir: gimpplugindir / 'plug-ins' / name,
|
||||
install_mode: 'rwxr-xr-x')
|
||||
endforeach
|
||||
|
||||
|
||||
# Install test translations for a suite of PDB procedures
|
||||
# under two i18n domain names: "script-fu-test" and "scriptfu-test-more"
|
||||
|
||||
# See "Internationalizing" at the gimp developer website
|
||||
# Two plugin files define three PDB procedures
|
||||
# that share the same translations data.
|
||||
# "Suite" means: sharing the same translations data files.
|
||||
# suite is one-to-many with i18n domain names, unfortunately.
|
||||
|
||||
# ! install_dir: does NOT accept a list
|
||||
|
||||
# test-i18n.scm defines two PDB procedures
|
||||
i18n.gettext ('scriptfu-test',
|
||||
preset: 'glib',
|
||||
install_dir: gimpplugindir / 'plug-ins' / 'test-i18n' / 'locale'
|
||||
)
|
||||
|
||||
# test-i18n-more.scm defines one PDB procedure
|
||||
# Duplicate, install i18n data in a second place
|
||||
# and give it a different domain name, "scriptfu-test-more !!!
|
||||
i18n.gettext ('scriptfu-test-more',
|
||||
preset: 'glib',
|
||||
install_dir: gimpplugindir / 'plug-ins' / 'test-i18n-more' / 'locale'
|
||||
)
|
41
plug-ins/script-fu/scripts/test/testi18n/test-i18n-more.scm
Normal file
41
plug-ins/script-fu/scripts/test/testi18n/test-i18n-more.scm
Normal file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
;!# Close comment started on first line. Needed by gettext.
|
||||
|
||||
; An independently interpreted Scheme plugin
|
||||
; to test the registration function script-fu-register-18n.
|
||||
|
||||
; This is marked with translateable strings,
|
||||
; but we don't expect translators to translate.
|
||||
; We mock up incomplete translation data.
|
||||
|
||||
; Has translatable dialog.
|
||||
; Dialog appears in native language
|
||||
; when the script-fu-register-18n call is proper
|
||||
; and mockup translation data installed corresponding to said call.
|
||||
(define (plug-in-test-i18n-3 orientation)
|
||||
; does nothing
|
||||
)
|
||||
|
||||
|
||||
; Not a filter, always enabled.
|
||||
(script-fu-register-procedure "plug-in-test-i18n-3"
|
||||
_"Test SF i18n Three..." ; menu item
|
||||
"" ; tooltip
|
||||
"LKK"
|
||||
"2025"
|
||||
; One arg, just to test the translation of its label
|
||||
SF-OPTION _"Orientation" '(_"Horizontal"
|
||||
_"Vertical")
|
||||
)
|
||||
|
||||
(script-fu-menu-register "plug-in-test-i18n-3"
|
||||
"<Image>/Filters/Development/Test")
|
||||
|
||||
; !!! Note the domain name is not the same as for the
|
||||
; other two PDB procedures in the suite
|
||||
(script-fu-register-i18n "plug-in-test-i18n-3" ; plugin name
|
||||
"scriptfu-test-more") ; domain name
|
||||
|
||||
|
||||
|
||||
|
202
plug-ins/script-fu/scripts/test/testi18n/test-i18n.scm
Normal file
202
plug-ins/script-fu/scripts/test/testi18n/test-i18n.scm
Normal file
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
;!# Close comment started on first line. Needed by gettext.
|
||||
|
||||
; An independently interpreted Scheme plugin
|
||||
; to test the registration function script-fu-register-18n.
|
||||
|
||||
; This is marked with translateable strings,
|
||||
; but we don't expect translators to translate.
|
||||
; We mock up translation data.
|
||||
|
||||
; Has translateable dialog.
|
||||
; Dialog appears in native language
|
||||
; only when the script-fu-register-18n call is proper
|
||||
; and mockup translation data installed corresponding to said call.
|
||||
(define (plug-in-test-i18n-1 orientation)
|
||||
; does nothing
|
||||
)
|
||||
(define (plug-in-test-i18n-2 elevation)
|
||||
; does nothing
|
||||
)
|
||||
|
||||
|
||||
; Not a filter, always enabled.
|
||||
(script-fu-register-procedure "plug-in-test-i18n-1"
|
||||
_"Test SF i18n One..." ; menu item
|
||||
"" ; tooltip
|
||||
"LKK"
|
||||
"2025"
|
||||
; a non-filter procedure has no image types, always enabled
|
||||
; a non-filter procedure has no drawable arity, always enabled
|
||||
|
||||
; One arg, just to test the translation of its label
|
||||
SF-OPTION _"Orientation" '(_"Horizontal"
|
||||
_"Vertical")
|
||||
)
|
||||
(script-fu-register-procedure "plug-in-test-i18n-2"
|
||||
_"Test SF i18n Two..." ; menu item
|
||||
"" ; tooltip
|
||||
"LKK"
|
||||
"2025"
|
||||
SF-OPTION _"Elevation" '(_"High"
|
||||
_"Low")
|
||||
)
|
||||
|
||||
(script-fu-menu-register "plug-in-test-i18n-1"
|
||||
"<Image>/Filters/Development/Test")
|
||||
(script-fu-menu-register "plug-in-test-i18n-2"
|
||||
"<Image>/Filters/Development/Test")
|
||||
|
||||
|
||||
|
||||
; This documents the cases for a script to declare translations data.
|
||||
; This is only for plugins installed to /plug-ins (independently interpreted.)
|
||||
;
|
||||
; The script must also have GUI strings marked for translation using notation _"foo".
|
||||
; A script may be marked, but not have translator produced translation files.
|
||||
;
|
||||
; 1. The script can simply omit a call to script-fu-register-i18n.
|
||||
; This means: there is no translation data for the procedure.
|
||||
;
|
||||
; 2. The script can call (script-fu-register-i18n "proc_name" "None")
|
||||
; This also means: there is no translation data for the procedure.
|
||||
;
|
||||
; 3. The script can call (script-fu-register-i18n "proc_name" "Standard")
|
||||
; The script will be in native language subject to the existence of translation files
|
||||
; installed the usual, standard way.
|
||||
; This means: the domain name is the script's name
|
||||
; and the translation files are in .../plug-ins/<plugin_name>/locale directory
|
||||
; for example for French language there exists a file
|
||||
; .../plug-ins/<plugin_name>/locale/fr/LC_MESSAGES/<plugin_name>.mo
|
||||
; all installed, for example,
|
||||
; in GIMP's installed data e.g. /usr/lib/share/GIMP/3.0/plug-ins
|
||||
; (when the plugin is an official plugin supported by GIMP)
|
||||
; or in the user's ~/.config/GIMP/3.0/plug-ins
|
||||
; (when the user wrote or installed a third-party plugin for their own private use.)
|
||||
;
|
||||
; 4. The script can call (script-fu-register-i18n "proc_name" "foo_domain" "bar_path")
|
||||
; This means a custom install location for the translation files,
|
||||
; and a custom name for the domain, i.e. name of the .mo files.
|
||||
;
|
||||
; Typically, this is NOT USEFUL: why change the names?
|
||||
; Typically this is NOT USEFUL for a group of plugins sharing translation files.
|
||||
;
|
||||
; It is not useful for group of plugins to share translations data because
|
||||
; "bar_path" must be a relative (not absolute) path to the plugin's directory,
|
||||
; AND a subdirectory of the plugin's directory.
|
||||
; NOT ALLOWED: "../bar" meaning parent dir of bar i.e. in /plug-ins.
|
||||
; NOT ALLOWED: "/usr/bar" meaning some absolute path starting at root.
|
||||
;
|
||||
; As of this writing, the useful ways for a group of third-party plugins to share
|
||||
; common translations data are:
|
||||
; a. Put all the procedures in the same .scm file (you can do that)
|
||||
; with a call (script-fu-register-i18n "proc_nameX" "Standard")
|
||||
; for each procedure X in the .scm file,
|
||||
; and install the usual way e.g. .../plug-ins/plugin-name/plugin-name.scm
|
||||
; and install .../plug-ins/plugin-name/locale/fr/LC_MESSAGES/plugin-name.mo
|
||||
; b. Install each plugin in its own subdirectory of .../plugins
|
||||
; with a call (script-fu-register-i18n "proc_nameX" "Standard")
|
||||
; and at install time, distribute the one shared translation file foo.mo
|
||||
; to each of the many catalog directories, with renaming,
|
||||
; e.g. to .../plug-ins/plugin-name1/locale/fr/LC_MESSAGES/plugin-name1.
|
||||
; and also to .../plug-ins/plugin-name2/locale/fr/LC_MESSAGES/plugin-name2.
|
||||
;
|
||||
; In the example, the translations files will be found
|
||||
; in .../plug-ins/proc_name/bar_path
|
||||
; which will contain for example one or more files like
|
||||
; .../plug-in/proc_name/bar_path/fr/LC_MESSAGES/foo_domain.mo
|
||||
;
|
||||
; 5. The script can call (script-fu-register-i18n "proc_name" "gimp30-script-fu")
|
||||
; This means use the translation files
|
||||
; common to all Scheme plugins distributed with GIMP.
|
||||
; This is only useful for official plugins distributed with GIMP.
|
||||
; It is not useful for third-party plugins,
|
||||
; since they should not be installed in the sys GIMP data directory
|
||||
; (else they will be lost in an upgrade)
|
||||
; and also since the official translations data installed with GIMP
|
||||
; should not be altered by a third-party plugin.
|
||||
|
||||
; Note that one script file may define many PDB procedures
|
||||
; and call script-fu-register-i18n for each of them.
|
||||
; Some procedures may be translated, and others not.
|
||||
;
|
||||
; A script can (but shouldn't) call script-fu-register-i18n more than once
|
||||
; for the same procedure.
|
||||
; Only the last one will have effect.
|
||||
|
||||
|
||||
|
||||
|
||||
; These are test cases for calls to script-fu-register-i18n.
|
||||
; To test, comment out one or more trailing cases and run again.
|
||||
; Only the last uncommented one has effect.
|
||||
|
||||
|
||||
; Valid use cases
|
||||
; No errors at registration time, but can error at runtime
|
||||
; depending on existence of translation data.
|
||||
|
||||
; Case: Standard translation data
|
||||
; As of this writing there exists no mockup translation data for this case.
|
||||
; Expect this will throw an error at plugin run time,
|
||||
; to the console where GIMP was started,
|
||||
; since the standard catalog directory (owned by the plugin) does not yet exist:
|
||||
; .../plug-ins/test-i18n/locale/es/LC_MESSAGES/test-i18n.mo
|
||||
;(script-fu-register-i18n "plug-in-test-i18n" "Standard")
|
||||
|
||||
; Case: no translation data, plugin not in native language.
|
||||
; Just omit the call to script-fu-register-i18n
|
||||
|
||||
; Case: declare domain "None", no translation data, plugin not in native language.
|
||||
; Expect this does not throw an error, and never translates the plugin.
|
||||
; Same as previous case, but documents that no translation is done.
|
||||
;(script-fu-register-i18n "plug-in-test-i18n" "None")
|
||||
|
||||
; Case: Rename the domain but not the catalog.
|
||||
; Expect plugin translates when /plug-ins/test-i18n/locale exists
|
||||
; and contains es/LC_MESSAGES/scriptfu-test.mo.
|
||||
; Expect throws an error at plugin run time when said catalog directory not exist
|
||||
; in a subdirectory of the plugin root dir
|
||||
; i.e. /usr/local/lib/gimp/3.0/plug-ins/test-i18n/locale/es/LC_MESSAGES/scriptfu-test.mo
|
||||
(script-fu-register-i18n "plug-in-test-i18n-1" ; plugin name
|
||||
"scriptfu-test") ; domain name
|
||||
(script-fu-register-i18n "plug-in-test-i18n-2" ; plugin name
|
||||
"scriptfu-test") ; domain name
|
||||
; This is the same as: (script-fu-register-i18n "plug-in-test-i18n" "fooDomain" "locale" )
|
||||
|
||||
; Case: Rename the domain and the catalog.
|
||||
; Expect plugin translates when /plug-ins/plug-in-test-i18n/barCatalog exists
|
||||
; and contains fr/LC_MESSAGES/fooDomain.mo.
|
||||
; Expect throws an error at plugin run time when said catalog directory not exist.
|
||||
; (script-fu-register-i18n "plug-in-test-i18n" "fooDomain" "barCatalog")
|
||||
|
||||
; Case: Rename the domain to the one shared by official GIMP ScriptFu plugins.
|
||||
; Expect plugin translates when GIMP is properly installed,
|
||||
; and the shared translations data contains translation pairs
|
||||
; that match translateable strings in the plugin.
|
||||
; Expect throws an error at plugin run time when GIMP is not properly installed.
|
||||
; Expect strings in the plugin are in the native language
|
||||
; (only since by design the string "Orientation" is in gimp30-script-fu.mo)
|
||||
;(script-fu-register-i18n "plug-in-test-i18n" "gimp30-script-fu")
|
||||
|
||||
; Error cases:
|
||||
|
||||
; Error case: a relative path to a catalog above the plugin's directory.
|
||||
; GIMP requires the catalog dir is a subdir of, i.e. beneath, a plugins' install dir.
|
||||
; Expect this throws an error: "The catalog directory set by set_i18n() is not a subdirectory: ../bar"
|
||||
; at plugin run time, not registration time.
|
||||
;(script-fu-register-i18n "plug-in-test-i18n" "fooDomain" "../bar" )
|
||||
|
||||
; Error case: an absolute path to a catalog.
|
||||
; Because GIMP requires path to the catalog dir is not absolute, i.e. starting with "/"
|
||||
; Expect this throws an error: The catalog directory set by set_i18n() is not relative: /bar
|
||||
; at plugin run time, not registration time.
|
||||
;(script-fu-register-i18n "plug-in-test-i18n" "fooDomain" "/bar" )
|
||||
|
||||
; Error Case: not enough arguments.
|
||||
; Expect: Error: script-fu-register-i18n takes two or three args
|
||||
; in the console, at registration time, but the plugin will still work, without translations.
|
||||
; (script-fu-register-i18n "plug-in-test-i18n")
|
||||
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue