summaryrefslogtreecommitdiff
path: root/fluid
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2025-06-27 14:34:49 +0200
committerMatthias Melcher <github@matthiasm.com>2025-06-27 14:34:49 +0200
commit3459e43ca830959d2b4ca71796a34ae7b21a819e (patch)
tree0e4bee6696fea137b1f0eff93b4f04f369bfed6f /fluid
parent088d98389cdc4c0ed38d05e4a8e59fab88198515 (diff)
FLUID: Move i18n settings into its own class
Diffstat (limited to 'fluid')
-rw-r--r--fluid/CMakeLists.txt2
-rw-r--r--fluid/Project.cxx14
-rw-r--r--fluid/Project.h36
-rw-r--r--fluid/io/Code_Writer.cxx34
-rw-r--r--fluid/io/Project_Reader.cxx34
-rw-r--r--fluid/io/Project_Writer.cxx24
-rw-r--r--fluid/io/Project_Writer.h1
-rw-r--r--fluid/io/String_Writer.cxx6
-rw-r--r--fluid/nodes/Menu_Node.cxx28
-rw-r--r--fluid/nodes/Widget_Node.cxx16
-rw-r--r--fluid/nodes/Window_Node.cxx6
-rw-r--r--fluid/panels/codeview_panel.cxx2
-rw-r--r--fluid/panels/codeview_panel.fl2
-rw-r--r--fluid/panels/settings_panel.cxx32
-rw-r--r--fluid/panels/settings_panel.fl32
-rw-r--r--fluid/proj/i18n.cxx93
-rw-r--r--fluid/proj/i18n.h88
17 files changed, 272 insertions, 178 deletions
diff --git a/fluid/CMakeLists.txt b/fluid/CMakeLists.txt
index 62d53315e..9eeec492b 100644
--- a/fluid/CMakeLists.txt
+++ b/fluid/CMakeLists.txt
@@ -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
diff --git a/fluid/Project.cxx b/fluid/Project.cxx
index c7c517a1d..46432f709 100644
--- a/fluid/Project.cxx
+++ b/fluid/Project.cxx
@@ -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");
diff --git a/fluid/Project.h b/fluid/Project.h
index e60f7bc26..f82529b1b 100644
--- a/fluid/Project.h
+++ b/fluid/Project.h
@@ -19,6 +19,7 @@
#define FLUID_PROJECT_H
#include "proj/undo.h"
+#include "proj/i18n.h"
#include "nodes/Tree.h"
#include <string>
@@ -34,16 +35,6 @@ namespace app {
} // 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.
*/
class Project
@@ -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;
diff --git a/fluid/io/Code_Writer.cxx b/fluid/io/Code_Writer.cxx
index b7179826d..086244035 100644
--- a/fluid/io/Code_Writer.cxx
+++ b/fluid/io/Code_Writer.cxx
@@ -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");
}
}
diff --git a/fluid/io/Project_Reader.cxx b/fluid/io/Project_Reader.cxx
index 4ef0c6523..c420824aa 100644
--- a/fluid/io/Project_Reader.cxx
+++ b/fluid/io/Project_Reader.cxx
@@ -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")) {
diff --git a/fluid/io/Project_Writer.cxx b/fluid/io/Project_Writer.cxx
index bfe6e0566..1975ef85d 100644
--- a/fluid/io/Project_Writer.cxx
+++ b/fluid/io/Project_Writer.cxx
@@ -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());
diff --git a/fluid/io/Project_Writer.h b/fluid/io/Project_Writer.h
index 67aebb46e..4b21cf2fb 100644
--- a/fluid/io/Project_Writer.h
+++ b/fluid/io/Project_Writer.h
@@ -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);
diff --git a/fluid/io/String_Writer.cxx b/fluid/io/String_Writer.cxx
index 6b70ec1f3..e96d2068e 100644
--- a/fluid/io/String_Writer.cxx
+++ b/fluid/io/String_Writer.cxx
@@ -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) {
diff --git a/fluid/nodes/Menu_Node.cxx b/fluid/nodes/Menu_Node.cxx
index a4434a4dd..f5555644c 100644
--- a/fluid/nodes/Menu_Node.cxx
+++ b/fluid/nodes/Menu_Node.cxx
@@ -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());
}
}
}
diff --git a/fluid/nodes/Widget_Node.cxx b/fluid/nodes/Widget_Node.cxx
index 95be9493d..2082941ce 100644
--- a/fluid/nodes/Widget_Node.cxx
+++ b/fluid/nodes/Widget_Node.cxx
@@ -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(")");
diff --git a/fluid/nodes/Window_Node.cxx b/fluid/nodes/Window_Node.cxx
index d6cbe80e6..5cc02a356 100644
--- a/fluid/nodes/Window_Node.cxx
+++ b/fluid/nodes/Window_Node.cxx
@@ -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();
diff --git a/fluid/panels/codeview_panel.cxx b/fluid/panels/codeview_panel.cxx
index 3cf191618..3c46715bd 100644
--- a/fluid/panels/codeview_panel.cxx
+++ b/fluid/panels/codeview_panel.cxx
@@ -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);
diff --git a/fluid/panels/codeview_panel.fl b/fluid/panels/codeview_panel.fl
index 3af688e16..612639c0d 100644
--- a/fluid/panels/codeview_panel.fl
+++ b/fluid/panels/codeview_panel.fl
@@ -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);
diff --git a/fluid/panels/settings_panel.cxx b/fluid/panels/settings_panel.cxx
index a57c797c2..d695c535c 100644
--- a/fluid/panels/settings_panel.cxx
+++ b/fluid/panels/settings_panel.cxx
@@ -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);
}
}
diff --git a/fluid/panels/settings_panel.fl b/fluid/panels/settings_panel.fl
index dd1f61107..59c1a476d 100644
--- a/fluid/panels/settings_panel.fl
+++ b/fluid/panels/settings_panel.fl
@@ -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
diff --git a/fluid/proj/i18n.cxx b/fluid/proj/i18n.cxx
new file mode 100644
index 000000000..a00dcf2f2
--- /dev/null
+++ b/fluid/proj/i18n.cxx
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/fluid/proj/i18n.h b/fluid/proj/i18n.h
new file mode 100644
index 000000000..30e09efae
--- /dev/null
+++ b/fluid/proj/i18n.h
@@ -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
+
+