FLUID: Move i18n settings into its own class
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
+2
View File
@@ -132,6 +132,7 @@ set(CPPFILES
panels/widget_panel/Grid_Tab.cxx panels/widget_panel/Grid_Tab.cxx
panels/widget_panel/Grid_Child_Tab.cxx panels/widget_panel/Grid_Child_Tab.cxx
proj/align_widget.cxx proj/align_widget.cxx
proj/i18n.cxx
proj/mergeback.cxx proj/mergeback.cxx
proj/undo.cxx proj/undo.cxx
rsrcs/pixmaps.cxx rsrcs/pixmaps.cxx
@@ -185,6 +186,7 @@ set(HEADERFILES
panels/widget_panel/Grid_Child_Tab.h panels/widget_panel/Grid_Child_Tab.h
proj/align_widget.h proj/align_widget.h
proj/mergeback.h proj/mergeback.h
proj/i18n.h
proj/undo.h proj/undo.h
rsrcs/comments.h rsrcs/comments.h
rsrcs/pixmaps.h rsrcs/pixmaps.h
+2 -12
View File
@@ -44,17 +44,7 @@ Project::~Project() {
*/ */
void Project::reset() { void Project::reset() {
::delete_all(); ::delete_all();
i18n_type = fld::I18n_Type::NONE; i18n.reset();
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";
include_H_from_C = 1; include_H_from_C = 1;
use_FL_COMMAND = 0; use_FL_COMMAND = 0;
@@ -167,7 +157,7 @@ std::string Project::stringsfile_path() const {
\return the file name without path \return the file name without path
*/ */
std::string Project::stringsfile_name() const { std::string Project::stringsfile_name() const {
switch (i18n_type) { switch (i18n.type) {
default: return fl_filename_setext_str(fl_filename_name(proj_filename), ".txt"); 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::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"); case fld::I18n_Type::POSIX: return fl_filename_setext_str(fl_filename_name(proj_filename), ".msg");
+3 -33
View File
@@ -19,6 +19,7 @@
#define FLUID_PROJECT_H #define FLUID_PROJECT_H
#include "proj/undo.h" #include "proj/undo.h"
#include "proj/i18n.h"
#include "nodes/Tree.h" #include "nodes/Tree.h"
#include <string> #include <string>
@@ -33,16 +34,6 @@ namespace app {
extern Layout_Preset *default_layout_preset; extern Layout_Preset *default_layout_preset;
} // 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. Data and settings for a FLUID project file.
*/ */
@@ -55,29 +46,8 @@ public: // Member Variables
// Manage the node tree of the project. // Manage the node tree of the project.
node::Tree tree { *this }; node::Tree tree { *this };
/// One of the available internationalization types. // Project internationalization.
fld::I18n_Type i18n_type = I18n_Type::NONE; proj::I18n i18n { *this };
/// 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";
/// If set, generate code to include the header file form the c++ file /// If set, generate code to include the header file form the c++ file
int include_H_from_C = 1; int include_H_from_C = 1;
+17 -17
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; std::string loc_include, loc_conditional;
if (proj_.i18n_type==fld::I18n_Type::GNU) { if (proj_.i18n.type==fld::I18n_Type::GNU) {
loc_include = proj_.i18n_gnu_include; loc_include = proj_.i18n.gnu_include;
loc_conditional = proj_.i18n_gnu_conditional; loc_conditional = proj_.i18n.gnu_conditional;
} else { } else {
loc_include = proj_.i18n_pos_include; loc_include = proj_.i18n.posix_include;
loc_conditional = proj_.i18n_pos_conditional; 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(); int conditional = !loc_conditional.empty();
if (conditional) { if (conditional) {
write_c("#ifdef %s\n", loc_conditional.c_str()); 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()); write_c("#%sinclude \"%s\"\n", indent(), loc_include.c_str());
else else
write_c("#%sinclude %s\n", indent(), loc_include.c_str()); write_c("#%sinclude %s\n", indent(), loc_include.c_str());
if (proj_.i18n_type == fld::I18n_Type::POSIX) { if (proj_.i18n.type == fld::I18n_Type::POSIX) {
if (!proj_.i18n_pos_file.empty()) { if (!proj_.i18n.posix_file.empty()) {
write_c("extern nl_catd %s;\n", proj_.i18n_pos_file.c_str()); write_c("extern nl_catd %s;\n", proj_.i18n.posix_file.c_str());
} else { } else {
write_c("// Initialize I18N stuff now for menus...\n"); write_c("// Initialize I18N stuff now for menus...\n");
write_c("#%sinclude <locale.h>\n", indent()); 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) { if (conditional) {
write_c("#else\n"); write_c("#else\n");
if (proj_.i18n_type == fld::I18n_Type::GNU) { if (proj_.i18n.type == fld::I18n_Type::GNU) {
if (!proj_.i18n_gnu_function.empty()) { if (!proj_.i18n.gnu_function.empty()) {
write_c("#%sifndef %s\n", indent(), proj_.i18n_gnu_function.c_str()); 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("#%sdefine %s(text) text\n", indent_plus(1), proj_.i18n.gnu_function.c_str());
write_c("#%sendif\n", indent()); 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("#%sifndef catgets\n", indent());
write_c("#%sdefine catgets(catalog, set, msgid, text) text\n", indent_plus(1)); write_c("#%sdefine catgets(catalog, set, msgid, text) text\n", indent_plus(1));
write_c("#%sendif\n", indent()); write_c("#%sendif\n", indent());
@@ -692,9 +692,9 @@ int Code_Writer::write_code(const char *s, const char *t, bool to_codeview) {
indentation--; indentation--;
write_c("#endif\n"); write_c("#endif\n");
} }
if (proj_.i18n_type == fld::I18n_Type::GNU && proj_.i18n_gnu_static_function[0]) { 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("#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("#%sdefine %s(text) text\n", indent_plus(1), proj_.i18n.gnu_static_function.c_str());
write_c("#endif\n"); write_c("#endif\n");
} }
} }
+2 -32
View File
@@ -261,38 +261,8 @@ Node *Project_Reader::read_children(Node *p, int merge, Strategy strategy, char
proj_.avoid_early_includes=1; proj_.avoid_early_includes=1;
goto CONTINUE; goto CONTINUE;
} }
if (!strcmp(c,"i18n_type")) { if (strncmp(c, "i18n_", 5) == 0) {
proj_.i18n_type = static_cast<fld::I18n_Type>(atoi(read_word())); proj_.i18n.read(*this, c);
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();
goto CONTINUE; goto CONTINUE;
} }
if (!strcmp(c,"header_name")) { if (!strcmp(c,"header_name")) {
+2 -22
View File
@@ -115,28 +115,8 @@ int Project_Writer::write_project(const char *filename, int selected_only, bool
write_string("\nutf8_in_src"); write_string("\nutf8_in_src");
if (proj_.avoid_early_includes) if (proj_.avoid_early_includes)
write_string("\navoid_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)); proj_.i18n.write(*this);
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;
}
}
if (!selected_only) { if (!selected_only) {
write_string("\nheader_name"); write_word(proj_.header_file_name.c_str()); write_string("\nheader_name"); write_word(proj_.header_file_name.c_str());
+1
View File
@@ -50,6 +50,7 @@ public:
int open_write(const char *s); int open_write(const char *s);
int close_write(); int close_write();
int write_project(const char *filename, int selected_only, bool codeview); int write_project(const char *filename, int selected_only, bool codeview);
void NewFunction();
void write_word(const char *); void write_word(const char *);
void write_string(const char *,...) __fl_attr((__format__ (__printf__, 2, 3))); void write_string(const char *,...) __fl_attr((__format__ (__printf__, 2, 3)));
void write_indent(int n); void write_indent(int n);
+3 -3
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. 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 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 \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`. \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"); FILE *fp = fl_fopen(filename.c_str(), "wb");
if (!fp) return 1; if (!fp) return 1;
switch (proj.i18n_type) { switch (proj.i18n.type) {
case fld::I18n_Type::NONE : /* None, just put static text out */ case fld::I18n_Type::NONE : /* None, just put static text out */
fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n", fprintf(fp, "# generated by Fast Light User Interface Designer (fluid) version %.4f\n",
FL_VERSION); 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 */ 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", fprintf(fp, "$ generated by Fast Light User Interface Designer (fluid) version %.4f\n",
FL_VERSION); 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); fputs("$quote \"\n", fp);
for (i = 1, p = proj.tree.first; p; p = p->next) { for (i = 1, p = proj.tree.first; p; p = p->next) {
+14 -14
View File
@@ -485,10 +485,10 @@ void Menu_Item_Node::write_item(fld::io::Code_Writer& f) {
write_comment_inline_c(f, " "); write_comment_inline_c(f, " ");
f.write_c(" {"); f.write_c(" {");
if (label() && label()[0]) if (label() && label()[0])
switch (Fluid.proj.i18n_type) { switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::GNU: case fld::I18n_Type::GNU:
// we will call i18n when the menu is instantiated for the first time // 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_cstring(label());
f.write_c(")"); f.write_c(")");
break; break;
@@ -591,16 +591,16 @@ void Menu_Item_Node::write_code1(fld::io::Code_Writer& f) {
f.write_c("%sml->labela = (char*)", f.indent()); f.write_c("%sml->labela = (char*)", f.indent());
image->write_inline(f); image->write_inline(f);
f.write_c(";\n"); 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()); 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.write_c("%sml->labelb = %s(o->label());\n",
f.indent(), Fluid.proj.i18n_gnu_function.c_str()); f.indent(), Fluid.proj.i18n.gnu_function.c_str());
} else if (Fluid.proj.i18n_type==fld::I18n_Type::POSIX) { } else if (Fluid.proj.i18n.type==fld::I18n_Type::POSIX) {
f.write_c("%sml->labelb = catgets(%s,%s,i+%d,o->label());\n", f.write_c("%sml->labelb = catgets(%s,%s,i+%d,o->label());\n",
f.indent(), f.indent(),
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(), Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), msgnum()); Fluid.proj.i18n.posix_set.c_str(), msgnum());
} }
f.write_c("%sml->typea = FL_IMAGE_LABEL;\n", f.indent()); f.write_c("%sml->typea = FL_IMAGE_LABEL;\n", f.indent());
f.write_c("%sml->typeb = FL_NORMAL_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"); 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(); Fl_Labeltype t = o->labeltype();
if (image) { if (image) {
// label was already copied a few lines up // label was already copied a few lines up
} else if ( t==FL_NORMAL_LABEL || t==FL_SHADOW_LABEL } else if ( t==FL_NORMAL_LABEL || t==FL_SHADOW_LABEL
|| t==FL_ENGRAVED_LABEL || t==FL_EMBOSSED_LABEL) { || t==FL_ENGRAVED_LABEL || t==FL_EMBOSSED_LABEL) {
start_menu_initialiser(f, menuItemInitialized, mname, i); 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.write_c("%so->label(%s(o->label()));\n",
f.indent(), Fluid.proj.i18n_gnu_function.c_str()); f.indent(), Fluid.proj.i18n.gnu_function.c_str());
} else if (Fluid.proj.i18n_type==fld::I18n_Type::POSIX) { } else if (Fluid.proj.i18n.type==fld::I18n_Type::POSIX) {
f.write_c("%so->label(catgets(%s,%s,i+%d,o->label()));\n", f.write_c("%so->label(catgets(%s,%s,i+%d,o->label()));\n",
f.indent(), f.indent(),
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(), Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), msgnum()); Fluid.proj.i18n.posix_set.c_str(), msgnum());
} }
} }
} }
+8 -8
View File
@@ -1601,19 +1601,19 @@ void Widget_Node::write_code1(fld::io::Code_Writer& f) {
} }
if (label() && *label()) { if (label() && *label()) {
f.write_c(", "); f.write_c(", ");
switch (Fluid.proj.i18n_type) { switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::NONE : /* None */ case fld::I18n_Type::NONE : /* None */
f.write_cstring(label()); f.write_cstring(label());
break; break;
case fld::I18n_Type::GNU : /* GNU gettext */ 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_cstring(label());
f.write_c(")"); f.write_c(")");
break; break;
case fld::I18n_Type::POSIX : /* POSIX catgets */ case fld::I18n_Type::POSIX : /* POSIX catgets */
f.write_c("catgets(%s,%s,%d,", f.write_c("catgets(%s,%s,%d,",
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(), Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), msgnum()); Fluid.proj.i18n.posix_set.c_str(), msgnum());
f.write_cstring(label()); f.write_cstring(label());
f.write_c(")"); f.write_c(")");
break; break;
@@ -1675,19 +1675,19 @@ void Widget_Node::write_widget_code(fld::io::Code_Writer& f) {
if (tooltip() && *tooltip()) { if (tooltip() && *tooltip()) {
f.write_c("%s%s->tooltip(",f.indent(), var); 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 */ case fld::I18n_Type::NONE : /* None */
f.write_cstring(tooltip()); f.write_cstring(tooltip());
break; break;
case fld::I18n_Type::GNU : /* GNU gettext */ 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_cstring(tooltip());
f.write_c(")"); f.write_c(")");
break; break;
case fld::I18n_Type::POSIX : /* POSIX catgets */ case fld::I18n_Type::POSIX : /* POSIX catgets */
f.write_c("catgets(%s,%s,%d,", f.write_c("catgets(%s,%s,%d,",
Fluid.proj.i18n_pos_file.empty() ? "_catalog" : Fluid.proj.i18n_pos_file.c_str(), Fluid.proj.i18n.posix_file.empty() ? "_catalog" : Fluid.proj.i18n.posix_file.c_str(),
Fluid.proj.i18n_pos_set.c_str(), Fluid.proj.i18n.posix_set.c_str(),
msgnum() + 1); msgnum() + 1);
f.write_cstring(tooltip()); f.write_cstring(tooltip());
f.write_c(")"); f.write_c(")");
+3 -3
View File
@@ -74,13 +74,13 @@ static void update_xywh() {
void i18n_type_cb(Fl_Choice *c, void *v) { void i18n_type_cb(Fl_Choice *c, void *v) {
if (v == LOAD) { if (v == LOAD) {
c->value(static_cast<int>(Fluid.proj.i18n_type)); c->value(static_cast<int>(Fluid.proj.i18n.type));
} else { } else {
Fluid.proj.undo.checkpoint(); 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); Fluid.proj.set_modflag(1);
} }
switch (Fluid.proj.i18n_type) { switch (Fluid.proj.i18n.type) {
case fld::I18n_Type::NONE : /* None */ case fld::I18n_Type::NONE : /* None */
i18n_gnu_group->hide(); i18n_gnu_group->hide();
i18n_posix_group->hide(); i18n_posix_group->hide();
+1 -1
View File
@@ -180,7 +180,7 @@ void update_codeview_cb(class Fl_Button*, void*) {
char fn[FL_PATH_MAX+1]; char fn[FL_PATH_MAX+1];
fl_strlcpy(fn, Fluid.get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcpy(fn, Fluid.get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(fn, "strings", 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); fld::io::write_strings(Fluid.proj, fn);
int top = cv_strings->top_line(); int top = cv_strings->top_line();
cv_strings->buffer()->loadfile(fn); cv_strings->buffer()->loadfile(fn);
+1 -1
View File
@@ -209,7 +209,7 @@ and load those into the Code Viewer widgets.} open return_type void
char fn[FL_PATH_MAX+1]; char fn[FL_PATH_MAX+1];
fl_strlcpy(fn, Fluid.get_tmpdir().c_str(), FL_PATH_MAX); fl_strlcpy(fn, Fluid.get_tmpdir().c_str(), FL_PATH_MAX);
fl_strlcat(fn, "strings", 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); fld::io::write_strings(Fluid.proj, fn);
int top = cv_strings->top_line(); int top = cv_strings->top_line();
cv_strings->buffer()->loadfile(fn); cv_strings->buffer()->loadfile(fn);
+16 -16
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) { static void cb_i18n_gnu_include_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_include.c_str()); o->value(Fluid.proj.i18n.gnu_include.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_include = o->value(); Fluid.proj.i18n.gnu_include = o->value();
Fluid.proj.set_modflag(1); 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) { static void cb_i18n_gnu_conditional_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_conditional.c_str()); o->value(Fluid.proj.i18n.gnu_conditional.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_conditional = o->value(); Fluid.proj.i18n.gnu_conditional = o->value();
Fluid.proj.set_modflag(1); 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) { static void cb_i18n_gnu_function_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_function.c_str()); o->value(Fluid.proj.i18n.gnu_function.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_function = o->value(); Fluid.proj.i18n.gnu_function = o->value();
Fluid.proj.set_modflag(1); 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) { static void cb_i18n_gnu_static_function_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_static_function.c_str()); o->value(Fluid.proj.i18n.gnu_static_function.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); 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); 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) { static void cb_i18n_pos_include_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_include.c_str()); o->value(Fluid.proj.i18n.posix_include.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_include = o->value(); Fluid.proj.i18n.posix_include = o->value();
Fluid.proj.set_modflag(1); 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) { static void cb_i18n_pos_conditional_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_conditional.c_str()); o->value(Fluid.proj.i18n.posix_conditional.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_conditional = o->value(); Fluid.proj.i18n.posix_conditional = o->value();
Fluid.proj.set_modflag(1); 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) { static void cb_i18n_pos_file_input(Fl_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_file.c_str()); o->value(Fluid.proj.i18n.posix_file.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_file = o->value(); Fluid.proj.i18n.posix_file = o->value();
Fluid.proj.set_modflag(1); 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) { static void cb_i18n_pos_set_input(Fl_Int_Input* o, void* v) {
if (v == LOAD) { if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_set.c_str()); o->value(Fluid.proj.i18n.posix_set.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_set = o->value(); Fluid.proj.i18n.posix_set = o->value();
Fluid.proj.set_modflag(1); Fluid.proj.set_modflag(1);
} }
} }
+16 -16
View File
@@ -1559,10 +1559,10 @@ if (v == LOAD) {
Fl_Input i18n_gnu_include_input { Fl_Input i18n_gnu_include_input {
label {\#include:} label {\#include:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_include.c_str()); o->value(Fluid.proj.i18n.i18n_gnu_include.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_include = o->value(); Fluid.proj.i18n.i18n_gnu_include = o->value();
Fluid.proj.set_modflag(1); 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 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 { Fl_Input i18n_gnu_conditional_input {
label {Conditional:} label {Conditional:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_conditional.c_str()); o->value(Fluid.proj.i18n.i18n_gnu_conditional.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_conditional = o->value(); Fluid.proj.i18n.i18n_gnu_conditional = o->value();
Fluid.proj.set_modflag(1); 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 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 { Fl_Input i18n_gnu_function_input {
label {Function:} label {Function:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_gnu_function.c_str()); o->value(Fluid.proj.i18n.i18n_gnu_function.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_gnu_function = o->value(); Fluid.proj.i18n.i18n_gnu_function = o->value();
Fluid.proj.set_modflag(1); 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 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 { Fl_Input i18n_gnu_static_function_input {
label {Static Function:} label {Static Function:}
callback {if (v == LOAD) { 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 { } else {
Fluid.proj.undo.checkpoint(); 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); 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 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 { Fl_Input i18n_pos_include_input {
label {\#include:} label {\#include:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_include.c_str()); o->value(Fluid.proj.i18n.i18n_pos_include.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_include = o->value(); Fluid.proj.i18n.i18n_pos_include = o->value();
Fluid.proj.set_modflag(1); 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 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 { Fl_Input i18n_pos_conditional_input {
label {Conditional:} label {Conditional:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_conditional.c_str()); o->value(Fluid.proj.i18n.i18n_pos_conditional.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_conditional = o->value(); Fluid.proj.i18n.i18n_pos_conditional = o->value();
Fluid.proj.set_modflag(1); 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 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 { Fl_Input i18n_pos_file_input {
label {Catalog:} label {Catalog:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_file.c_str()); o->value(Fluid.proj.i18n.i18n_pos_file.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_file = o->value(); Fluid.proj.i18n.i18n_pos_file = o->value();
Fluid.proj.set_modflag(1); 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 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 { Fl_Input i18n_pos_set_input {
label {Set:} label {Set:}
callback {if (v == LOAD) { callback {if (v == LOAD) {
o->value(Fluid.proj.i18n_pos_set.c_str()); o->value(Fluid.proj.i18n.i18n_pos_set.c_str());
} else { } else {
Fluid.proj.undo.checkpoint(); Fluid.proj.undo.checkpoint();
Fluid.proj.i18n_pos_set = o->value(); Fluid.proj.i18n.i18n_pos_set = o->value();
Fluid.proj.set_modflag(1); 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 tooltip {The message set number.} xywh {100 178 80 20} type Int box THIN_DOWN_BOX labelsize 11 textfont 4 textsize 11
+93
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
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