STR 3289: Fluid i18n, gettext, catguts improvements

Removed some unneeded code.
This commit is contained in:
Matthias Melcher 2021-12-19 01:09:13 +01:00 committed by Matthias Melcher
parent 5438954d8c
commit 29531873ea
15 changed files with 342 additions and 122 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1503,8 +1503,10 @@ existing template, and click "Delete Template".
\section fluid_i18n Internationalization with FLUID
FLUID supports internationalization (I18N for short) of label
strings used by widgets. The preferences window
(<tt>Ctrl+p</tt>) provides access to the I18N options.
strings and tooltips used by widgets. The GNU gettext option also
supports deferred translation of statically initialised menu item
labels. The preferences window (<tt>Ctrl+p</tt>) provides access
to the I18N options.
\subsection fluid_i18n_methods I18N Methods
@ -1530,10 +1532,10 @@ need to call \p setlocale() and \p textdomain() or
message file.
To use GNU gettext for I18N, open the preferences window and
choose "GNU gettext" from the \b Use: chooser. Two new input
choose "GNU gettext" from the \b Use: chooser. Four new input
fields will then appear to control the include file and
function/macro name to use when retrieving the localized label
strings.
function/macro names to use when retrieving localized label
strings in dynamic allocation and static initialisation.
\image html fluid-gettext.png "Internationalization using GNU gettext"
\image latex fluid-gettext.png "Internationalization using GNU gettext" width=10cm
@ -1543,10 +1545,24 @@ field controls the header file to include for
I18N; by default this is \b <libintl.h>, the
standard I18N file for GNU gettext.
If the \b Conditional: field contains a macro name, i18n will only be compiled
into the product if this macro is defined. The build system should define the
macro only if all required headers and libraries are available. If the macro
is not defined, no headers are included and `gettext` passes text through
untranslated.
The \b Function: field controls the function (or macro) that
will retrieve the localized message; by default the
\p gettext function will be called.
The **Static Function:** field names a macro that will mark static text
fields for extraction with the `xgettext` tool. The default macro name is
\p gettext_noop and will be defined as `#define gettext_noop(text) text`
right after the `#include` statement. Fluid will do its best to call
`gettext` on static texts after the textdomain was set by the user.
\see [GNU gettext special cases](https://www.gnu.org/software/gettext/manual/html_node/Special-cases.html)
\subsection fluid_catgets_i18n Using POSIX catgets for I18N
FLUID's code support for POSIX catgets allows you to use a

View File

@ -39,6 +39,7 @@
#include <FL/Fl_Menu_Button.H>
#include <FL/Fl_Output.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Multi_Label.H>
#include "../src/flstring.h"
#include <stdio.h>
@ -53,6 +54,32 @@ Fl_Menu_Item menu_item_type_menu[] = {
static char submenuflag;
static uchar menuitemtype = 0;
static void delete_dependents(Fl_Menu_Item *m) {
if (!m)
return;
int level = 0;
for (;;m++) {
if (m->label()==NULL) {
if (level==0) {
break;
} else {
level--;
}
}
if (m->flags&FL_SUBMENU)
level++;
if (m->labeltype()==FL_MULTI_LABEL)
delete (Fl_Multi_Label*)m->label();
}
}
static void delete_menu(Fl_Menu_Item *m) {
if (!m)
return;
delete_dependents(m);
delete[] m;
}
void Fl_Input_Choice_Type::build_menu() {
Fl_Input_Choice* w = (Fl_Input_Choice*)o;
// count how many Fl_Menu_Item structures needed:
@ -63,23 +90,35 @@ void Fl_Input_Choice_Type::build_menu() {
n++;
}
if (!n) {
if (menusize) delete[] (Fl_Menu_Item*)(w->menu());
if (menusize) delete_menu((Fl_Menu_Item*)(w->menu()));
w->menu(0);
menusize = 0;
} else {
n++; // space for null at end of menu
if (menusize<n) {
if (menusize) delete[] (Fl_Menu_Item*)(w->menu());
if (menusize) delete_menu((Fl_Menu_Item*)(w->menu()));
menusize = n+10;
w->menu(new Fl_Menu_Item[menusize]);
} else {
if (menusize) delete_dependents((Fl_Menu_Item*)(w->menu()));
}
// fill them all in:
Fl_Menu_Item* m = (Fl_Menu_Item*)(w->menu());
int lvl = level+1;
for (q = next; q && q->level > level; q = q->next) {
Fl_Menu_Item_Type* i = (Fl_Menu_Item_Type*)q;
if (i->o->image()) i->o->image()->label(m);
else {
if (i->o->image()) {
if (i->o->label() && i->o->label()[0]) {
Fl_Multi_Label *ml = new Fl_Multi_Label;
ml->labela = (char*)i->o->image();
ml->labelb = i->o->label();
ml->typea = FL_IMAGE_LABEL;
ml->typeb = FL_NORMAL_LABEL;
ml->label(m);
} else {
i->o->image()->label(m);
}
} else {
m->label(i->o->label() ? i->o->label() : "(nolabel)");
m->labeltype(i->o->labeltype());
}
@ -198,6 +237,8 @@ const char* Fl_Menu_Item_Type::menu_name(int& i) {
}
void Fl_Menu_Item_Type::write_static() {
if (image && label() && label()[0])
write_declare("#include <FL/Fl_Multi_Label.H>");
if (callback() && is_name(callback()) && !user_defined(callback()))
write_declare("extern void %s(Fl_Menu_*, %s);", callback(),
user_data_type() ? user_data_type() : "void*");
@ -265,11 +306,9 @@ void Fl_Menu_Item_Type::write_static() {
const char* k = class_name(1);
if (k) {
int i;
if (i18n_type) write_c("\nunsigned char %s::%s_i18n_done = 0;", k, menu_name(i));
write_c("\nFl_Menu_Item %s::%s[] = {\n", k, menu_name(i));
} else {
int i;
if (i18n_type) write_c("\nunsigned char %s_i18n_done = 0;", menu_name(i));
write_c("\nFl_Menu_Item %s[] = {\n", menu_name(i));
}
Fl_Type* t = prev; while (t && t->is_menu_item()) t = t->prev;
@ -331,9 +370,21 @@ void Fl_Menu_Item_Type::write_item() {
write_comment_inline_c(" ");
write_c(" {");
if (image) write_c("0");
else if (label()) write_cstring(label()); // we will call i18n when the widget is instantiated for the first time
else write_c("\"\"");
if (label() && label()[0])
switch (i18n_type) {
case 1:
// we will call i18n when the menu is instantiated for the first time
write_c("%s(", i18n_static_function);
write_cstring(label());
write_c(")");
break;
case 2:
// fall through: strings can't be translated before a catalog is choosen
default:
write_cstring(label());
}
else
write_c("\"\"");
if (((Fl_Button*)o)->shortcut()) {
int s = ((Fl_Button*)o)->shortcut();
if (use_FL_COMMAND && (s & (FL_CTRL|FL_META))) {
@ -361,16 +412,22 @@ void Fl_Menu_Item_Type::write_item() {
write_c("},\n");
}
void start_menu_initialiser(int &initialized, const char *name, int index) {
if (!initialized) {
initialized = 1;
write_c("%s{ Fl_Menu_Item* o = &%s[%d];\n", indent(), name, index);
indentation++;
}
}
void Fl_Menu_Item_Type::write_code1() {
int i; const char* mname = menu_name(i);
if (!prev->is_menu_item()) {
// for first menu item, declare the array
if (class_name(1)) {
if (i18n_type) write_h("%sstatic unsigned char %s_i18n_done;\n", indent(1), mname);
write_h("%sstatic Fl_Menu_Item %s[];\n", indent(1), mname);
} else {
if (i18n_type) write_h("extern unsigned char %s_i18n_done;\n", mname);
write_h("extern Fl_Menu_Item %s[];\n", mname);
}
}
@ -401,24 +458,59 @@ void Fl_Menu_Item_Type::write_code1() {
int menuItemInitialized = 0;
// if the name is an array variable, assign the value here
if (name() && strchr(name(), '[')) {
write_c("%s%s = &%s[%d];\n", indent(), name(), mname, i);
write_c("%s%s = &%s[%d];\n", indent_plus(1), name(), mname, i);
}
if (image) {
menuItemInitialized = 1;
write_c("%s{ Fl_Menu_Item* o = &%s[%d];\n", indent(), mname, i);
image->write_code("o");
start_menu_initialiser(menuItemInitialized, mname, i);
if (label() && label()[0]) {
write_c("%sFl_Multi_Label *ml = new Fl_Multi_Label;\n", indent());
write_c("%sml->labela = (char*)", indent());
image->write_inline();
write_c(";\n");
if (i18n_type==0) {
write_c("%sml->labelb = o->label();\n", indent());
} else if (i18n_type==1) {
write_c("%sml->labelb = %s(o->label());\n",
indent(), i18n_function);
} else if (i18n_type==2) {
write_c("%sml->labelb = catgets(%s,%s,i+%d,o->label());\n",
indent(), i18n_file[0] ? i18n_file : "_catalog",
i18n_set, msgnum());
}
write_c("%sml->typea = FL_IMAGE_LABEL;\n", indent());
write_c("%sml->typeb = FL_NORMAL_LABEL;\n", indent());
write_c("%sml->label(o);\n", indent());
} else {
image->write_code("o");
}
}
if (i18n_type && label() && label()[0]) {
Fl_Labeltype t = o->labeltype();
if (image) {
// label was already copied a few lines up
} else if ( t==FL_NORMAL_LABEL || t==FL_SHADOW_LABEL
|| t==FL_ENGRAVED_LABEL || t==FL_EMBOSSED_LABEL) {
start_menu_initialiser(menuItemInitialized, mname, i);
if (i18n_type==1) {
write_c("%so->label(%s(o->label()));\n",
indent(), i18n_function);
} else if (i18n_type==2) {
write_c("%so->label(catgets(%s,%s,i+%d,o->label()));\n",
indent(), i18n_file[0] ? i18n_file : "_catalog",
i18n_set, msgnum());
}
}
}
for (int n=0; n < NUM_EXTRA_CODE; n++) {
if (extra_code(n) && !isdeclare(extra_code(n))) {
if (!menuItemInitialized) {
menuItemInitialized = 1;
write_c("%s{ Fl_Menu_Item* o = &%s[%d];\n", indent(), mname, i);
}
write_c("%s%s\n", indent_plus(1), extra_code(n));
start_menu_initialiser(menuItemInitialized, mname, i);
write_c("%s%s\n", indent(), extra_code(n));
}
}
if (menuItemInitialized)
if (menuItemInitialized) {
indentation--;
write_c("%s}\n",indent());
}
}
void Fl_Menu_Item_Type::write_code2() {}
@ -440,23 +532,35 @@ void Fl_Menu_Type::build_menu() {
n++;
}
if (!n) {
if (menusize) delete[] (Fl_Menu_Item*)(w->menu());
if (menusize) delete_menu((Fl_Menu_Item*)(w->menu()));
w->menu(0);
menusize = 0;
} else {
n++; // space for null at end of menu
if (menusize<n) {
if (menusize) delete[] (Fl_Menu_Item*)(w->menu());
if (menusize) delete_menu((Fl_Menu_Item*)(w->menu()));
menusize = n+10;
w->menu(new Fl_Menu_Item[menusize]);
} else {
if (menusize) delete_dependents((Fl_Menu_Item*)(w->menu()));
}
// fill them all in:
Fl_Menu_Item* m = (Fl_Menu_Item*)(w->menu());
int lvl = level+1;
for (q = next; q && q->level > level; q = q->next) {
Fl_Menu_Item_Type* i = (Fl_Menu_Item_Type*)q;
if (i->o->image()) i->o->image()->label(m);
else {
if (i->o->image()) {
if (i->o->label() && i->o->label()[0]) {
Fl_Multi_Label *ml = new Fl_Multi_Label;
ml->labela = (char*)i->o->image();
ml->labelb = i->o->label();
ml->typea = FL_IMAGE_LABEL;
ml->typeb = FL_NORMAL_LABEL;
ml->label(m);
} else {
i->o->image()->label(m);
}
} else {
m->label(i->o->label() ? i->o->label() : "(nolabel)");
m->labeltype(i->o->labeltype());
}
@ -498,38 +602,6 @@ Fl_Type* Fl_Menu_Type::click_test(int, int) {
void Fl_Menu_Type::write_code2() {
if (next && next->is_menu_item()) {
if (i18n_type) {
// take care of i18n now!
Fl_Menu_Item_Type *mi = (Fl_Menu_Item_Type*)next;
int i, nItem = 0, nLabel = 0;
const char *mName = mi->menu_name(i);
for (Fl_Type* q = next; q && q->is_menu_item(); q = q->next) {
if (((Fl_Menu_Item_Type*)q)->label()) nLabel++;
int thislevel = q->level; if (q->is_parent()) thislevel++;
int nextlevel =
(q->next && q->next->is_menu_item()) ? q->next->level : next->level+1;
nItem += 1 + ((thislevel > nextlevel) ? (thislevel-nextlevel) : 0);
}
if (nLabel) {
write_c("%sif (!%s_i18n_done) {\n", indent(), mName);
write_c("%sint i=0;\n", indent_plus(1));
write_c("%sfor ( ; i<%d; i++)\n", indent_plus(1), nItem);
write_c("%sif (%s[i].label())\n", indent_plus(2), mName);
switch (i18n_type) {
case 1:
write_c("%s%s[i].label(%s(%s[i].label()));\n",
indent_plus(3), mName, i18n_function, mName);
break;
case 2:
write_c("%s%s[i].label(catgets(%s,%s,i+%d,%s[i].label()));\n",
indent_plus(3), mName, i18n_file[0] ? i18n_file : "_catalog",
i18n_set, mi->msgnum(), mName);
break;
}
write_c("%s%s_i18n_done = 1;\n", indent_plus(1), mName);
write_c("%s}\n", indent());
}
}
write_c("%s%s->menu(%s);\n", indent(), name() ? name() : "o",
unique_id(this, "menu", name(), label()));
}

View File

@ -179,6 +179,7 @@ void delete_all(int selected_only) {
} else f = f->next;
}
if(!selected_only) {
// FIXME: undo/redo uses this function, resetting the following preferences randomly
include_H_from_C=1;
use_FL_COMMAND=0;
utf8_in_src = 0;

View File

@ -45,11 +45,6 @@
int include_H_from_C = 1;
int use_FL_COMMAND = 0;
int utf8_in_src = 0;
extern int i18n_type;
extern const char* i18n_include;
extern const char* i18n_function;
extern const char* i18n_file;
extern const char* i18n_set;
extern Fl_Preferences fluid_prefs;
@ -125,31 +120,43 @@ void i18n_type_cb(Fl_Choice *c, void *) {
switch (i18n_type = c->value()) {
case 0 : /* None */
i18n_include_input->hide();
i18n_conditional_input->hide();
i18n_file_input->hide();
i18n_set_input->hide();
i18n_function_input->hide();
i18n_static_function_input->hide();
break;
case 1 : /* GNU gettext */
i18n_include_input->value("<libintl.h>");
i18n_include = i18n_include_input->value();
i18n_conditional_input->value("");
i18n_conditional = i18n_conditional_input->value();
i18n_function_input->value("gettext");
i18n_function = i18n_function_input->value();
i18n_static_function_input->value("gettext_noop");
i18n_static_function = i18n_static_function_input->value();
i18n_include_input->show();
i18n_conditional_input->show();
i18n_file_input->hide();
i18n_set_input->hide();
i18n_function_input->show();
i18n_static_function_input->show();
break;
case 2 : /* POSIX cat */
i18n_include_input->value("<nl_types.h>");
i18n_include = i18n_include_input->value();
i18n_conditional_input->value("");
i18n_conditional = i18n_conditional_input->value();
i18n_file_input->value("");
i18n_file = i18n_file_input->value();
i18n_set_input->value("1");
i18n_set = i18n_set_input->value();
i18n_include_input->show();
i18n_include = i18n_include_input->value();
i18n_conditional_input->show();
i18n_file_input->show();
i18n_set_input->show();
i18n_function_input->hide();
i18n_static_function_input->hide();
break;
}
@ -161,10 +168,14 @@ void i18n_text_cb(Fl_Input *i, void *) {
if (i == i18n_function_input)
i18n_function = i->value();
else if (i == i18n_static_function_input)
i18n_static_function = i->value();
else if (i == i18n_file_input)
i18n_file = i->value();
else if (i == i18n_include_input)
i18n_include = i->value();
else if (i == i18n_conditional_input)
i18n_conditional = i->value();
set_modflag(1);
}
@ -187,27 +198,35 @@ void show_project_cb(Fl_Widget *, void *) {
code_file_input->value(code_file_name);
i18n_type_chooser->value(i18n_type);
i18n_function_input->value(i18n_function);
i18n_static_function_input->value(i18n_static_function);
i18n_file_input->value(i18n_file);
i18n_set_input->value(i18n_set);
i18n_include_input->value(i18n_include);
i18n_conditional_input->value(i18n_conditional);
switch (i18n_type) {
case 0 : /* None */
i18n_include_input->hide();
i18n_conditional_input->hide();
i18n_file_input->hide();
i18n_set_input->hide();
i18n_function_input->hide();
i18n_static_function_input->hide();
break;
case 1 : /* GNU gettext */
i18n_include_input->show();
i18n_conditional_input->show();
i18n_file_input->hide();
i18n_set_input->hide();
i18n_function_input->show();
i18n_static_function_input->show();
break;
case 2 : /* POSIX cat */
i18n_include_input->show();
i18n_conditional_input->show();
i18n_file_input->show();
i18n_set_input->show();
i18n_function_input->hide();
i18n_static_function_input->hide();
break;
}
project_window->hotspot(project_window);

View File

@ -157,6 +157,11 @@ void Fluid_Image::write_code(const char *var, int inactive) {
if (img) write_c("%s%s->%s( %s() );\n", indent(), var, inactive ? "deimage" : "image", function_name_);
}
void Fluid_Image::write_inline(int inactive) {
if (img)
write_c("%s()", function_name_);
}
////////////////////////////////////////////////////////////////

View File

@ -41,6 +41,7 @@ public:
void write_static();
void write_initializer(const char *type_name, const char *format, ...);
void write_code(const char *var, int inactive = 0);
void write_inline(int inactive = 0);
const char *name() const {return name_;}
};

View File

@ -49,21 +49,26 @@ Fl_Menu_Item menu_i18n_type_chooser[] = {
Fl_Input *i18n_include_input=(Fl_Input *)0;
Fl_Input *i18n_conditional_input=(Fl_Input *)0;
Fl_Input *i18n_file_input=(Fl_Input *)0;
Fl_Int_Input *i18n_set_input=(Fl_Int_Input *)0;
Fl_Input *i18n_function_input=(Fl_Input *)0;
Fl_Input *i18n_static_function_input=(Fl_Input *)0;
Fl_Double_Window* make_project_window() {
{ project_window = new Fl_Double_Window(399, 275, "Project Settings");
{ Fl_Button* o = new Fl_Button(328, 239, 60, 25, "Close");
o->tooltip("Close this dialog.");
o->callback((Fl_Callback*)cb_Close);
} // Fl_Button* o
{ Fl_Tabs* o = new Fl_Tabs(10, 10, 378, 218);
{ Fl_Tabs* o = new Fl_Tabs(10, 10, 379, 218);
o->selection_color((Fl_Color)12);
{ Fl_Group* o = new Fl_Group(10, 36, 378, 192, "Output");
o->labelcolor(FL_BACKGROUND2_COLOR);
{ Fl_Group* o = new Fl_Group(10, 36, 379, 192, "Output");
{ Fl_Box* o = new Fl_Box(20, 49, 340, 49, "Use \"name.ext\" to set a file name or just \".ext\" to set extension.");
o->align(Fl_Align(132|FL_ALIGN_INSIDE));
} // Fl_Box* o
@ -89,7 +94,7 @@ Fl_Double_Window* make_project_window() {
include_H_from_C_button->callback((Fl_Callback*)include_H_from_C_button_cb);
} // Fl_Check_Button* include_H_from_C_button
{ use_FL_COMMAND_button = new Fl_Check_Button(117, 176, 272, 20, "Menu shortcuts use FL_COMMAND");
use_FL_COMMAND_button->tooltip("Replace FL_CTRL with FL_COMMAND when generating menu shortcut code.");
use_FL_COMMAND_button->tooltip("Replace FL_CTRL and FL_META with FL_COMMAND when generating menu shortcuts");
use_FL_COMMAND_button->down_box(FL_DOWN_BOX);
use_FL_COMMAND_button->callback((Fl_Callback*)use_FL_COMMAND_button_cb);
} // Fl_Check_Button* use_FL_COMMAND_button
@ -104,7 +109,7 @@ ped using octal notation `\\0123`. If this option is checked, Fluid will write\
} // Fl_Group* o
{ Fl_Group* o = new Fl_Group(10, 36, 378, 192, "Internationalization");
o->hide();
{ i18n_type_chooser = new Fl_Choice(100, 48, 136, 25, "Use:");
{ i18n_type_chooser = new Fl_Choice(128, 48, 136, 25, "Use:");
i18n_type_chooser->tooltip("Type of internationalization to use.");
i18n_type_chooser->box(FL_THIN_UP_BOX);
i18n_type_chooser->down_box(FL_BORDER_BOX);
@ -112,21 +117,29 @@ ped using octal notation `\\0123`. If this option is checked, Fluid will write\
i18n_type_chooser->callback((Fl_Callback*)i18n_type_cb);
i18n_type_chooser->menu(menu_i18n_type_chooser);
} // Fl_Choice* i18n_type_chooser
{ i18n_include_input = new Fl_Input(100, 78, 272, 20, "#include:");
{ i18n_include_input = new Fl_Input(128, 78, 243, 20, "#include:");
i18n_include_input->tooltip("The include file for internationalization.");
i18n_include_input->box(FL_THIN_DOWN_BOX);
i18n_include_input->labelfont(1);
i18n_include_input->textfont(4);
i18n_include_input->callback((Fl_Callback*)i18n_text_cb);
} // Fl_Input* i18n_include_input
{ i18n_file_input = new Fl_Input(100, 104, 272, 20, "File:");
{ i18n_conditional_input = new Fl_Input(128, 103, 243, 20, "Conditional:");
i18n_conditional_input->tooltip("only include the header file if this preprocessor macro is defined, for examp\
le FLTK_GETTEXT_FOUND");
i18n_conditional_input->box(FL_THIN_DOWN_BOX);
i18n_conditional_input->labelfont(1);
i18n_conditional_input->textfont(4);
i18n_conditional_input->callback((Fl_Callback*)i18n_text_cb);
} // Fl_Input* i18n_conditional_input
{ i18n_file_input = new Fl_Input(128, 128, 243, 20, "File:");
i18n_file_input->tooltip("The name of the message catalog.");
i18n_file_input->box(FL_THIN_DOWN_BOX);
i18n_file_input->labelfont(1);
i18n_file_input->textfont(4);
i18n_file_input->callback((Fl_Callback*)i18n_text_cb);
} // Fl_Input* i18n_file_input
{ i18n_set_input = new Fl_Int_Input(100, 128, 272, 20, "Set:");
{ i18n_set_input = new Fl_Int_Input(128, 153, 243, 20, "Set:");
i18n_set_input->tooltip("The message set number.");
i18n_set_input->type(2);
i18n_set_input->box(FL_THIN_DOWN_BOX);
@ -134,13 +147,22 @@ ped using octal notation `\\0123`. If this option is checked, Fluid will write\
i18n_set_input->textfont(4);
i18n_set_input->callback((Fl_Callback*)i18n_int_cb);
} // Fl_Int_Input* i18n_set_input
{ i18n_function_input = new Fl_Input(100, 103, 272, 20, "Function:");
i18n_function_input->tooltip("The function to call to internationalize the labels and tooltips.");
{ i18n_function_input = new Fl_Input(128, 128, 243, 20, "Function:");
i18n_function_input->tooltip("The function to call to translate labels and tooltips, usually \"gettext\" or\
\"_\"");
i18n_function_input->box(FL_THIN_DOWN_BOX);
i18n_function_input->labelfont(1);
i18n_function_input->textfont(4);
i18n_function_input->callback((Fl_Callback*)i18n_text_cb);
} // Fl_Input* i18n_function_input
{ i18n_static_function_input = new Fl_Input(128, 153, 243, 20, "Static Function:");
i18n_static_function_input->tooltip("function to call to translate static text, The function to call to internatio\
nalize labels and tooltips, usually \"gettext_noop\" or \"N_\"");
i18n_static_function_input->box(FL_THIN_DOWN_BOX);
i18n_static_function_input->labelfont(1);
i18n_static_function_input->textfont(4);
i18n_static_function_input->callback((Fl_Callback*)i18n_text_cb);
} // Fl_Input* i18n_static_function_input
o->end();
} // Fl_Group* o
o->end();
@ -525,7 +547,7 @@ Fl_Double_Window* make_layout_window() {
o->labelfont(1);
o->align(Fl_Align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE));
} // Fl_Box* o
{ Fl_Group* o = new Fl_Group(105, 115, 170, 75);
{ Fl_Group* o = new Fl_Group(105, 115, 192, 75);
{ def_widget_size[0] = new Fl_Round_Button(115, 115, 70, 25);
def_widget_size[0]->type(102);
def_widget_size[0]->down_box(FL_ROUND_DOWN_BOX);

View File

@ -54,7 +54,7 @@ Function {make_project_window()} {open
} {
Fl_Window project_window {
label {Project Settings} open
xywh {473 246 399 275} type Double
xywh {472 246 399 275} type Double
code0 {\#include <FL/Fl_Preferences.H>}
code1 {\#include <FL/Fl_Tooltip.H>} modal visible
} {
@ -65,11 +65,11 @@ set_modflag(-1, -1);}
tooltip {Close this dialog.} xywh {328 239 60 25}
}
Fl_Tabs {} {open
xywh {10 10 378 218} selection_color 12
xywh {10 10 379 218} selection_color 12 labelcolor 7
} {
Fl_Group {} {
label Output open
xywh {10 36 378 192}
label Output open selected
xywh {10 36 379 192}
} {
Fl_Box {} {
label {Use "name.ext" to set a file name or just ".ext" to set extension.}
@ -95,11 +95,11 @@ set_modflag(-1, -1);}
Fl_Check_Button use_FL_COMMAND_button {
label {Menu shortcuts use FL_COMMAND}
callback use_FL_COMMAND_button_cb
tooltip {Replace FL_CTRL with FL_COMMAND when generating menu shortcut code.} xywh {117 176 272 20} down_box DOWN_BOX
tooltip {Replace FL_CTRL and FL_META with FL_COMMAND when generating menu shortcuts} xywh {117 176 272 20} down_box DOWN_BOX
}
Fl_Check_Button utf8_in_src_button {
label {allow Unicode UTF-8 in source code}
callback utf8_in_src_cb selected
callback utf8_in_src_cb
tooltip {For older compilers, characters outside of the printable ASCII range are escaped using octal notation `\\0123`. If this option is checked, Fluid will write UTF-8 characters unchanged.} xywh {117 199 272 20} down_box DOWN_BOX
}
}
@ -110,7 +110,7 @@ set_modflag(-1, -1);}
Fl_Choice i18n_type_chooser {
label {Use:}
callback i18n_type_cb open
tooltip {Type of internationalization to use.} xywh {100 48 136 25} box THIN_UP_BOX down_box BORDER_BOX labelfont 1
tooltip {Type of internationalization to use.} xywh {128 48 136 25} box THIN_UP_BOX down_box BORDER_BOX labelfont 1
} {
MenuItem {} {
label None
@ -128,22 +128,32 @@ set_modflag(-1, -1);}
Fl_Input i18n_include_input {
label {\#include:}
callback i18n_text_cb
tooltip {The include file for internationalization.} xywh {100 78 272 20} box THIN_DOWN_BOX labelfont 1 textfont 4
tooltip {The include file for internationalization.} xywh {128 78 243 20} box THIN_DOWN_BOX labelfont 1 textfont 4
}
Fl_Input i18n_conditional_input {
label {Conditional:}
callback i18n_text_cb
tooltip {only include the header file if this preprocessor macro is defined, for example FLTK_GETTEXT_FOUND} xywh {128 103 243 20} box THIN_DOWN_BOX labelfont 1 textfont 4
}
Fl_Input i18n_file_input {
label {File:}
callback i18n_text_cb
tooltip {The name of the message catalog.} xywh {100 104 272 20} box THIN_DOWN_BOX labelfont 1 textfont 4
tooltip {The name of the message catalog.} xywh {128 128 243 20} box THIN_DOWN_BOX labelfont 1 textfont 4
}
Fl_Input i18n_set_input {
label {Set:}
callback i18n_int_cb
tooltip {The message set number.} xywh {100 128 272 20} type Int box THIN_DOWN_BOX labelfont 1 textfont 4
tooltip {The message set number.} xywh {128 153 243 20} type Int box THIN_DOWN_BOX labelfont 1 textfont 4
}
Fl_Input i18n_function_input {
label {Function:}
callback i18n_text_cb
tooltip {The function to call to internationalize the labels and tooltips.} xywh {100 103 272 20} box THIN_DOWN_BOX labelfont 1 textfont 4
tooltip {The function to call to translate labels and tooltips, usually "gettext" or "_"} xywh {128 128 243 20} box THIN_DOWN_BOX labelfont 1 textfont 4
}
Fl_Input i18n_static_function_input {
label {Static Function:}
callback i18n_text_cb
tooltip {function to call to translate static text, The function to call to internationalize labels and tooltips, usually "gettext_noop" or "N_"} xywh {128 153 243 20} box THIN_DOWN_BOX labelfont 1 textfont 4
}
}
}
@ -388,7 +398,7 @@ Function {make_layout_window()} {open
} {
Fl_Window grid_window {
label {Layout Settings}
xywh {885 274 310 245} type Double non_modal visible
xywh {745 303 310 245} type Double non_modal visible
} {
Fl_Input horizontal_input {
label x
@ -431,7 +441,7 @@ Function {make_layout_window()} {open
xywh {10 115 107 25} labelfont 1 align 24
}
Fl_Group {} {open
xywh {105 115 170 75}
xywh {105 115 192 75}
} {
Fl_Round_Button {def_widget_size[0]} {
user_data 8 user_data_type long

View File

@ -51,11 +51,13 @@ extern void i18n_type_cb(Fl_Choice*, void*);
extern Fl_Choice *i18n_type_chooser;
extern void i18n_text_cb(Fl_Input*, void*);
extern Fl_Input *i18n_include_input;
extern Fl_Input *i18n_conditional_input;
extern Fl_Input *i18n_file_input;
#include <FL/Fl_Int_Input.H>
extern void i18n_int_cb(Fl_Int_Input*, void*);
extern Fl_Int_Input *i18n_set_input;
extern Fl_Input *i18n_function_input;
extern Fl_Input *i18n_static_function_input;
Fl_Double_Window* make_project_window();
extern Fl_Menu_Item menu_i18n_type_chooser[];
extern void i18n_cb(Fl_Choice *,void *);

View File

@ -573,23 +573,6 @@ int write_code(const char *s, const char *t) {
}
write_declare("#include <FL/Fl.H>");
if (i18n_type && i18n_include[0]) {
if (i18n_include[0] != '<' &&
i18n_include[0] != '\"')
write_c("#include \"%s\"\n", i18n_include);
else
write_c("#include %s\n", i18n_include);
if (i18n_type == 2) {
if (i18n_file[0]) write_c("extern nl_catd %s;\n", i18n_file);
else {
write_c("// Initialize I18N stuff now for menus...\n");
write_c("#include <locale.h>\n");
write_c("static char *_locale = setlocale(LC_MESSAGES, \"\");\n");
write_c("static nl_catd _catalog = catopen(\"%s\", 0);\n",
i18n_program);
}
}
}
if (t && include_H_from_C) {
if (*header_file_name == '.' && strchr(header_file_name, '/') == NULL) {
write_c("#include \"%s\"\n", fl_filename_name(t));
@ -597,6 +580,50 @@ int write_code(const char *s, const char *t) {
write_c("#include \"%s\"\n", t);
}
}
if (i18n_type && i18n_include[0]) {
int conditional = (i18n_conditional[0]!=0);
if (conditional) {
write_c("#ifdef %s\n", i18n_conditional);
indentation++;
}
if (i18n_include[0] != '<' &&
i18n_include[0] != '\"')
write_c("#%sinclude \"%s\"\n", indent(), i18n_include);
else
write_c("#%sinclude %s\n", indent(), i18n_include);
if (i18n_type == 2) {
if (i18n_file[0]) write_c("extern nl_catd %s;\n", i18n_file);
else {
write_c("// Initialize I18N stuff now for menus...\n");
write_c("#%sinclude <locale.h>\n", indent());
write_c("static char *_locale = setlocale(LC_MESSAGES, \"\");\n");
write_c("static nl_catd _catalog = catopen(\"%s\", 0);\n",
i18n_program);
}
}
if (conditional) {
write_c("#else\n");
if (i18n_type == 1) {
if (i18n_function[0]) {
write_c("#%sifndef %s\n", indent(), i18n_function);
write_c("#%sdefine %s(text) text\n", indent_plus(1), i18n_function);
write_c("#%sendif\n", indent());
}
}
if (i18n_type == 2) {
write_c("#%sifndef catgets\n", indent());
write_c("#%sdefine catgets(catalog, set, msgid, text) text\n", indent_plus(1));
write_c("#%sendif\n", indent());
}
indentation--;
write_c("#endif\n");
}
if (i18n_type == 1 && i18n_static_function[0]) {
write_c("#ifndef %s\n", i18n_static_function);
write_c("#%sdefine %s(text) text\n", indent_plus(1), i18n_static_function);
write_c("#endif\n");
}
}
for (Fl_Type* p = first_type; p;) {
// write all static data for this & all children first
if (write_sourceview) p->header_position = (int)ftell(header_file);

View File

@ -385,14 +385,16 @@ int write_file(const char *filename, int selected_only) {
write_string("\nutf8_in_src");
if (i18n_type) {
write_string("\ni18n_type %d", i18n_type);
write_string("\ni18n_include %s", i18n_include);
write_string("\ni18n_include"); write_word(i18n_include);
write_string("\ni18n_conditional"); write_word(i18n_conditional);
switch (i18n_type) {
case 1 : /* GNU gettext */
write_string("\ni18n_function %s", i18n_function);
write_string("\ni18n_function"); write_word(i18n_function);
write_string("\ni18n_static_function"); write_word(i18n_static_function);
break;
case 2 : /* POSIX catgets */
if (i18n_file[0]) write_string("\ni18n_file %s", i18n_file);
write_string("\ni18n_set %s", i18n_set);
if (i18n_file[0]) write_string("\ni18n_file"); write_word(i18n_file);
write_string("\ni18n_set"); write_word(i18n_set);
break;
}
}
@ -507,6 +509,10 @@ static void read_children(Fl_Type *p, int paste, Strategy strategy, char skip_op
i18n_function = fl_strdup(read_word());
goto CONTINUE;
}
if (!strcmp(c,"i18n_static_function")) {
i18n_static_function = fl_strdup(read_word());
goto CONTINUE;
}
if (!strcmp(c,"i18n_file")) {
i18n_file = fl_strdup(read_word());
goto CONTINUE;
@ -519,9 +525,8 @@ static void read_children(Fl_Type *p, int paste, Strategy strategy, char skip_op
i18n_include = fl_strdup(read_word());
goto CONTINUE;
}
if (!strcmp(c,"i18n_type"))
{
i18n_type = atoi(read_word());
if (!strcmp(c,"i18n_conditional")) {
i18n_conditional = fl_strdup(read_word());
goto CONTINUE;
}
if (!strcmp(c,"i18n_type"))

View File

@ -180,14 +180,47 @@ const char* code_file_name = ".cxx";
/// \todo document me
int i18n_type = 0;
/// Saved in the .fl design file.
/// \todo document me
/**
For either type of translation, write a #include statement into the
source file.
This is usually `<libintl.h>` or `"gettext.h"` for GNU gettext, or
`<nl_types.h>` for Posix catgets.
Fluid accepts filenames in quotes or in \< and \>. If neither is found,
double quotes are added.
If this value is emty, no include statement will be generated.
Saved in the .fl design file.
*/
const char* i18n_include = "";
/// Saved in the .fl design file.
/// \todo document me
const char* i18n_conditional = "";
/**
For the gettext/intl.h options, this is the function that translates text
at runtime.
This is usually "gettext" or "_".
This should not be empty.
Saved in the .fl design file.
*/
const char* i18n_function = "";
/**
For the gettext/intl.h options, this is the function that marks the
translation of text at initialisation time.
This is usually "gettext_noop" or "N_".
This should not be empty.
Fluid will translate static text (usually in menu items) later when used
for the first time.
Saved in the .fl design file.
*/
const char* i18n_static_function = "";
/// Saved in the .fl design file.
/// \todo document me
const char* i18n_file = "";

View File

@ -82,7 +82,9 @@ extern const char* code_file_name;
extern int i18n_type;
extern const char* i18n_include;
extern const char* i18n_conditional;
extern const char* i18n_function;
extern const char* i18n_static_function;
extern const char* i18n_file;
extern const char* i18n_set;;
extern char i18n_program[FL_PATH_MAX];

View File

@ -1,5 +1,10 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0400
i18n_type 1
i18n_include {<libintl.h>}
i18n_conditional FLTK_GETTEXT_FOUND
i18n_function gettext
i18n_static_function gettext_noop
header_name {.h}
code_name {.cxx}
decl {\#include <FL/Fl_Preferences.H>} {public local
@ -45,7 +50,7 @@ Function {} {open return_type int
Fl_Window myWindow {
label {My Preferences}
callback closeWindowCB open
xywh {586 277 298 311} type Double visible
xywh {585 277 298 311} type Double visible
} {
Fl_Button {} {
label Cancel
@ -62,7 +67,7 @@ Function {} {open return_type int
xywh {20 30 115 225} box ENGRAVED_FRAME align 5
} {
Fl_Input wAlarm {
label {Alarm at:} selected
label {Alarm at:}
xywh {25 55 45 20} align 5
}
Fl_Choice wAmPm {open
@ -73,7 +78,7 @@ Function {} {open return_type int
xywh {0 0 100 20}
}
MenuItem {} {
label {p.m.}
label {p.m.} selected
xywh {0 0 100 20}
}
}