FLUID: Move i18n settings into its own class
Some checks failed
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled

This commit is contained in:
Matthias Melcher
2025-06-27 14:34:49 +02:00
parent 088d98389c
commit 3459e43ca8
17 changed files with 272 additions and 178 deletions

View File

@@ -132,6 +132,7 @@ set(CPPFILES
panels/widget_panel/Grid_Tab.cxx
panels/widget_panel/Grid_Child_Tab.cxx
proj/align_widget.cxx
proj/i18n.cxx
proj/mergeback.cxx
proj/undo.cxx
rsrcs/pixmaps.cxx
@@ -185,6 +186,7 @@ set(HEADERFILES
panels/widget_panel/Grid_Child_Tab.h
proj/align_widget.h
proj/mergeback.h
proj/i18n.h
proj/undo.h
rsrcs/comments.h
rsrcs/pixmaps.h

View File

@@ -44,17 +44,7 @@ Project::~Project() {
*/
void Project::reset() {
::delete_all();
i18n_type = fld::I18n_Type::NONE;
i18n_gnu_include = "<libintl.h>";
i18n_gnu_conditional = "";
i18n_gnu_function = "gettext";
i18n_gnu_static_function = "gettext_noop";
i18n_pos_include = "<nl_types.h>";
i18n_pos_conditional = "";
i18n_pos_file = "";
i18n_pos_set = "1";
i18n.reset();
include_H_from_C = 1;
use_FL_COMMAND = 0;
@@ -167,7 +157,7 @@ std::string Project::stringsfile_path() const {
\return the file name without path
*/
std::string Project::stringsfile_name() const {
switch (i18n_type) {
switch (i18n.type) {
default: return fl_filename_setext_str(fl_filename_name(proj_filename), ".txt");
case fld::I18n_Type::GNU: return fl_filename_setext_str(fl_filename_name(proj_filename), ".po");
case fld::I18n_Type::POSIX: return fl_filename_setext_str(fl_filename_name(proj_filename), ".msg");

View File

@@ -19,6 +19,7 @@
#define FLUID_PROJECT_H
#include "proj/undo.h"
#include "proj/i18n.h"
#include "nodes/Tree.h"
#include <string>
@@ -33,16 +34,6 @@ namespace app {
extern Layout_Preset *default_layout_preset;
} // namespace app
/**
Enumeration of available internationalization types.
*/
enum class I18n_Type {
NONE = 0, ///< No i18n, all strings are litearals
GNU, ///< GNU gettext internationalization
POSIX ///< Posix catgets internationalization
};
/**
Data and settings for a FLUID project file.
*/
@@ -55,29 +46,8 @@ public: // Member Variables
// Manage the node tree of the project.
node::Tree tree { *this };
/// One of the available internationalization types.
fld::I18n_Type i18n_type = I18n_Type::NONE;
/// Include file for GNU i18n, writes an #include statement into the source
/// file. This is usually `<libintl.h>` or `"gettext.h"` for GNU gettext.
std::string i18n_gnu_include = "<libintl.h>";
// Optional name of a macro for conditional i18n compilation.
std::string i18n_gnu_conditional = "";
/// For the gettext/intl.h options, this is the function that translates text
/// at runtime. This is usually "gettext" or "_".
std::string i18n_gnu_function = "gettext";
/// 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_".
std::string i18n_gnu_static_function = "gettext_noop";
/// Include file for Posix i18n, write a #include statement into the source
/// file. This is usually `<nl_types.h>` for Posix catgets.
std::string i18n_pos_include = "<nl_types.h>";
// Optional name of a macro for conditional i18n compilation.
std::string i18n_pos_conditional = "";
/// Name of the nl_catd database
std::string i18n_pos_file = "";
/// Message set ID for the catalog.
std::string i18n_pos_set = "1";
// Project internationalization.
proj::I18n i18n { *this };
/// If set, generate code to include the header file form the c++ file
int include_H_from_C = 1;

View File

@@ -648,14 +648,14 @@ int Code_Writer::write_code(const char *s, const char *t, bool to_codeview) {
}
}
std::string loc_include, loc_conditional;
if (proj_.i18n_type==fld::I18n_Type::GNU) {
loc_include = proj_.i18n_gnu_include;
loc_conditional = proj_.i18n_gnu_conditional;
if (proj_.i18n.type==fld::I18n_Type::GNU) {
loc_include = proj_.i18n.gnu_include;
loc_conditional = proj_.i18n.gnu_conditional;
} else {
loc_include = proj_.i18n_pos_include;
loc_conditional = proj_.i18n_pos_conditional;
loc_include = proj_.i18n.posix_include;
loc_conditional = proj_.i18n.posix_conditional;
}
if ((proj_.i18n_type != fld::I18n_Type::NONE) && !loc_include.empty()) {
if ((proj_.i18n.type != fld::I18n_Type::NONE) && !loc_include.empty()) {
int conditional = !loc_conditional.empty();
if (conditional) {
write_c("#ifdef %s\n", loc_conditional.c_str());
@@ -665,9 +665,9 @@ int Code_Writer::write_code(const char *s, const char *t, bool to_codeview) {
write_c("#%sinclude \"%s\"\n", indent(), loc_include.c_str());
else
write_c("#%sinclude %s\n", indent(), loc_include.c_str());
if (proj_.i18n_type == fld::I18n_Type::POSIX) {
if (!proj_.i18n_pos_file.empty()) {
write_c("extern nl_catd %s;\n", proj_.i18n_pos_file.c_str());
if (proj_.i18n.type == fld::I18n_Type::POSIX) {
if (!proj_.i18n.posix_file.empty()) {
write_c("extern nl_catd %s;\n", proj_.i18n.posix_file.c_str());
} else {
write_c("// Initialize I18N stuff now for menus...\n");
write_c("#%sinclude <locale.h>\n", indent());
@@ -677,14 +677,14 @@ int Code_Writer::write_code(const char *s, const char *t, bool to_codeview) {
}
if (conditional) {
write_c("#else\n");
if (proj_.i18n_type == fld::I18n_Type::GNU) {
if (!proj_.i18n_gnu_function.empty()) {
write_c("#%sifndef %s\n", indent(), proj_.i18n_gnu_function.c_str());
write_c("#%sdefine %s(text) text\n", indent_plus(1), proj_.i18n_gnu_function.c_str());
if (proj_.i18n.type == fld::I18n_Type::GNU) {
if (!proj_.i18n.gnu_function.empty()) {
write_c("#%sifndef %s\n", indent(), proj_.i18n.gnu_function.c_str());
write_c("#%sdefine %s(text) text\n", indent_plus(1), proj_.i18n.gnu_function.c_str());
write_c("#%sendif\n", indent());
}
}
if (proj_.i18n_type == fld::I18n_Type::POSIX) {
if (proj_.i18n.type == fld::I18n_Type::POSIX) {
write_c("#%sifndef catgets\n", indent());
write_c("#%sdefine catgets(catalog, set, msgid, text) text\n", indent_plus(1));
write_c("#%sendif\n", indent());
@@ -692,9 +692,9 @@ int Code_Writer::write_code(const char *s, const char *t, bool to_codeview) {
indentation--;
write_c("#endif\n");
}
if (proj_.i18n_type == fld::I18n_Type::GNU && proj_.i18n_gnu_static_function[0]) {
write_c("#ifndef %s\n", proj_.i18n_gnu_static_function.c_str());
write_c("#%sdefine %s(text) text\n", indent_plus(1), proj_.i18n_gnu_static_function.c_str());
if (proj_.i18n.type == fld::I18n_Type::GNU && proj_.i18n.gnu_static_function[0]) {
write_c("#ifndef %s\n", proj_.i18n.gnu_static_function.c_str());
write_c("#%sdefine %s(text) text\n", indent_plus(1), proj_.i18n.gnu_static_function.c_str());
write_c("#endif\n");
}
}

View File

@@ -261,38 +261,8 @@ Node *Project_Reader::read_children(Node *p, int merge, Strategy strategy, char
proj_.avoid_early_includes=1;
goto CONTINUE;
}
if (!strcmp(c,"i18n_type")) {
proj_.i18n_type = static_cast<fld::I18n_Type>(atoi(read_word()));
goto CONTINUE;
}
if (!strcmp(c,"i18n_gnu_function")) {
proj_.i18n_gnu_function = read_word();
goto CONTINUE;
}
if (!strcmp(c,"i18n_gnu_static_function")) {
proj_.i18n_gnu_static_function = read_word();
goto CONTINUE;
}
if (!strcmp(c,"i18n_pos_file")) {
proj_.i18n_pos_file = read_word();
goto CONTINUE;
}
if (!strcmp(c,"i18n_pos_set")) {
proj_.i18n_pos_set = read_word();
goto CONTINUE;
}
if (!strcmp(c,"i18n_include")) {
if (proj_.i18n_type == fld::I18n_Type::GNU)
proj_.i18n_gnu_include = read_word();
else if (proj_.i18n_type == fld::I18n_Type::POSIX)
proj_.i18n_pos_include = read_word();
goto CONTINUE;
}
if (!strcmp(c,"i18n_conditional")) {
if (proj_.i18n_type == fld::I18n_Type::GNU)
proj_.i18n_gnu_conditional = read_word();
else if (proj_.i18n_type == fld::I18n_Type::POSIX)
proj_.i18n_pos_conditional = read_word();
if (strncmp(c, "i18n_", 5) == 0) {
proj_.i18n.read(*this, c);
goto CONTINUE;
}
if (!strcmp(c,"header_name")) {

View File

@@ -115,28 +115,8 @@ int Project_Writer::write_project(const char *filename, int selected_only, bool
write_string("\nutf8_in_src");
if (proj_.avoid_early_includes)
write_string("\navoid_early_includes");
if ((proj_.i18n_type != fld::I18n_Type::NONE)) {
write_string("\ni18n_type %d", static_cast<int>(proj_.i18n_type));
switch (proj_.i18n_type) {
case fld::I18n_Type::NONE:
break;
case fld::I18n_Type::GNU : /* GNU gettext */
write_string("\ni18n_include"); write_word(proj_.i18n_gnu_include.c_str());
write_string("\ni18n_conditional"); write_word(proj_.i18n_gnu_conditional.c_str());
write_string("\ni18n_gnu_function"); write_word(proj_.i18n_gnu_function.c_str());
write_string("\ni18n_gnu_static_function"); write_word(proj_.i18n_gnu_static_function.c_str());
break;
case fld::I18n_Type::POSIX : /* POSIX catgets */
write_string("\ni18n_include"); write_word(proj_.i18n_pos_include.c_str());
write_string("\ni18n_conditional"); write_word(proj_.i18n_pos_conditional.c_str());
if (!proj_.i18n_pos_file.empty()) {
write_string("\ni18n_pos_file");
write_word(proj_.i18n_pos_file.c_str());
}
write_string("\ni18n_pos_set"); write_word(proj_.i18n_pos_set.c_str());
break;
}
}
proj_.i18n.write(*this);
if (!selected_only) {
write_string("\nheader_name"); write_word(proj_.header_file_name.c_str());

View File

@@ -50,6 +50,7 @@ public:
int open_write(const char *s);
int close_write();
int write_project(const char *filename, int selected_only, bool codeview);
void NewFunction();
void write_word(const char *);
void write_string(const char *,...) __fl_attr((__format__ (__printf__, 2, 3)));
void write_indent(int n);

View File

@@ -56,7 +56,7 @@ static int write_escaped_strings(FILE *out, const char *text) {
/**
Write a file that contains all label and tooltip strings for internationalization.
The user is responsible to set the right file name extension. The file format
is determined by `proj_.i18n_type`.
is determined by `proj_.i18n.type`.
\param[in] filename file path and name to a file that will hold the strings
\return 1 if the file could not be opened for writing, or the result of `fclose`.
*/
@@ -68,7 +68,7 @@ int fld::io::write_strings(Project &proj, const std::string &filename) {
FILE *fp = fl_fopen(filename.c_str(), "wb");
if (!fp) return 1;
switch (proj.i18n_type) {
switch (proj.i18n.type) {
case fld::I18n_Type::NONE : /* None, just put static text out */
fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
FL_VERSION);
@@ -115,7 +115,7 @@ int fld::io::write_strings(Project &proj, const std::string &filename) {
case fld::I18n_Type::POSIX : /* POSIX catgets, put a .msg file out */
fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n",
FL_VERSION);
fprintf(fp, "$set %s\n", proj.i18n_pos_set.c_str());
fprintf(fp, "$set %s\n", proj.i18n.posix_set.c_str());
fputs("$quote \"\n", fp);
for (i = 1, p = proj.tree.first; p; p = p->next) {

View File

@@ -485,10 +485,10 @@ void Menu_Item_Node::write_item(fld::io::Code_Writer& f) {
write_comment_inline_c(f, " ");
f.write_c(" {");
if (label() && label()[0])
switch (Fluid.proj.i18n_type) {
switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::GNU:
// we will call i18n when the menu is instantiated for the first time
f.write_c("%s(", Fluid.proj.i18n_gnu_static_function.c_str());
f.write_c("%s(", Fluid.proj.i18n.gnu_static_function.c_str());
f.write_cstring(label());
f.write_c(")");
break;
@@ -591,16 +591,16 @@ void Menu_Item_Node::write_code1(fld::io::Code_Writer& f) {
f.write_c("%sml->labela = (char*)", f.indent());
image->write_inline(f);
f.write_c(";\n");
if (Fluid.proj.i18n_type==fld::I18n_Type::NONE) {
if (Fluid.proj.i18n.type==fld::I18n_Type::NONE) {
f.write_c("%sml->labelb = o->label();\n", f.indent());
} else if (Fluid.proj.i18n_type==fld::I18n_Type::GNU) {
} else if (Fluid.proj.i18n.type==fld::I18n_Type::GNU) {
f.write_c("%sml->labelb = %s(o->label());\n",
f.indent(), Fluid.proj.i18n_gnu_function.c_str());
} else if (Fluid.proj.i18n_type==fld::I18n_Type::POSIX) {
f.indent(), Fluid.proj.i18n.gnu_function.c_str());
} else if (Fluid.proj.i18n.type==fld::I18n_Type::POSIX) {
f.write_c("%sml->labelb = catgets(%s,%s,i+%d,o->label());\n",
f.indent(),
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), msgnum());
Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n.posix_set.c_str(), msgnum());
}
f.write_c("%sml->typea = FL_IMAGE_LABEL;\n", f.indent());
f.write_c("%sml->typeb = FL_NORMAL_LABEL;\n", f.indent());
@@ -609,21 +609,21 @@ void Menu_Item_Node::write_code1(fld::io::Code_Writer& f) {
image->write_code(f, 0, "o");
}
}
if ((Fluid.proj.i18n_type != fld::I18n_Type::NONE) && label() && label()[0]) {
if ((Fluid.proj.i18n.type != fld::I18n_Type::NONE) && 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(f, menuItemInitialized, mname, i);
if (Fluid.proj.i18n_type==fld::I18n_Type::GNU) {
if (Fluid.proj.i18n.type==fld::I18n_Type::GNU) {
f.write_c("%so->label(%s(o->label()));\n",
f.indent(), Fluid.proj.i18n_gnu_function.c_str());
} else if (Fluid.proj.i18n_type==fld::I18n_Type::POSIX) {
f.indent(), Fluid.proj.i18n.gnu_function.c_str());
} else if (Fluid.proj.i18n.type==fld::I18n_Type::POSIX) {
f.write_c("%so->label(catgets(%s,%s,i+%d,o->label()));\n",
f.indent(),
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), msgnum());
Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n.posix_set.c_str(), msgnum());
}
}
}

View File

@@ -1601,19 +1601,19 @@ void Widget_Node::write_code1(fld::io::Code_Writer& f) {
}
if (label() && *label()) {
f.write_c(", ");
switch (Fluid.proj.i18n_type) {
switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::NONE : /* None */
f.write_cstring(label());
break;
case fld::I18n_Type::GNU : /* GNU gettext */
f.write_c("%s(", Fluid.proj.i18n_gnu_function.c_str());
f.write_c("%s(", Fluid.proj.i18n.gnu_function.c_str());
f.write_cstring(label());
f.write_c(")");
break;
case fld::I18n_Type::POSIX : /* POSIX catgets */
f.write_c("catgets(%s,%s,%d,",
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), msgnum());
Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n.posix_set.c_str(), msgnum());
f.write_cstring(label());
f.write_c(")");
break;
@@ -1675,19 +1675,19 @@ void Widget_Node::write_widget_code(fld::io::Code_Writer& f) {
if (tooltip() && *tooltip()) {
f.write_c("%s%s->tooltip(",f.indent(), var);
switch (Fluid.proj.i18n_type) {
switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::NONE : /* None */
f.write_cstring(tooltip());
break;
case fld::I18n_Type::GNU : /* GNU gettext */
f.write_c("%s(", Fluid.proj.i18n_gnu_function.c_str());
f.write_c("%s(", Fluid.proj.i18n.gnu_function.c_str());
f.write_cstring(tooltip());
f.write_c(")");
break;
case fld::I18n_Type::POSIX : /* POSIX catgets */
f.write_c("catgets(%s,%s,%d,",
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(),
Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n.posix_set.c_str(),
msgnum() + 1);
f.write_cstring(tooltip());
f.write_c(")");

View File

@@ -74,13 +74,13 @@ static void update_xywh() {
void i18n_type_cb(Fl_Choice *c, void *v) {
if (v == LOAD) {
c->value(static_cast<int>(Fluid.proj.i18n_type));
c->value(static_cast<int>(Fluid.proj.i18n.type));
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_type = static_cast<fld::I18n_Type>(c->value());
Fluid.proj.i18n.type = static_cast<fld::I18n_Type>(c->value());
Fluid.proj.set_modflag(1);
}
switch (Fluid.proj.i18n_type) {
switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::NONE : /* None */
i18n_gnu_group->hide();
i18n_posix_group->hide();

View File

@@ -180,7 +180,7 @@ void update_codeview_cb(class Fl_Button*, void*) {
char fn[FL_PATH_MAX+1];
fl_strlcpy(fn, Fluid.get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(fn, "strings", FL_PATH_MAX);
fl_filename_setext(fn, FL_PATH_MAX, exts[static_cast<int>(Fluid.proj.i18n_type)]);
fl_filename_setext(fn, FL_PATH_MAX, exts[static_cast<int>(Fluid.proj.i18n.type)]);
fld::io::write_strings(Fluid.proj, fn);
int top = cv_strings->top_line();
cv_strings->buffer()->loadfile(fn);

View File

@@ -209,7 +209,7 @@ and load those into the Code Viewer widgets.} open return_type void
char fn[FL_PATH_MAX+1];
fl_strlcpy(fn, Fluid.get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(fn, "strings", FL_PATH_MAX);
fl_filename_setext(fn, FL_PATH_MAX, exts[static_cast<int>(Fluid.proj.i18n_type)]);
fl_filename_setext(fn, FL_PATH_MAX, exts[static_cast<int>(Fluid.proj.i18n.i18n_type)]);
fld::io::write_strings(Fluid.proj, fn);
int top = cv_strings->top_line();
cv_strings->buffer()->loadfile(fn);

View File

@@ -2137,10 +2137,10 @@ Fl_Input *i18n_gnu_include_input=(Fl_Input *)0;
static void cb_i18n_gnu_include_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_include.c_str());
o->value(Fluid.proj.i18n.gnu_include.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_include = o->value();
Fluid.proj.i18n.gnu_include = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2149,10 +2149,10 @@ Fl_Input *i18n_gnu_conditional_input=(Fl_Input *)0;
static void cb_i18n_gnu_conditional_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_conditional.c_str());
o->value(Fluid.proj.i18n.gnu_conditional.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_conditional = o->value();
Fluid.proj.i18n.gnu_conditional = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2161,10 +2161,10 @@ Fl_Input *i18n_gnu_function_input=(Fl_Input *)0;
static void cb_i18n_gnu_function_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_function.c_str());
o->value(Fluid.proj.i18n.gnu_function.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_function = o->value();
Fluid.proj.i18n.gnu_function = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2173,10 +2173,10 @@ Fl_Input *i18n_gnu_static_function_input=(Fl_Input *)0;
static void cb_i18n_gnu_static_function_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_static_function.c_str());
o->value(Fluid.proj.i18n.gnu_static_function.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_static_function = o->value();
Fluid.proj.i18n.gnu_static_function = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2191,10 +2191,10 @@ Fl_Input *i18n_pos_include_input=(Fl_Input *)0;
static void cb_i18n_pos_include_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_include.c_str());
o->value(Fluid.proj.i18n.posix_include.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_include = o->value();
Fluid.proj.i18n.posix_include = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2203,10 +2203,10 @@ Fl_Input *i18n_pos_conditional_input=(Fl_Input *)0;
static void cb_i18n_pos_conditional_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_conditional.c_str());
o->value(Fluid.proj.i18n.posix_conditional.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_conditional = o->value();
Fluid.proj.i18n.posix_conditional = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2215,10 +2215,10 @@ Fl_Input *i18n_pos_file_input=(Fl_Input *)0;
static void cb_i18n_pos_file_input(Fl_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_file.c_str());
o->value(Fluid.proj.i18n.posix_file.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_file = o->value();
Fluid.proj.i18n.posix_file = o->value();
Fluid.proj.set_modflag(1);
}
}
@@ -2231,10 +2231,10 @@ Fl_Int_Input *i18n_pos_set_input=(Fl_Int_Input *)0;
static void cb_i18n_pos_set_input(Fl_Int_Input* o, void* v) {
if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_set.c_str());
o->value(Fluid.proj.i18n.posix_set.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_set = o->value();
Fluid.proj.i18n.posix_set = o->value();
Fluid.proj.set_modflag(1);
}
}

View File

@@ -1559,10 +1559,10 @@ if (v == LOAD) {
Fl_Input i18n_gnu_include_input {
label {\#include:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_include.c_str());
o->value(Fluid.proj.i18n.i18n_gnu_include.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_include = o->value();
Fluid.proj.i18n.i18n_gnu_include = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {The include file for internationalization.} xywh {100 103 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1570,10 +1570,10 @@ if (v == LOAD) {
Fl_Input i18n_gnu_conditional_input {
label {Conditional:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_conditional.c_str());
o->value(Fluid.proj.i18n.i18n_gnu_conditional.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_conditional = o->value();
Fluid.proj.i18n.i18n_gnu_conditional = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {only include the header file if this preprocessor macro is defined, for example FLTK_GETTEXT_FOUND} xywh {100 128 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1581,10 +1581,10 @@ if (v == LOAD) {
Fl_Input i18n_gnu_function_input {
label {Function:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_function.c_str());
o->value(Fluid.proj.i18n.i18n_gnu_function.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_function = o->value();
Fluid.proj.i18n.i18n_gnu_function = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {The function to call to translate labels and tooltips, usually "gettext" or "_"} xywh {100 153 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1592,10 +1592,10 @@ if (v == LOAD) {
Fl_Input i18n_gnu_static_function_input {
label {Static Function:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_static_function.c_str());
o->value(Fluid.proj.i18n.i18n_gnu_static_function.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_static_function = o->value();
Fluid.proj.i18n.i18n_gnu_static_function = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {function to call to translate static text, The function to call to internationalize labels and tooltips, usually "gettext_noop" or "N_"} xywh {100 178 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1608,10 +1608,10 @@ if (v == LOAD) {
Fl_Input i18n_pos_include_input {
label {\#include:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_include.c_str());
o->value(Fluid.proj.i18n.i18n_pos_include.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_include = o->value();
Fluid.proj.i18n.i18n_pos_include = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {The include file for internationalization.} xywh {100 103 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1619,10 +1619,10 @@ if (v == LOAD) {
Fl_Input i18n_pos_conditional_input {
label {Conditional:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_conditional.c_str());
o->value(Fluid.proj.i18n.i18n_pos_conditional.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_conditional = o->value();
Fluid.proj.i18n.i18n_pos_conditional = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {only include the header file if this preprocessor macro is defined, for example FLTK_GETTEXT_FOUND} xywh {100 128 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1630,10 +1630,10 @@ if (v == LOAD) {
Fl_Input i18n_pos_file_input {
label {Catalog:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_file.c_str());
o->value(Fluid.proj.i18n.i18n_pos_file.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_file = o->value();
Fluid.proj.i18n.i18n_pos_file = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {The name of the message catalog.} xywh {100 153 220 20} box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
@@ -1645,10 +1645,10 @@ if (v == LOAD) {
Fl_Input i18n_pos_set_input {
label {Set:}
callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_set.c_str());
o->value(Fluid.proj.i18n.i18n_pos_set.c_str());
} else {
Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_set = o->value();
Fluid.proj.i18n.i18n_pos_set = o->value();
Fluid.proj.set_modflag(1);
}}
tooltip {The message set number.} xywh {100 178 80 20} type Int box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11

93
fluid/proj/i18n.cxx Normal file
View File

@@ -0,0 +1,93 @@
//
// Fluid Project Internationalization code for the Fast Light Tool Kit (FLTK).
//
// Copyright 2025 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//
#include "proj/i18n.h"
#include "io/Project_Reader.h"
#include "io/Project_Writer.h"
using namespace fld;
using namespace fld::proj;
/**
Reset all project setting to create a new empty project.
*/
void I18n::reset() {
type = fld::I18n_Type::NONE;
gnu_include = "<libintl.h>";
gnu_conditional = "";
gnu_function = "gettext";
gnu_static_function = "gettext_noop";
posix_include = "<nl_types.h>";
posix_conditional = "";
posix_file = "";
posix_set = "1";
}
void I18n::read(io::Project_Reader &f, const char *key) {
if (!strcmp(key, "i18n_type")) {
type = static_cast<fld::I18n_Type>(atoi(f.read_word()));
} else if (!strcmp(key, "i18n_gnu_function")) {
gnu_function = f.read_word();
} else if (!strcmp(key, "i18n_gnu_static_function")) {
gnu_static_function = f.read_word();
} else if (!strcmp(key, "i18n_pos_file")) {
posix_file = f.read_word();
} else if (!strcmp(key, "i18n_pos_set")) {
posix_set = f.read_word();
} else if (!strcmp(key, "i18n_include")) {
if (type == fld::I18n_Type::GNU) {
gnu_include = f.read_word();
} else if (type == fld::I18n_Type::POSIX) {
posix_include = f.read_word();
}
} else if (!strcmp(key, "i18n_conditional")) {
if (type == fld::I18n_Type::GNU) {
gnu_conditional = f.read_word();
} else if (type == fld::I18n_Type::POSIX) {
posix_conditional = f.read_word();
}
}
}
void I18n::write(io::Project_Writer &f) const {
if ((type != fld::I18n_Type::NONE)) {
f.write_string("\ni18n_type %d", static_cast<int>(type));
switch (type) {
case fld::I18n_Type::NONE:
break;
case fld::I18n_Type::GNU : /* GNU gettext */
f.write_string("\ni18n_include"); f.write_word(gnu_include.c_str());
f.write_string("\ni18n_conditional"); f.write_word(gnu_conditional.c_str());
f.write_string("\ni18n_gnu_function"); f.write_word(gnu_function.c_str());
f.write_string("\ni18n_gnu_static_function"); f.write_word(gnu_static_function.c_str());
break;
case fld::I18n_Type::POSIX : /* POSIX catgets */
f.write_string("\ni18n_include"); f.write_word(posix_include.c_str());
f.write_string("\ni18n_conditional"); f.write_word(posix_conditional.c_str());
if (!posix_file.empty()) {
f.write_string("\ni18n_pos_file");
f.write_word(posix_file.c_str());
}
f.write_string("\ni18n_pos_set"); f.write_word(posix_set.c_str());
break;
}
}
}

88
fluid/proj/i18n.h Normal file
View File

@@ -0,0 +1,88 @@
//
// Fluid Project Internationalization header for the Fast Light Tool Kit (FLTK).
//
// Copyright 2025 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//
#ifndef FLUID_PROJ_I18N_H
#define FLUID_PROJ_I18N_H
#include <string>
namespace fld {
class Project;
/**
Enumeration of available internationalization types.
*/
enum class I18n_Type {
NONE = 0, ///< No i18n, all strings are litearals
GNU, ///< GNU gettext internationalization
POSIX ///< Posix catgets internationalization
};
namespace io {
class Project_Reader;
class Project_Writer;
}
namespace proj {
/**
Data and settings for a FLUID project file.
*/
class I18n
{
public:
Project &project_;
/// One of the available internationalization types.
fld::I18n_Type type = I18n_Type::NONE;
/// Include file for GNU i18n, writes an #include statement into the source
/// file. This is usually `<libintl.h>` or `"gettext.h"` for GNU gettext.
std::string gnu_include = "<libintl.h>";
// Optional name of a macro for conditional i18n compilation.
std::string gnu_conditional = "";
/// For the gettext/intl.h options, this is the function that translates text
/// at runtime. This is usually "gettext" or "_".
std::string gnu_function = "gettext";
/// 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_".
std::string gnu_static_function = "gettext_noop";
/// Include file for Posix i18n, write a #include statement into the source
/// file. This is usually `<nl_types.h>` for Posix catgets.
std::string posix_include = "<nl_types.h>";
// Optional name of a macro for conditional i18n compilation.
std::string posix_conditional = "";
/// Name of the nl_catd database
std::string posix_file = "";
/// Message set ID for the catalog.
std::string posix_set = "1";
public: // Methods
I18n(Project &p) : project_(p) {};
~I18n() = default;
void reset();
void read(io::Project_Reader &f, const char *key);
void write(io::Project_Writer &f) const;
};
} // namespace proj
} // namespace fld
#endif // FLUID_PROJ_I18N_H