* gettext-tools/doc/lang-ocaml.texi: New file.
* gettext-tools/doc/Makefile.am (gettext_TEXINFOS): Add it.
* gettext-tools/doc/gettext.texi (No string concatenation): Mention string
concatenation in OCaml.
(List of Programming Languages): Include lang-ocaml.texi.
* gettext-tools/doc/xgettext.texi: Document the -L OCaml option.
* gettext-tools/src/x-ocaml.h: New file.
* gettext-tools/src/x-ocaml.c: New file.
* gettext-tools/src/xgettext.c: Include x-ocaml.h.
(flag_table_ocaml): New variable.
(main): Invoke init_flag_table_ocaml, x_ocaml_extract_all, x_ocaml_keyword.
(usage): Document the -L OCaml option.
(language_to_extractor, extension_to_language): Support OCaml.
* gettext-tools/src/FILES: Mention x-ocaml.h, x-ocaml.c.
* gettext-tools/src/Makefile.am (noinst_HEADERS): Add x-ocaml.h.
(xgettext_SOURCES): Add x-ocaml.c.
* gettext-tools/po/POTFILES.in: Add src/x-ocaml.c.
lang-pascal.texi \
lang-modula2.texi \
lang-d.texi \
+ lang-ocaml.texi \
lang-smalltalk.texi \
lang-vala.texi \
lang-wxwidgets.texi \
* Lua:: Lua
* Pascal:: Pascal - Free Pascal Compiler
* Modula-2:: Modula-2
+* OCaml:: OCaml
* Smalltalk:: GNU Smalltalk
* Vala:: Vala
* wxWidgets:: wxWidgets library
@cindex Lua, string concatenation
@cindex Modula-2, string concatenation
@cindex D, string concatenation
+@cindex OCaml, string concatenation
@cindex Smalltalk, string concatenation
@cindex Vala, string concatenation
@cindex Perl, string concatenation
In D, string concatenation is denoted by the @samp{~} operator.
@c Reference: https://dlang.org/spec/expression.html#cat_expressions
@item
+In OCaml, string concatenation is denoted by the @samp{^} operator.
+@c Reference: https://ocaml.org/manual/5.3/api/String.html#concat
+@item
In Smalltalk, string concatenation is denoted by the @samp{,} operator.
@c Reference: https://rmod-files.lille.inria.fr/FreeBooks/ByExample/14%20-%20Chapter%2012%20-%20Strings.pdf
@item
* Pascal:: Pascal - Free Pascal Compiler
* Modula-2:: Modula-2
* D:: D
+* OCaml:: OCaml
* Smalltalk:: GNU Smalltalk
* Vala:: Vala
* wxWidgets:: wxWidgets library
@include lang-pascal.texi
@include lang-modula2.texi
@include lang-d.texi
+@include lang-ocaml.texi
@include lang-smalltalk.texi
@include lang-vala.texi
@include lang-wxwidgets.texi
--- /dev/null
+@c This file is part of the GNU gettext manual.
+@c Copyright (C) 1995-2025 Free Software Foundation, Inc.
+@c See the file gettext.texi for copying conditions.
+
+@node OCaml
+@subsection OCaml
+@cindex OCaml
+
+@table @asis
+@item RPMs
+ocaml, ocaml-gettext-devel
+
+@item Ubuntu packages
+ocaml, opam
+@*@code{opam install gettext-stub}
+
+@item File extension
+@code{ml}
+
+@item String syntax
+@code{"abc"}
+
+@item gettext shorthand
+@code{(s_ "abc")} or, for format strings, @code{(f_ "abc")}
+
+@item gettext/ngettext functions
+@code{s_}, @code{f_}, @code{sn_}, @code{fn_}
+
+@item textdomain
+@code{textdomain} field in first parameter of @code{Gettext.Program}
+
+@item bindtextdomain
+@code{dir} field in first parameter of @code{Gettext.Program}
+
+@item setlocale
+---
+
+@item Prerequisite
+Declare the libraries @code{gettext.base} and @code{gettext-stub}
+in the @samp{dune} file.
+
+@item Use or emulate GNU gettext
+Use (assuming that you pass @code{GettextStub.Native}
+as second parameter of @code{Gettext.Program})
+
+@item Extractor
+@code{xgettext}
+
+@item Formatting with positions
+---
+
+@item Portability
+fully portable
+
+@item po-mode marking
+---
+@end table
+
+@c An example is available in the @file{examples} directory: @code{hello-ocaml}.
@code{Lua},
@code{Modula-2},
@code{D},
+@code{OCaml},
@code{Smalltalk},
@code{Vala},
@code{Tcl},
src/x-lisp.c
src/x-lua.c
src/x-modula2.c
+src/x-ocaml.c
src/x-perl.c
src/x-php.c
src/x-po.c
| x-d.c
| html5-entities.h
| String extractor for D.
+| x-ocaml.h
+| x-ocaml.c
+| String extractor for OCaml.
| x-smalltalk.h
| x-smalltalk.c
| String extractor for Smalltalk.
x-lua.h \
x-modula2.h \
x-d.h html5-entities.h \
+ x-ocaml.h \
x-smalltalk.h \
x-vala.h \
x-tcl.h \
x-lua.c \
x-modula2.c \
x-d.c \
+ x-ocaml.c \
x-smalltalk.c \
x-vala.c \
x-tcl.c \
--- /dev/null
+/* xgettext OCaml backend.
+ Copyright (C) 2020-2025 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2025.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Specification. */
+#include "x-ocaml.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <error.h>
+#include "message.h"
+#include "clean-temp.h"
+#include "concat-filename.h"
+#include "execute.h"
+#include "xvasprintf.h"
+#include "x-po.h"
+#include "xgettext.h"
+#include "gettext.h"
+
+/* A convenience macro. I don't like writing gettext() every time. */
+#define _(str) gettext (str)
+
+/* We don't parse OCaml directly, but instead rely on the 'ocaml-gettext'
+ program, that invokes the 'ocaml-xgettext' program. Both are contained
+ in the 'opam' package named 'gettext':
+ https://opam.ocaml.org/packages/gettext/
+ https://github.com/gildor478/ocaml-gettext
+ https://github.com/gildor478/ocaml-gettext/blob/master/doc/reference-manual.md
+
+ Comments start with '(*' and end with '*)' and can be nested.
+ Reference: <https://ocaml.org/docs/tour-of-ocaml>
+ */
+
+
+/* ====================== Keyword set customization. ====================== */
+
+/* This function currently has no effect. */
+void
+x_ocaml_extract_all (void)
+{
+}
+
+/* This function currently has no effect. */
+void
+x_ocaml_keyword (const char *keyword)
+{
+}
+
+/* This function currently has no effect. */
+void
+init_flag_table_ocaml (void)
+{
+}
+
+
+/* ========================= Extracting strings. ========================== */
+
+static bool
+is_not_header (const message_ty *mp)
+{
+ return !is_header (mp);
+}
+
+void
+extract_ocaml (const char *found_in_dir, const char *real_filename,
+ const char *logical_filename,
+ flag_context_list_table_ty *flag_table,
+ msgdomain_list_ty *mdlp)
+{
+ /* Invoke
+ ocaml-gettext --action extract --extract-pot <temp>.pot real_filename */
+
+ /* First, create a temporary directory where this invocation can place its
+ output. */
+ struct temp_dir *tmpdir = create_temp_dir ("ocgt", NULL, false);
+ if (tmpdir == NULL)
+ exit (EXIT_FAILURE);
+
+ /* Prepare the temporary POT file name. */
+ char *temp_file_name = xconcatenated_filename (tmpdir->dir_name, "temp.pot", NULL);
+ register_temp_file (tmpdir, temp_file_name);
+
+ /* Invoke ocaml-gettext. */
+ const char *progname = "ocaml-gettext";
+ {
+ const char *argv[7];
+ int exitstatus;
+ /* Prepare arguments. */
+ argv[0] = progname;
+ argv[1] = "--action";
+ argv[2] = "extract";
+ argv[3] = "--extract-pot";
+ argv[4] = temp_file_name;
+ argv[5] = logical_filename;
+ argv[6] = NULL;
+ exitstatus = execute (progname, progname, argv, NULL, found_in_dir,
+ true, false, false, false, true, false, NULL);
+ if (exitstatus != 0)
+ error (EXIT_FAILURE, 0, _("%s subprocess failed with exit code %d"),
+ progname, exitstatus);
+ }
+
+ /* Read the resulting POT file. */
+ {
+ FILE *fp = fopen (temp_file_name, "r");
+ if (fp == NULL)
+ error (EXIT_FAILURE, 0, _("%s subprocess did not create the expected file"),
+ progname);
+ char *dummy_filename = xasprintf (_("(output from '%s')"), progname);
+ extract_po (fp, temp_file_name, dummy_filename, flag_table, mdlp);
+ fclose (fp);
+ free (dummy_filename);
+ }
+
+ cleanup_temp_dir (tmpdir);
+
+ if (xgettext_omit_header)
+ {
+ /* Remove the header entry. */
+ if (mdlp->nitems > 0)
+ message_list_remove_if_not (mdlp->item[0]->messages, is_not_header);
+ }
+}
--- /dev/null
+/* xgettext OCaml backend.
+ Copyright (C) 2020-2025 Free Software Foundation, Inc.
+ Written by Bruno Haible <bruno@clisp.org>, 2025.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+
+#include <stdio.h>
+
+#include "message.h"
+#include "xg-arglist-context.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define EXTENSIONS_OCAML \
+ { "ml", "OCaml" }, \
+
+#define SCANNERS_OCAML \
+ { "OCaml", NULL, extract_ocaml, \
+ NULL, NULL, NULL }, \
+
+extern void extract_ocaml (const char *found_in_dir, const char *real_filename,
+ const char *logical_filename,
+ flag_context_list_table_ty *flag_table,
+ msgdomain_list_ty *mdlp);
+
+extern void x_ocaml_keyword (const char *keyword);
+extern void x_ocaml_extract_all (void);
+
+extern void init_flag_table_ocaml (void);
+
+
+#ifdef __cplusplus
+}
+#endif
#include "x-lua.h"
#include "x-modula2.h"
#include "x-d.h"
+#include "x-ocaml.h"
#include "x-smalltalk.h"
#include "x-vala.h"
#include "x-tcl.h"
init_flag_table_lua ();
init_flag_table_modula2 ();
init_flag_table_d ();
+ init_flag_table_ocaml ();
init_flag_table_vala ();
init_flag_table_tcl ();
init_flag_table_perl ();
x_lua_extract_all ();
x_modula2_extract_all ();
x_d_extract_all ();
+ x_ocaml_extract_all ();
x_vala_extract_all ();
x_tcl_extract_all ();
x_perl_extract_all ();
x_lua_keyword (optarg);
x_modula2_keyword (optarg);
x_d_keyword (optarg);
+ x_ocaml_keyword (optarg);
x_vala_keyword (optarg);
x_tcl_keyword (optarg);
x_perl_keyword (optarg);
(C, C++, ObjectiveC, PO, Python, Java,\n\
JavaProperties, C#, JavaScript, TypeScript, TSX,\n\
Scheme, Guile, Lisp, EmacsLisp, librep, Rust,\n\
- Go, Ruby, Shell, awk, Lua, Modula-2, D,\n\
+ Go, Ruby, Shell, awk, Lua, Modula-2, D, OCaml,\n\
Smalltalk, Vala, Tcl, Perl, PHP, GCC-source,\n\
YCP, NXStringTable, RST, RSJ, Glade, GSettings,\n\
Desktop)\n"));
SCANNERS_LUA
SCANNERS_MODULA2
SCANNERS_D
+ SCANNERS_OCAML
SCANNERS_SMALLTALK
SCANNERS_VALA
SCANNERS_TCL
EXTENSIONS_LUA
EXTENSIONS_MODULA2
EXTENSIONS_D
+ EXTENSIONS_OCAML
EXTENSIONS_SMALLTALK
EXTENSIONS_VALA
EXTENSIONS_TCL