summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McDermott <patrick.mcdermott@libiquity.com>2023-04-20 14:11:29 (EDT)
committer Patrick McDermott <patrick.mcdermott@libiquity.com>2023-04-20 14:11:29 (EDT)
commit8865acffee909d1d528d30444b44dad359913c0a (patch)
tree37d411b283bcfc36c8b38dd42c5ee6f2924ec377
parent3c8577cecc0001daf53526aa790e6638c7c50a9e (diff)
parent6daf35d0b533d28c34c69e8f678ce87b970c1acb (diff)
Merge branch 'feature/i18n'
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am5
-rw-r--r--TODO1
-rwxr-xr-xautogen.sh10
-rw-r--r--configure.ac8
-rw-r--r--m4/.gitignore8
-rw-r--r--po/.gitignore11
-rw-r--r--po/Makevars26
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/i18n.h11
-rw-r--r--src/local.mk1
-rw-r--r--src/main.c112
-rw-r--r--src/opk.c32
13 files changed, 160 insertions, 70 deletions
diff --git a/.gitignore b/.gitignore
index 12aa9dd..2ff673f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,8 @@
*~
*.orig
-# Files generated by aclocal, autoconf, and automake
+# Files generated by gettextize, aclocal, autoconf, and automake
+/ABOUT-NLS
/aclocal.m4
/autom4te.cache/
/configure
diff --git a/Makefile.am b/Makefile.am
index 68131cc..b2d1c4d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -47,6 +47,7 @@ opkg_opk_CFLAGS = \
$(WARN_CFLAGS) \
$(ASAN_CFLAGS)
opkg_opk_CPPFLAGS = \
+ -DLOCALEDIR=\"$(localedir)\" \
$(ZLIB_CFLAGS)
opkg_opk_LDADD = \
$(ASAN_CFLAGS) \
@@ -55,7 +56,7 @@ opkg_opk_LINK = $(LINK) version.c
EXTRA_opkg_opk_DEPENDENCIES = version.c
CLEANFILES = version.c
CONFIG_CLEAN_FILES =
-EXTRA_DIST = autogen.sh
+EXTRA_DIST = build-aux/config.rpath autogen.sh
version.c: $(opkg_opk_OBJECTS) $(opkg_opk_DEPENDENCIES)
$(AM_V_GEN)printf 'const char *PACKAGE_VERSION_GIT = "%s";\n' \
@@ -103,3 +104,5 @@ release:
$(PACKAGE) $(VERSION) '$(PACKAGE_NAME)'
include $(top_srcdir)/src/local.mk
+
+SUBDIRS = . po
diff --git a/TODO b/TODO
deleted file mode 100644
index fb3fa82..0000000
--- a/TODO
+++ /dev/null
@@ -1 +0,0 @@
-I18n?
diff --git a/autogen.sh b/autogen.sh
index 28c30e4..f334959 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -2,7 +2,7 @@
#
# Script to generate the build system.
#
-# Copyright (C) 2013 Patrick McDermott
+# Copyright (C) 2013, 2019 Patrick McDermott
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
@@ -19,6 +19,14 @@ srcdir="${0%/*}"
cat >ChangeLog <<-EOF
This file is generated upon release. Run \`git log\` for a list of changes.
EOF
+ # Force gettextize to be non-interactive. Stupid but necessary.
+ LC_ALL=C expect -f - <<-EOF
+ spawn gettextize --force --no-changelog
+ expect "Press Return to acknowledge the previous * paragraphs."
+ send "\n"
+ EOF
+ # This file contains a huge outdated matrix of unrelated packages.
+ >ABOUT-NLS
aclocal
autoconf
autoheader
diff --git a/configure.ac b/configure.ac
index 3c0924b..f600715 100644
--- a/configure.ac
+++ b/configure.ac
@@ -29,6 +29,12 @@ AM_SILENT_RULES([yes])
AM_CONDITIONAL([IN_GIT],
[test -d "${srcdir}/.git" && command -v git >/dev/null 2>&1])
+GETTEXT_PACKAGE="${PACKAGE}"
+AC_SUBST([GETTEXT_PACKAGE])
+AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["${GETTEXT_PACKAGE}"],
+ [Define the gettext package to be used.])
+AM_GNU_GETTEXT([external])
+
save_CFLAGS="${CFLAGS-}"
AC_PROG_CC()
AM_PROG_CC_C_O()
@@ -106,6 +112,6 @@ if test "x${address_sanitization}" = 'xyes'; then
AC_SUBST([ASAN_CFLAGS])
fi
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile po/Makefile.in])
AC_CONFIG_HEADERS([config.h])
AC_OUTPUT()
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644
index 0000000..c7e2124
--- /dev/null
+++ b/m4/.gitignore
@@ -0,0 +1,8 @@
+/gettext.m4
+/iconv.m4
+/lib-ld.m4
+/lib-link.m4
+/lib-prefix.m4
+/nls.m4
+/po.m4
+/progtest.m4
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 0000000..532f823
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1,11 @@
+/Makefile.in.in
+/Makevars.template
+/Rules-quot
+/*.sed
+/POTFILES
+/*.pot
+/*.po
+/*.mo
+/*@boldquot.header
+/*@quot.header
+/stamp-po
diff --git a/po/Makevars b/po/Makevars
new file mode 100644
index 0000000..0cddd98
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,26 @@
+# Variables to be inserted into Makefile
+
+DOMAIN = $(PACKAGE)
+
+subdir = po
+top_builddir = ..
+
+XGETTEXT_OPTIONS = --add-comments=TRANSLATORS --keyword=_
+
+COPYRIGHT_HOLDER = Patrick McDermott
+
+PACKAGE_GNU = no
+
+MSGID_BUGS_ADDRESS = mailto:patrick.mcdermott@libiquity.com
+
+EXTRA_LOCALE_CATEGORIES =
+
+USE_MSGCTXT = no
+
+MSGMERGE_OPTIONS =
+
+MSGINIT_OPTIONS =
+
+PO_DEPENDS_ON_POT = yes
+
+DIST_DEPENDS_ON_UPDATE_PO = yes
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..c1b37bb
--- /dev/null
+++ b/po/POTFILES.in
@@ -0,0 +1,2 @@
+src/main.c
+src/opk.c
diff --git a/src/i18n.h b/src/i18n.h
new file mode 100644
index 0000000..4d8ee76
--- /dev/null
+++ b/src/i18n.h
@@ -0,0 +1,11 @@
+#ifdef ENABLE_NLS
+
+#include <libintl.h>
+
+#define _(msgid) gettext(msgid)
+
+#else
+
+#define _(msgid) (msgid)
+
+#endif
diff --git a/src/local.mk b/src/local.mk
index 808322f..e26508f 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -2,6 +2,7 @@ opkg_opk_SOURCES += \
%reldir%/defs.h \
%reldir%/gzip.c \
%reldir%/gzip.h \
+ %reldir%/i18n.h \
%reldir%/main.c \
%reldir%/opk.c \
%reldir%/opk.h \
diff --git a/src/main.c b/src/main.c
index 7a0efd5..5a20236 100644
--- a/src/main.c
+++ b/src/main.c
@@ -17,14 +17,18 @@
* along with opkg-opk. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
+#ifdef ENABLE_NLS
+#include <locale.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include "defs.h"
+#include "i18n.h"
#include "opk.h"
#include "ustar.h"
-#include "config.h"
-
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
@@ -72,46 +76,40 @@ struct option _longopts[] = {
static void
_help(const char *program_name)
{
- printf("Usage: %s OPTION... PACKAGE\n", program_name);
- puts("Options:");
+ printf(_("Usage: %s OPTION... PACKAGE\n"), program_name);
#ifdef HAVE_GETOPT_LONG
- puts(" -I, --info=CONTROL-FILE Print the named control file. If "
- "this option is");
- puts(" given multiple times, the named "
- "control files will be");
- puts(" printed in the order they appear in "
- "the package.");
- puts(" -f, --control Print the control file.");
- puts(" -c, --contents List the contents of the filesystem "
- "tree archive");
- puts(" portion of the package. It is "
- "currently produced in");
- puts(" a format similar to that generated by "
- "GNU and BusyBox");
- puts(" tar's verbose listing. User and "
- "group IDs and names");
- puts(" are not checked against those on the "
- "host system,");
- puts(" since they may differ.");
- puts(" -h, --help Show this help information and exit.");
- puts(" -V, --version Show version information and exit.");
+ puts(_("Options:\n"
+" -I, --info=CONTROL-FILE Print the named control file. If this option is\n"
+" given multiple times, the named control files will "
+ "be\n"
+" printed in the order they appear in the package.\n"
+" -f, --control Print the control file.\n"
+" -c, --contents List the contents of the filesystem tree archive\n"
+" portion of the package. It is currently produced "
+ "in\n"
+" a format similar to that generated by GNU and "
+ "BusyBox\n"
+" tar's verbose listing. User and group IDs and "
+ "names\n"
+" are not checked against those on the host system,\n"
+" since they may differ.\n"
+" -h, --help Show this help information and exit.\n"
+" -V, --version Show version information and exit."));
#else
- puts(" -I Print the named control file. If this option is given "
- "multiple times, the");
- puts(" named control files will be printed in the order they "
- "appear in the");
- puts(" package.");
- puts(" -f Print the control file.");
- puts(" -c List the contents of the filesystem tree archive portion "
- "of the package.");
- puts(" It is currently produced in a format similar to that "
- "generated by GNU and");
- puts(" BusyBox tar's verbose listing. User and group IDs and "
- "names are not");
- puts(" checked against those on the host system, since they may "
- "differ.");
- puts(" -h Show this help information and exit.");
- puts(" -V Show version information and exit.");
+ puts(_("Options:\n"
+" -I Print the named control file. If this option is given multiple times, "
+ "the\n"
+" named control files will be printed in the order they appear in the\n"
+" package.\n"
+" -f Print the control file.\n"
+" -c List the contents of the filesystem tree archive portion of the "
+ "package.\n"
+" It is currently produced in a format similar to that generated by GNU "
+ "and\n"
+" BusyBox tar's verbose listing. User and group IDs and names are not\n"
+" checked against those on the host system, since they may differ.\n"
+" -h Show this help information and exit.\n"
+" -V Show version information and exit."));
#endif
}
@@ -119,20 +117,24 @@ static void
_version(void)
{
printf("%s %s%s\n", PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_VERSION_GIT);
- printf("Copyright (C) %s %s\n", "2023", "Patrick McDermott");
- puts("License GPLv3+: GNU GPL version 3 or later "
+ /* TRANSLATORS: The "%s" conversion specifications are the copyright
+ * year(s) and copyright holder(s), respectively. */
+ printf(_("Copyright (C) %s %s\n"), "2023", "Patrick McDermott");
+ puts(_("License GPLv3+: GNU GPL version 3 or later "
"<http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and "
"redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by "
- "law.\n");
- printf("Please report bugs to <%s>.\n", PACKAGE_BUGREPORT);
+ "law.\n"));
+ printf(_("Please report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
static void
_help_tip(const char *program_name)
{
- fprintf(stderr, "Try \"%s %s\" for more information\n", program_name,
+ /* TRANSLATORS: The "%s" conversion specifications are the program name
+ * and help option, respectively. */
+ fprintf(stderr, _("Try \"%s %s\" for more information\n"), program_name,
#ifdef HAVE_GETOPT_LONG
"--help"
#else
@@ -150,6 +152,15 @@ main(int argc, char *argv[])
int opt;
struct opkg_opk_opk *opk;
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset(PACKAGE, "UTF-8");
+#endif
+ textdomain(PACKAGE);
+ setlocale(LC_ALL, "");
+#endif
+
program_name = argv[0];
control_files = NULL;
list_members = 0;
@@ -185,7 +196,8 @@ main(int argc, char *argv[])
_version();
return EXIT_SUCCESS;
default:
- fprintf(stderr, "%s: Invalid option: \"%c\"\n",
+ fprintf(stderr, _("%s: Invalid option: "
+ "\"%c\"\n"),
program_name, optopt);
_help_tip(program_name);
return EXIT_FAILURE;
@@ -195,19 +207,19 @@ main(int argc, char *argv[])
argv += optind;
if (argc < 1) {
- fprintf(stderr, "%s: Missing package file operand\n",
+ fprintf(stderr, _("%s: Missing package file operand\n"),
program_name);
_help_tip(program_name);
return EXIT_FAILURE;
} else if (argc > 1) {
- fprintf(stderr, "%s: Too many package file operands\n",
+ fprintf(stderr, _("%s: Too many package file operands\n"),
program_name);
_help_tip(program_name);
return EXIT_FAILURE;
}
if (control_files == NULL && list_members == 0) {
- fprintf(stderr, "%s: At least one of -I, -f, or -c must be "
- "given\n", program_name);
+ fprintf(stderr, _("%s: At least one of -I, -f, or -c must be "
+ "given\n"), program_name);
_help_tip(program_name);
return EXIT_FAILURE;
}
diff --git a/src/opk.c b/src/opk.c
index 578f85b..ddcacea 100644
--- a/src/opk.c
+++ b/src/opk.c
@@ -24,6 +24,7 @@
#include <time.h>
#include "defs.h"
#include "gzip.h"
+#include "i18n.h"
#include "opk.h"
#include "ustar.h"
@@ -69,7 +70,7 @@ opkg_opk_opk_init(const char *file_name)
/* Open outer archive. */
opk->file = fopen(file_name, "rb");
if (opk->file == NULL) {
- fprintf(stderr, "Error: Failed to open file \"%s\"\n",
+ fprintf(stderr, _("Error: Failed to open file \"%s\"\n"),
file_name);
goto error1;
}
@@ -77,34 +78,34 @@ opkg_opk_opk_init(const char *file_name)
/* Initialize outer gzip decompressor. */
opk->outer_gzip = opkg_opk_gzip_init(&_opkg_opk_opk_file_read, opk);
if (opk->outer_gzip == NULL) {
- fputs("Error: Failed to initialize\n", stderr);
+ fputs(_("Error: Failed to initialize\n"), stderr);
goto error2;
}
/* Initialize outer ustar unarchiver. */
opk->outer_ustar = opkg_opk_ustar_init(opk->outer_gzip);
if (opk->outer_ustar == NULL) {
- fputs("Error: Failed to initialize\n", stderr);
+ fputs(_("Error: Failed to initialize\n"), stderr);
goto error3;
}
/* Check package version. */
if (opkg_opk_ustar_seek_one(opk->outer_ustar, "debian-binary") !=
OPKG_OPK_OK) {
- fputs("Error: Failed to find \"debian-binary\" in archive\n",
+ fputs(_("Error: Failed to find \"debian-binary\" in archive\n"),
stderr);
goto error4;
}
if (opkg_opk_ustar_read(opk->outer_ustar,
&opk->version_buffer, &opk->version_size) !=
OPKG_OPK_OK) {
- fputs("Error: Failed to read \"debian-binary\" in archive\n",
+ fputs(_("Error: Failed to read \"debian-binary\" in archive\n"),
stderr);
goto error4;
}
if (opk->version_size < 4 || strncmp(opk->version_buffer, "2.", 2) != 0)
{
- fputs("Error: Unsupported package version\n", stderr);
+ fputs(_("Error: Unsupported package version\n"), stderr);
goto error4;
}
@@ -133,13 +134,13 @@ _opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member)
while ((ret = opkg_opk_ustar_read(opk->outer_ustar, NULL, NULL)) ==
OPKG_OPK_OK);
if (ret == OPKG_OPK_ERROR) {
- fputs("Error: Failed to read archive\n", stderr);
+ fputs(_("Error: Failed to read archive\n"), stderr);
return OPKG_OPK_ERROR;
}
/* Find requested inner archive. */
if (opkg_opk_ustar_seek_one(opk->outer_ustar, member) != OPKG_OPK_OK) {
- fprintf(stderr, "Error: Failed to find \"%s\" in archive\n",
+ fprintf(stderr, _("Error: Failed to find \"%s\" in archive\n"),
member);
return OPKG_OPK_ERROR;
}
@@ -149,14 +150,14 @@ _opkg_opk_opk_init_inner(struct opkg_opk_opk *opk, const char *member)
(opkg_opk_gzip_read_func *) &opkg_opk_ustar_read,
opk->outer_ustar);
if (opk->inner_gzip == NULL) {
- fputs("Error: Failed to initialize\n", stderr);
+ fputs(_("Error: Failed to initialize\n"), stderr);
return OPKG_OPK_ERROR;
}
/* Initialize inner ustar unarchiver. */
opk->inner_ustar = opkg_opk_ustar_init(opk->inner_gzip);
if (opk->inner_ustar == NULL) {
- fputs("Error: Failed to initialize\n", stderr);
+ fputs(_("Error: Failed to initialize\n"), stderr);
opkg_opk_gzip_free(opk->inner_gzip);
return OPKG_OPK_ERROR;
}
@@ -193,14 +194,15 @@ opkg_opk_opk_read_control(struct opkg_opk_opk *opk,
&buffer, &size)) == OPKG_OPK_OK)
{
if (fwrite(buffer, 1, size, stdout) != size) {
- fputs("Error: Failed to print control file\n",
- stderr);
+ fputs(_("Error: Failed to print control file\n")
+ , stderr);
_opkg_opk_opk_free_inner(opk);
return OPKG_OPK_ERROR;
}
}
if (ret_read == OPKG_OPK_ERROR) {
- fputs("Error: Failed to read control file\n", stderr);
+ fputs(_("Error: Failed to read control file\n"),
+ stderr);
_opkg_opk_opk_free_inner(opk);
return OPKG_OPK_ERROR;
}
@@ -210,7 +212,7 @@ opkg_opk_opk_read_control(struct opkg_opk_opk *opk,
}
}
if (ret_seek == OPKG_OPK_ERROR) {
- fputs("Error: Failed to find control file\n", stderr);
+ fputs(_("Error: Failed to find control file\n"), stderr);
_opkg_opk_opk_free_inner(opk);
return OPKG_OPK_ERROR;
}
@@ -273,7 +275,7 @@ opkg_opk_opk_list_members(struct opkg_opk_opk *opk)
}
}
if (ret == OPKG_OPK_ERROR) {
- fputs("Error: Failed to list data files\n", stderr);
+ fputs(_("Error: Failed to list data files\n"), stderr);
_opkg_opk_opk_free_inner(opk);
return OPKG_OPK_ERROR;
}