diff options
author | Patrick 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) |
commit | 8865acffee909d1d528d30444b44dad359913c0a (patch) | |
tree | 37d411b283bcfc36c8b38dd42c5ee6f2924ec377 | |
parent | 3c8577cecc0001daf53526aa790e6638c7c50a9e (diff) | |
parent | 6daf35d0b533d28c34c69e8f678ce87b970c1acb (diff) |
Merge branch 'feature/i18n'
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rwxr-xr-x | autogen.sh | 10 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | m4/.gitignore | 8 | ||||
-rw-r--r-- | po/.gitignore | 11 | ||||
-rw-r--r-- | po/Makevars | 26 | ||||
-rw-r--r-- | po/POTFILES.in | 2 | ||||
-rw-r--r-- | src/i18n.h | 11 | ||||
-rw-r--r-- | src/local.mk | 1 | ||||
-rw-r--r-- | src/main.c | 112 | ||||
-rw-r--r-- | src/opk.c | 32 |
13 files changed, 160 insertions, 70 deletions
@@ -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 @@ -1 +0,0 @@ -I18n? @@ -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 \ @@ -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; } @@ -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; } |