summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Pelz <pelzflorian@pelzflorian.de>2017-12-09 17:46:51 +0100
committerFlorian Pelz <pelzflorian@pelzflorian.de>2017-12-09 17:46:51 +0100
commit5f97bf157eaddcfe722c97dcab349b7dcfbbcd9d (patch)
treed624f9597e5d127b67333725c36cad2653be7a91
parent6a6a82ddca3527610f561a601a3c02ec9f9f0c86 (diff)
Use Gettext PO files for translations with libgettextpo.
I want to avoid repeated setlocale calls and thus am not using the gettext function directly. See the code comments for details.
-rw-r--r--NOTES26
-rw-r--r--gettext-po.ffi4
-rw-r--r--gettext-po.scm927
-rw-r--r--haunt.scm262
-rw-r--r--po/LINGUAS2
-rw-r--r--po/POTFILES1
-rw-r--r--po/de.po309
-rw-r--r--po/en.po309
8 files changed, 1705 insertions, 135 deletions
diff --git a/NOTES b/NOTES
new file mode 100644
index 0000000..bcb77c7
--- /dev/null
+++ b/NOTES
@@ -0,0 +1,26 @@
+This is the code for my personal website built with Haunt. Since I
+want translations to work with po files but without repeatedly calling
+setlocale, I’m using the ffi-helper in nyacc
+<savannah.nongnu.org/projects/nyacc/> to call libgettextpo to parse
+the po files.
+
+gettext-po.scm was created with the ffi-helper.
+
+To create a pot file, call:
+
+xgettext -f po/POTFILES -o po/pelzfloriande-website.pot --from-code=UTF-8 --copyright-holder="" --package-name="pelzfloriande-website" --msgid-bugs-address="pelzflorian@pelzflorian.de" --keyword=_
+
+To create a po file from a pot file, do the usual:
+
+cd po
+msginit -l de --no-translator
+
+To build the site, assuming nyacc’s source is in
+$HOME/build/nyacc/src/nyacc:
+
+GUILE_LOAD_PATH=$HOME/keep/projects/pelzfloriande-website:$HOME/build/nyacc/src/nyacc/examples:$GUILE_LOAD_PATH GUILE_LOAD_COMPILED_PATH=$GUILE_LOAD_COMPILED_PATH:$HOME/.cache/guile/ccache/2.2-LE-8-3.A/home/florian/keep/projects/pelzfloriande-website haunt build
+
+Use this to run guile with strace for debugging. It’s probably easiest
+to do this from Emacs; I’m currently using M-x shell in Emacs.
+
+GUILE_LOAD_PATH=$HOME/keep/projects/pelzfloriande-website:$HOME/build/nyacc/src/nyacc/examples:$GUILE_LOAD_PATH GUILE_LOAD_COMPILED_PATH=$GUILE_LOAD_COMPILED_PATH:$HOME/.cache/guile/ccache/2.2-LE-8-3.A/home/florian/keep/projects/pelzfloriande-website strace -o out guile
diff --git a/gettext-po.ffi b/gettext-po.ffi
new file mode 100644
index 0000000..55962b7
--- /dev/null
+++ b/gettext-po.ffi
@@ -0,0 +1,4 @@
+(define-ffi-module (gettext-po)
+ #:include '("gettext-po.h")
+ #:library '("libgettextpo"))
+
diff --git a/gettext-po.scm b/gettext-po.scm
new file mode 100644
index 0000000..590d77c
--- /dev/null
+++ b/gettext-po.scm
@@ -0,0 +1,927 @@
+;; generated with `guild compile-ffi gettext-po.ffi'
+
+(define-module (gettext-po)
+ #:use-module (system ffi-help-rt)
+ #:use-module ((system foreign) #:prefix ffi:)
+ #:use-module (bytestructures guile)
+ )
+(define link-lib (dynamic-link "libgettextpo"))
+
+;; extern int libgettextpo_version;
+(define libgettextpo_version
+ (let* ((addr #f)
+ (memoize-addr
+ (lambda ()
+ (unless
+ addr
+ (set! addr
+ (make-bytestructure
+ (ffi:pointer->bytevector
+ (dynamic-pointer
+ "libgettextpo_version"
+ (dynamic-link))
+ (ffi:sizeof '*))
+ 0
+ (bs:pointer int)))))))
+ (case-lambda
+ (() (memoize-addr) (bytestructure-ref addr '*)))))
+(export libgettextpo_version)
+
+;; typedef struct po_file *po_file_t;
+(define-public po_file_t-desc (bs:pointer 'void))
+(define-fh-pointer-type po_file_t po_file_t-desc po_file_t? make-po_file_t)
+(export po_file_t po_file_t? make-po_file_t)
+
+;; typedef struct po_message_iterator *po_message_iterator_t;
+(define-public po_message_iterator_t-desc (bs:pointer 'void))
+(define-fh-pointer-type po_message_iterator_t po_message_iterator_t-desc
+ po_message_iterator_t? make-po_message_iterator_t)
+(export po_message_iterator_t po_message_iterator_t?
+ make-po_message_iterator_t)
+
+;; typedef struct po_message *po_message_t;
+(define-public po_message_t-desc (bs:pointer 'void))
+(define-fh-pointer-type po_message_t po_message_t-desc po_message_t?
+ make-po_message_t)
+(export po_message_t po_message_t? make-po_message_t)
+
+;; typedef struct po_filepos *po_filepos_t;
+(define-public po_filepos_t-desc (bs:pointer 'void))
+(define-fh-pointer-type po_filepos_t po_filepos_t-desc po_filepos_t?
+ make-po_filepos_t)
+(export po_filepos_t po_filepos_t? make-po_filepos_t)
+
+;; struct po_error_handler {
+;; /* Signal an error. The error message is built from FORMAT and the following
+;;
+;; arguments. ERRNUM, if nonzero, is an errno value.
+;; Must increment the error_message_count variable declared in error.h.
+;; Must not return if STATUS is nonzero. */
+;; void (*error)(int status, int errnum, const char *format, ...);
+;; /* Signal an error. The error message is built from FORMAT and the following
+;;
+;; arguments. The error location is at FILENAME line LINENO. ERRNUM, if
+;; nonzero, is an errno value.
+;; Must increment the error_message_count variable declared in error.h.
+;; Must not return if STATUS is nonzero. */
+;; void (*error_at_line)(int status, int errnum, const char *filename,
+;; unsigned int lineno, const char *format, ...);
+;; /* Signal a multiline warning. The PREFIX applies to all lines of the
+;; MESSAGE. Free the PREFIX and MESSAGE when done. */
+;; void (*multiline_warning)(char *prefix, char *message);
+;; /* Signal a multiline error. The PREFIX applies to all lines of the
+;; MESSAGE. Free the PREFIX and MESSAGE when done.
+;; Must increment the error_message_count variable declared in error.h if
+;; PREFIX is non-NULL. */
+;; void (*multiline_error)(char *prefix, char *message);
+;; };
+(define-public struct-po_error_handler-desc
+ (bs:struct
+ (list `(error ,(bs:pointer 'void))
+ `(error_at_line ,(bs:pointer 'void))
+ `(multiline_warning ,(bs:pointer 'void))
+ `(multiline_error ,(bs:pointer 'void)))))
+(define-fh-compound-type struct-po_error_handler struct-po_error_handler-desc
+ struct-po_error_handler? make-struct-po_error_handler)
+(export struct-po_error_handler struct-po_error_handler?
+ make-struct-po_error_handler)
+(define-public struct-po_error_handler*-desc
+ (bs:pointer struct-po_error_handler-desc))
+(define-fh-pointer-type struct-po_error_handler* struct-po_error_handler*-desc
+ struct-po_error_handler*? make-struct-po_error_handler*)
+(export struct-po_error_handler* struct-po_error_handler*?
+ make-struct-po_error_handler*)
+(ref<->deref!
+ struct-po_error_handler*
+ make-struct-po_error_handler*
+ struct-po_error_handler
+ make-struct-po_error_handler)
+
+;; typedef const struct po_error_handler *po_error_handler_t;
+(define-public po_error_handler_t&-desc 'void)
+(define-public po_error_handler_t-desc (bs:pointer (delay po_error_handler_t&-desc)))
+(define-fh-pointer-type po_error_handler_t po_error_handler_t-desc
+ po_error_handler_t? make-po_error_handler_t)
+(export po_error_handler_t po_error_handler_t? make-po_error_handler_t)
+
+;; struct po_xerror_handler {
+;; /* Signal a problem of the given severity.
+;; MESSAGE and/or FILENAME + LINENO indicate where the problem occurred.
+;; If FILENAME is NULL, FILENAME and LINENO and COLUMN should be ignored.
+;; If LINENO is (size_t)(-1), LINENO and COLUMN should be ignored.
+;; If COLUMN is (size_t)(-1), it should be ignored.
+;; MESSAGE_TEXT is the problem description (if MULTILINE_P is true,
+;; multiple lines of text, each terminated with a newline, otherwise
+;; usually a single line).
+;; Must not return if SEVERITY is PO_SEVERITY_FATAL_ERROR. */
+;; void (*xerror)(int severity, po_message_t message, const char *filename,
+;; size_t lineno, size_t column, int multiline_p, const char *
+;; message_text);
+;; /* Signal a problem that refers to two messages.
+;; Similar to two calls to xerror.
+;; If possible, a "..." can be appended to MESSAGE_TEXT1 and prepended to
+;; MESSAGE_TEXT2. */
+;; void (*xerror2)(int severity, po_message_t message1, const char *filename1
+;; , size_t lineno1, size_t column1, int multiline_p1, const char *
+;; message_text1, po_message_t message2, const char *filename2, size_t
+;; lineno2, size_t column2, int multiline_p2, const char *message_text2)
+;; ;
+;; };
+(define-public struct-po_xerror_handler-desc
+ (bs:struct
+ (list `(xerror ,(bs:pointer 'void))
+ `(xerror2 ,(bs:pointer 'void)))))
+(define-fh-compound-type struct-po_xerror_handler
+ struct-po_xerror_handler-desc struct-po_xerror_handler?
+ make-struct-po_xerror_handler)
+(export struct-po_xerror_handler struct-po_xerror_handler?
+ make-struct-po_xerror_handler)
+(define-public struct-po_xerror_handler*-desc
+ (bs:pointer struct-po_xerror_handler-desc))
+(define-fh-pointer-type struct-po_xerror_handler*
+ struct-po_xerror_handler*-desc struct-po_xerror_handler*?
+ make-struct-po_xerror_handler*)
+(export struct-po_xerror_handler* struct-po_xerror_handler*?
+ make-struct-po_xerror_handler*)
+(ref<->deref!
+ struct-po_xerror_handler*
+ make-struct-po_xerror_handler*
+ struct-po_xerror_handler
+ make-struct-po_xerror_handler)
+
+;; typedef const struct po_xerror_handler *po_xerror_handler_t;
+(define-public po_xerror_handler_t&-desc 'void)
+(define-public po_xerror_handler_t-desc (bs:pointer (delay po_xerror_handler_t&-desc)))
+(define-fh-pointer-type po_xerror_handler_t po_xerror_handler_t-desc
+ po_xerror_handler_t? make-po_xerror_handler_t)
+(export po_xerror_handler_t po_xerror_handler_t? make-po_xerror_handler_t)
+
+;; extern po_file_t po_file_create(void);
+(define ~po_file_create
+ (delay (fh-link-proc
+ ffi-void*
+ "po_file_create"
+ (list)
+ link-lib)))
+(define (po_file_create)
+ (let ()
+ ((fht-wrap po_file_t) ((force ~po_file_create)))))
+(export po_file_create)
+
+;; extern po_file_t po_file_read_v3(const char *filename, po_xerror_handler_t
+;; handler);
+(define ~po_file_read_v3
+ (delay (fh-link-proc
+ ffi-void*
+ "po_file_read_v3"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_file_read_v3 filename handler)
+ (let ((~filename (unwrap~pointer filename))
+ (~handler
+ ((fht-unwrap po_xerror_handler_t) handler)))
+ ((fht-wrap po_file_t)
+ ((force ~po_file_read_v3) ~filename ~handler))))
+(export po_file_read_v3)
+
+;; extern po_file_t po_file_write_v2(po_file_t file, const char *filename,
+;; po_xerror_handler_t handler);
+(define ~po_file_write_v2
+ (delay (fh-link-proc
+ ffi-void*
+ "po_file_write_v2"
+ (list ffi-void* ffi-void* ffi-void*)
+ link-lib)))
+(define (po_file_write_v2 file filename handler)
+ (let ((~file ((fht-unwrap po_file_t) file))
+ (~filename (unwrap~pointer filename))
+ (~handler
+ ((fht-unwrap po_xerror_handler_t) handler)))
+ ((fht-wrap po_file_t)
+ ((force ~po_file_write_v2)
+ ~file
+ ~filename
+ ~handler))))
+(export po_file_write_v2)
+
+;; extern void po_file_free(po_file_t file);
+(define ~po_file_free
+ (delay (fh-link-proc
+ ffi:void
+ "po_file_free"
+ (list ffi-void*)
+ link-lib)))
+(define (po_file_free file)
+ (let ((~file ((fht-unwrap po_file_t) file)))
+ ((force ~po_file_free) ~file)))
+(export po_file_free)
+
+;; extern const char *const*po_file_domains(po_file_t file);
+(define ~po_file_domains
+ (delay (fh-link-proc
+ ffi-void*
+ "po_file_domains"
+ (list ffi-void*)
+ link-lib)))
+(define (po_file_domains file)
+ (let ((~file ((fht-unwrap po_file_t) file)))
+ ((force ~po_file_domains) ~file)))
+(export po_file_domains)
+
+;; extern const char *po_file_domain_header(po_file_t file, const char *domain)
+;; ;
+(define ~po_file_domain_header
+ (delay (fh-link-proc
+ ffi-void*
+ "po_file_domain_header"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_file_domain_header file domain)
+ (let ((~file ((fht-unwrap po_file_t) file))
+ (~domain (unwrap~pointer domain)))
+ ((force ~po_file_domain_header) ~file ~domain)))
+(export po_file_domain_header)
+
+;; extern char *po_header_field(const char *header, const char *field);
+(define ~po_header_field
+ (delay (fh-link-proc
+ ffi-void*
+ "po_header_field"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_header_field header field)
+ (let ((~header (unwrap~pointer header))
+ (~field (unwrap~pointer field)))
+ ((force ~po_header_field) ~header ~field)))
+(export po_header_field)
+
+;; extern char *po_header_set_field(const char *header, const char *field,
+;; const char *value);
+(define ~po_header_set_field
+ (delay (fh-link-proc
+ ffi-void*
+ "po_header_set_field"
+ (list ffi-void* ffi-void* ffi-void*)
+ link-lib)))
+(define (po_header_set_field header field value)
+ (let ((~header (unwrap~pointer header))
+ (~field (unwrap~pointer field))
+ (~value (unwrap~pointer value)))
+ ((force ~po_header_set_field)
+ ~header
+ ~field
+ ~value)))
+(export po_header_set_field)
+
+;; extern po_message_iterator_t po_message_iterator(po_file_t file, const char
+;; *domain);
+(define ~po_message_iterator
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_iterator"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_iterator file domain)
+ (let ((~file ((fht-unwrap po_file_t) file))
+ (~domain (unwrap~pointer domain)))
+ ((fht-wrap po_message_iterator_t)
+ ((force ~po_message_iterator) ~file ~domain))))
+(export po_message_iterator)
+
+;; extern void po_message_iterator_free(po_message_iterator_t iterator);
+(define ~po_message_iterator_free
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_iterator_free"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_iterator_free iterator)
+ (let ((~iterator
+ ((fht-unwrap po_message_iterator_t) iterator)))
+ ((force ~po_message_iterator_free) ~iterator)))
+(export po_message_iterator_free)
+
+;; extern po_message_t po_next_message(po_message_iterator_t iterator);
+(define ~po_next_message
+ (delay (fh-link-proc
+ ffi-void*
+ "po_next_message"
+ (list ffi-void*)
+ link-lib)))
+(define (po_next_message iterator)
+ (let ((~iterator
+ ((fht-unwrap po_message_iterator_t) iterator)))
+ ((fht-wrap po_message_t)
+ ((force ~po_next_message) ~iterator))))
+(export po_next_message)
+
+;; extern void po_message_insert(po_message_iterator_t iterator, po_message_t
+;; message);
+(define ~po_message_insert
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_insert"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_insert iterator message)
+ (let ((~iterator
+ ((fht-unwrap po_message_iterator_t) iterator))
+ (~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_insert) ~iterator ~message)))
+(export po_message_insert)
+
+;; extern po_message_t po_message_create(void);
+(define ~po_message_create
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_create"
+ (list)
+ link-lib)))
+(define (po_message_create)
+ (let ()
+ ((fht-wrap po_message_t)
+ ((force ~po_message_create)))))
+(export po_message_create)
+
+;; extern const char *po_message_msgctxt(po_message_t message);
+(define ~po_message_msgctxt
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_msgctxt"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_msgctxt message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_msgctxt) ~message)))
+(export po_message_msgctxt)
+
+;; extern void po_message_set_msgctxt(po_message_t message, const char *msgctxt
+;; );
+(define ~po_message_set_msgctxt
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_msgctxt"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_msgctxt message msgctxt)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~msgctxt (unwrap~pointer msgctxt)))
+ ((force ~po_message_set_msgctxt)
+ ~message
+ ~msgctxt)))
+(export po_message_set_msgctxt)
+
+;; extern const char *po_message_msgid(po_message_t message);
+(define ~po_message_msgid
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_msgid"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_msgid message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_msgid) ~message)))
+(export po_message_msgid)
+
+;; extern void po_message_set_msgid(po_message_t message, const char *msgid);
+(define ~po_message_set_msgid
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_msgid"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_msgid message msgid)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~msgid (unwrap~pointer msgid)))
+ ((force ~po_message_set_msgid) ~message ~msgid)))
+(export po_message_set_msgid)
+
+;; extern const char *po_message_msgid_plural(po_message_t message);
+(define ~po_message_msgid_plural
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_msgid_plural"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_msgid_plural message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_msgid_plural) ~message)))
+(export po_message_msgid_plural)
+
+;; extern void po_message_set_msgid_plural(po_message_t message, const char *
+;; msgid_plural);
+(define ~po_message_set_msgid_plural
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_msgid_plural"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_msgid_plural
+ message
+ msgid_plural)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~msgid_plural (unwrap~pointer msgid_plural)))
+ ((force ~po_message_set_msgid_plural)
+ ~message
+ ~msgid_plural)))
+(export po_message_set_msgid_plural)
+
+;; extern const char *po_message_msgstr(po_message_t message);
+(define ~po_message_msgstr
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_msgstr"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_msgstr message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_msgstr) ~message)))
+(export po_message_msgstr)
+
+;; extern void po_message_set_msgstr(po_message_t message, const char *msgstr)
+;; ;
+(define ~po_message_set_msgstr
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_msgstr"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_msgstr message msgstr)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~msgstr (unwrap~pointer msgstr)))
+ ((force ~po_message_set_msgstr) ~message ~msgstr)))
+(export po_message_set_msgstr)
+
+;; extern const char *po_message_msgstr_plural(po_message_t message, int index)
+;; ;
+(define ~po_message_msgstr_plural
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_msgstr_plural"
+ (list ffi-void* ffi:int)
+ link-lib)))
+(define (po_message_msgstr_plural message index)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~index (unwrap~fixed index)))
+ ((force ~po_message_msgstr_plural)
+ ~message
+ ~index)))
+(export po_message_msgstr_plural)
+
+;; extern void po_message_set_msgstr_plural(po_message_t message, int index,
+;; const char *msgstr);
+(define ~po_message_set_msgstr_plural
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_msgstr_plural"
+ (list ffi-void* ffi:int ffi-void*)
+ link-lib)))
+(define (po_message_set_msgstr_plural
+ message
+ index
+ msgstr)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~index (unwrap~fixed index))
+ (~msgstr (unwrap~pointer msgstr)))
+ ((force ~po_message_set_msgstr_plural)
+ ~message
+ ~index
+ ~msgstr)))
+(export po_message_set_msgstr_plural)
+
+;; extern const char *po_message_comments(po_message_t message);
+(define ~po_message_comments
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_comments"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_comments message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_comments) ~message)))
+(export po_message_comments)
+
+;; extern void po_message_set_comments(po_message_t message, const char *
+;; comments);
+(define ~po_message_set_comments
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_comments"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_comments message comments)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~comments (unwrap~pointer comments)))
+ ((force ~po_message_set_comments)
+ ~message
+ ~comments)))
+(export po_message_set_comments)
+
+;; extern const char *po_message_extracted_comments(po_message_t message);
+(define ~po_message_extracted_comments
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_extracted_comments"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_extracted_comments message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_extracted_comments) ~message)))
+(export po_message_extracted_comments)
+
+;; extern void po_message_set_extracted_comments(po_message_t message, const
+;; char *comments);
+(define ~po_message_set_extracted_comments
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_extracted_comments"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_extracted_comments
+ message
+ comments)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~comments (unwrap~pointer comments)))
+ ((force ~po_message_set_extracted_comments)
+ ~message
+ ~comments)))
+(export po_message_set_extracted_comments)
+
+;; extern po_filepos_t po_message_filepos(po_message_t message, int i);
+(define ~po_message_filepos
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_filepos"
+ (list ffi-void* ffi:int)
+ link-lib)))
+(define (po_message_filepos message i)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~i (unwrap~fixed i)))
+ ((fht-wrap po_filepos_t)
+ ((force ~po_message_filepos) ~message ~i))))
+(export po_message_filepos)
+
+;; extern void po_message_remove_filepos(po_message_t message, int i);
+(define ~po_message_remove_filepos
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_remove_filepos"
+ (list ffi-void* ffi:int)
+ link-lib)))
+(define (po_message_remove_filepos message i)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~i (unwrap~fixed i)))
+ ((force ~po_message_remove_filepos) ~message ~i)))
+(export po_message_remove_filepos)
+
+;; extern void po_message_add_filepos(po_message_t message, const char *file,
+;; size_t start_line);
+(define ~po_message_add_filepos
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_add_filepos"
+ (list ffi-void* ffi-void* ffi:size_t)
+ link-lib)))
+(define (po_message_add_filepos message file start_line)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~file (unwrap~pointer file))
+ (~start_line (unwrap~fixed start_line)))
+ ((force ~po_message_add_filepos)
+ ~message
+ ~file
+ ~start_line)))
+(export po_message_add_filepos)
+
+;; extern const char *po_message_prev_msgctxt(po_message_t message);
+(define ~po_message_prev_msgctxt
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_prev_msgctxt"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_prev_msgctxt message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_prev_msgctxt) ~message)))
+(export po_message_prev_msgctxt)
+
+;; extern void po_message_set_prev_msgctxt(po_message_t message, const char *
+;; prev_msgctxt);
+(define ~po_message_set_prev_msgctxt
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_prev_msgctxt"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_prev_msgctxt
+ message
+ prev_msgctxt)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~prev_msgctxt (unwrap~pointer prev_msgctxt)))
+ ((force ~po_message_set_prev_msgctxt)
+ ~message
+ ~prev_msgctxt)))
+(export po_message_set_prev_msgctxt)
+
+;; extern const char *po_message_prev_msgid(po_message_t message);
+(define ~po_message_prev_msgid
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_prev_msgid"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_prev_msgid message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_prev_msgid) ~message)))
+(export po_message_prev_msgid)
+
+;; extern void po_message_set_prev_msgid(po_message_t message, const char *
+;; prev_msgid);
+(define ~po_message_set_prev_msgid
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_prev_msgid"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_prev_msgid message prev_msgid)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~prev_msgid (unwrap~pointer prev_msgid)))
+ ((force ~po_message_set_prev_msgid)
+ ~message
+ ~prev_msgid)))
+(export po_message_set_prev_msgid)
+
+;; extern const char *po_message_prev_msgid_plural(po_message_t message);
+(define ~po_message_prev_msgid_plural
+ (delay (fh-link-proc
+ ffi-void*
+ "po_message_prev_msgid_plural"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_prev_msgid_plural message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_prev_msgid_plural) ~message)))
+(export po_message_prev_msgid_plural)
+
+;; extern void po_message_set_prev_msgid_plural(po_message_t message, const
+;; char *prev_msgid_plural);
+(define ~po_message_set_prev_msgid_plural
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_prev_msgid_plural"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_set_prev_msgid_plural
+ message
+ prev_msgid_plural)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~prev_msgid_plural
+ (unwrap~pointer prev_msgid_plural)))
+ ((force ~po_message_set_prev_msgid_plural)
+ ~message
+ ~prev_msgid_plural)))
+(export po_message_set_prev_msgid_plural)
+
+;; extern int po_message_is_obsolete(po_message_t message);
+(define ~po_message_is_obsolete
+ (delay (fh-link-proc
+ ffi:int
+ "po_message_is_obsolete"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_is_obsolete message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_is_obsolete) ~message)))
+(export po_message_is_obsolete)
+
+;; extern void po_message_set_obsolete(po_message_t message, int obsolete);
+(define ~po_message_set_obsolete
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_obsolete"
+ (list ffi-void* ffi:int)
+ link-lib)))
+(define (po_message_set_obsolete message obsolete)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~obsolete (unwrap~fixed obsolete)))
+ ((force ~po_message_set_obsolete)
+ ~message
+ ~obsolete)))
+(export po_message_set_obsolete)
+
+;; extern int po_message_is_fuzzy(po_message_t message);
+(define ~po_message_is_fuzzy
+ (delay (fh-link-proc
+ ffi:int
+ "po_message_is_fuzzy"
+ (list ffi-void*)
+ link-lib)))
+(define (po_message_is_fuzzy message)
+ (let ((~message ((fht-unwrap po_message_t) message)))
+ ((force ~po_message_is_fuzzy) ~message)))
+(export po_message_is_fuzzy)
+
+;; extern void po_message_set_fuzzy(po_message_t message, int fuzzy);
+(define ~po_message_set_fuzzy
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_fuzzy"
+ (list ffi-void* ffi:int)
+ link-lib)))
+(define (po_message_set_fuzzy message fuzzy)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~fuzzy (unwrap~fixed fuzzy)))
+ ((force ~po_message_set_fuzzy) ~message ~fuzzy)))
+(export po_message_set_fuzzy)
+
+;; extern int po_message_is_format(po_message_t message, const char *
+;; format_type);
+(define ~po_message_is_format
+ (delay (fh-link-proc
+ ffi:int
+ "po_message_is_format"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_is_format message format_type)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~format_type (unwrap~pointer format_type)))
+ ((force ~po_message_is_format)
+ ~message
+ ~format_type)))
+(export po_message_is_format)
+
+;; extern void po_message_set_format(po_message_t message, const char *
+;; format_type, int value);
+(define ~po_message_set_format
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_format"
+ (list ffi-void* ffi-void* ffi:int)
+ link-lib)))
+(define (po_message_set_format message format_type value)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~format_type (unwrap~pointer format_type))
+ (~value (unwrap~fixed value)))
+ ((force ~po_message_set_format)
+ ~message
+ ~format_type
+ ~value)))
+(export po_message_set_format)
+
+;; extern int po_message_is_range(po_message_t message, int *minp, int *maxp);
+(define ~po_message_is_range
+ (delay (fh-link-proc
+ ffi:int
+ "po_message_is_range"
+ (list ffi-void* ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_is_range message minp maxp)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~minp (unwrap~pointer minp))
+ (~maxp (unwrap~pointer maxp)))
+ ((force ~po_message_is_range)
+ ~message
+ ~minp
+ ~maxp)))
+(export po_message_is_range)
+
+;; extern void po_message_set_range(po_message_t message, int min, int max);
+(define ~po_message_set_range
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_set_range"
+ (list ffi-void* ffi:int ffi:int)
+ link-lib)))
+(define (po_message_set_range message min max)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~min (unwrap~fixed min))
+ (~max (unwrap~fixed max)))
+ ((force ~po_message_set_range)
+ ~message
+ ~min
+ ~max)))
+(export po_message_set_range)
+
+;; extern const char *po_filepos_file(po_filepos_t filepos);
+(define ~po_filepos_file
+ (delay (fh-link-proc
+ ffi-void*
+ "po_filepos_file"
+ (list ffi-void*)
+ link-lib)))
+(define (po_filepos_file filepos)
+ (let ((~filepos ((fht-unwrap po_filepos_t) filepos)))
+ ((force ~po_filepos_file) ~filepos)))
+(export po_filepos_file)
+
+;; extern size_t po_filepos_start_line(po_filepos_t filepos);
+(define ~po_filepos_start_line
+ (delay (fh-link-proc
+ ffi:size_t
+ "po_filepos_start_line"
+ (list ffi-void*)
+ link-lib)))
+(define (po_filepos_start_line filepos)
+ (let ((~filepos ((fht-unwrap po_filepos_t) filepos)))
+ ((force ~po_filepos_start_line) ~filepos)))
+(export po_filepos_start_line)
+
+;; extern const char *const*po_format_list(void);
+(define ~po_format_list
+ (delay (fh-link-proc
+ ffi-void*
+ "po_format_list"
+ (list)
+ link-lib)))
+(define (po_format_list)
+ (let () ((force ~po_format_list))))
+(export po_format_list)
+
+;; extern const char *po_format_pretty_name(const char *format_type);
+(define ~po_format_pretty_name
+ (delay (fh-link-proc
+ ffi-void*
+ "po_format_pretty_name"
+ (list ffi-void*)
+ link-lib)))
+(define (po_format_pretty_name format_type)
+ (let ((~format_type (unwrap~pointer format_type)))
+ ((force ~po_format_pretty_name) ~format_type)))
+(export po_format_pretty_name)
+
+;; extern void po_file_check_all(po_file_t file, po_xerror_handler_t handler);
+(define ~po_file_check_all
+ (delay (fh-link-proc
+ ffi:void
+ "po_file_check_all"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_file_check_all file handler)
+ (let ((~file ((fht-unwrap po_file_t) file))
+ (~handler
+ ((fht-unwrap po_xerror_handler_t) handler)))
+ ((force ~po_file_check_all) ~file ~handler)))
+(export po_file_check_all)
+
+;; extern void po_message_check_all(po_message_t message, po_message_iterator_t
+;; iterator, po_xerror_handler_t handler);
+(define ~po_message_check_all
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_check_all"
+ (list ffi-void* ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_check_all message iterator handler)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~iterator
+ ((fht-unwrap po_message_iterator_t) iterator))
+ (~handler
+ ((fht-unwrap po_xerror_handler_t) handler)))
+ ((force ~po_message_check_all)
+ ~message
+ ~iterator
+ ~handler)))
+(export po_message_check_all)
+
+;; extern void po_message_check_format_v2(po_message_t message,
+;; po_xerror_handler_t handler);
+(define ~po_message_check_format_v2
+ (delay (fh-link-proc
+ ffi:void
+ "po_message_check_format_v2"
+ (list ffi-void* ffi-void*)
+ link-lib)))
+(define (po_message_check_format_v2 message handler)
+ (let ((~message ((fht-unwrap po_message_t) message))
+ (~handler
+ ((fht-unwrap po_xerror_handler_t) handler)))
+ ((force ~po_message_check_format_v2)
+ ~message
+ ~handler)))
+(export po_message_check_format_v2)
+
+;; access to enum symbols and #define'd constants:
+(define gettext-po-symbol-val
+ (let ((sym-tab
+ '((_GETTEXT_PO_H . 1)
+ (LIBGETTEXTPO_VERSION . 4872)
+ (PO_SEVERITY_WARNING . 0)
+ (PO_SEVERITY_ERROR . 1)
+ (PO_SEVERITY_FATAL_ERROR . 2))))
+ (lambda (k) (or (assq-ref sym-tab k)))))
+(export gettext-po-symbol-val)
+
+(define (unwrap-enum obj)
+ (cond ((number? obj) obj)
+ ((symbol? obj) (gettext-po-symbol-val obj))
+ ((fh-object? obj) (struct-ref obj 0))
+ (else (error "type mismatch"))))
+
+(define gettext-po-types
+ '("po_file_t" "po_message_iterator_t" "po_message_t" "po_filepos_t" (struct
+ . "po_error_handler") "po_error_handler_t" (struct . "po_xerror_handler")
+ "po_xerror_handler_t"))
+(export gettext-po-types)
+
+;; TODO: add renamer
+
+;; --- last line ---
diff --git a/haunt.scm b/haunt.scm
index f257ecb..6ecc801 100644
--- a/haunt.scm
+++ b/haunt.scm
@@ -18,162 +18,154 @@
;;; instructions on where to get Haunt or just use your distribution’s
;;; package manager.
;;; Once Haunt is installed, just run `haunt build` inside the directory
-;;; containing this file.
+;;; containing this file. TODO Well no because of translations, see the file NOTES.
;;; If you wish to contact me, find my contact information on:
;;; https://pelzflorian.de
;;; Sorry that some code here currently isn’t pretty yet.
-;;; Also I guess I should not use absolute URLs for href.
-;;; Format strings should be used for internationalization.
-
-(use-modules (ice-9 match)
- (ice-9 regex)
- (srfi srfi-1)
- (srfi srfi-19)
- (haunt asset)
- (haunt html)
- (haunt page)
- (haunt post)
- (haunt reader)
- (haunt site)
- (haunt builder assets)
- (haunt builder atom)
- (haunt builder blog))
+;;; TODO Format strings should be used for internationalization.
+;;; TODO Properly wrap newlines with \ at the end of a line in strings.
+;;; TODO Switch to the Meson build system and update the above comment accordingly.
+
+(use-modules
+ (gettext-po)
+ (system ffi-help-rt)
+ ((system foreign)
+ #:prefix ffi:)
+ (ice-9 match)
+ (ice-9 regex)
+ (srfi srfi-1)
+ (srfi srfi-19)
+ (haunt asset)
+ (haunt html)
+ (haunt page)
+ (haunt post)
+ (haunt reader)
+ (haunt site)
+ (haunt builder assets)
+ (haunt builder atom)
+ (haunt builder blog))
(define linguas
(list "de"
"en"))
-;;; gettext po files *should* be used instead, but gettext seems bad, see
-;;; https://stackoverflow.com/questions/3398113/php-gettext-problems
-;;; TODO find a non-hacky way to do so first…
-(define (translated-msg msg lingua)
- (let ((english-translations
- '(("@ietf-lang-tag" . "en")))
- (german-translations
- '(("← Back to home page" . "← Zurück zur hauptseite")
- ("@ietf-lang-tag" . "de")
- ("My blog in English" . "Mein blog auf deutsch")
- ("Git Projects" . "Git-projecte")
- ("Old stuff" . "Alter kram")
- ("GTK+ Workshop 2016" . "GTK+-Workshop 2016")
- ("Subscribe to Atom feed" . "Als Atom-feed abonnieren")
- ("Contact me:" . "So erreichen Sie mich:")
- ("Mail:" . "E-mail:")
- ("GnuPG key:" . "GnuPG-schlüssel:")
- ("Find the source code for this website" . "Den quellcode dieser Web-seite gibt es")
- ("here" . "hier")
- ("Powered by" . "Sie läuft dank")
- ("and" . "und")
- ("Tags:" . "Schlüsselwörter:")
- ("Recent posts" . "Neue einträge")
- ("Lecture notes" . "Vorlesungsnoticen")
- ("Some German lecture summaries I made for lectures I heard in 2013:" . "Ein paar selbst erstellte zusammenfassungen zu vorlesungen, die ich im sommersemester 2013 gehört habe:")
- ("C exercises (German)" . "C-übungen (deutsch)")
- ("Includes a cheat sheet for working with C." . "Enthält einen spickzettel für die arbeit mit C.")
- ("C Exercises" . "C-übungen")
- ("Home page" . "Hauptseite")
- ("Welcome" . "Willkommen")
- ("Welcome to my personal web site. My
-name is Florian Pelz and I live in Kaiserslautern in Germany. When I
-have interesting things to share, I’ll put them up here." . "Willkommen auf meiner
-Web-seite. Ich heiße Florian Pelz und wohne in Kaiserslautern. Wenn
-ich interessante sachen teilen möchte, lade ich sie hier hoch.")
- ("See other posts" . "Andere einträge ansehen")
- ("See other posts about " . "Andere einträge ansehen über ")
- ("Thank you for your interest in my workshop
-“GUI Programming with GTK+”. " . "Vielen Dank für Ihr Interesse an meinem Workshop
-„GUI-Programmierung mit GTK+”. ")
- ("To register please go " . "Zur Anmeldung geht es ")
- ("For more information see " . "Weitere Informationen siehe ")
- ("GUI Programming with GTK+ " . "GUI-Programmierung mit GTK+ ")
- ("All source code for the workshop." . "Aller Quellcode zum Workshop.")
- ("Don’t Hang" . "Don’t Hang")
- ("A simple GTK+ hangman game inspired by bsd-games’ hangman." . "Ein einfaches GTK+-galgenmännchen-spiel, inspiriert von bsd-games.")
- ("“Don’t Hang” is a simple hangman game for acquiring and consolidating
-a basic vocabulary in a foreign language. It supports loading custom word lists and works with
-Unicode and bidirectional text. It also supports pasting characters from the clipboard." . "„Don’t
-Hang“ soll beim erlernen und festigen eines grundwortschatzes in
-einer fremdsprache helfen. Das spiel unterstützt eigene wortlisten sowie
-Unicode und bidirectionalen text. Außerdem bietet es die möglichkeit,
-zeichen aus der zwischenablage einzufügen.")
- ("It is free software and also publicly available at no cost." . "Es
-ist freie software und kostenlos verfügbar.")
- ("Screenshots" . "Screenshots")
- ("Guessing an expression" . "Beim erraten eines ausdrucks")
- ("Right-to-left support" . "Rechts-nach-links-unterstützung")
- ("News" . "Neuigkeiten")
- ("“Don’t Hang”" . "„Don’t Hang“")
- ("Downloads" . "Herunterladen")
- ("“Don’t Hang” version 1.1 Source code." . "„Don’t Hang“: Quellcode von version 1.1.")
- ("Current development version." . "Momentaner entwicklungsstand.")
- ("“Don’t Hang” for Arch Linux" . "„Don’t Hang“ für Arch Linux")
- (" and derivative GNU distributions such as " . " und abgeleitete GNU-distributionen wie ")
- ("Parabola GNU/Linux-libre" . "Parabola GNU/Linux-libre")
- ("Windows installer (x86)" . "Windows-installationsprogramm (x86)")
- (" as well as " . " sowie ")
- ("“portable” binaries without installer" . "„portable“ binärdateien ohne
-installation")
- (" if you are still using Windows, all built using " . " stehen zur verfügung, falls Sie
-noch immer Windows benutzen, gebaut mit ")
- (" for which the source files are available at their
-home page." . ", dessen quelldateien auf deren homepage zu finden sind.")
- ("Unsigned " . "Unsignierte ")
- ("macOS binaries (10.10 Yosemite or newer)" . "macOS-binärdateien (10.10 Yosemite oder neuer)")
- (" if you are still using macOS (you may need to follow the instructions
-+from the macOS error messages on how to make macOS trust the binaries)." . ", falls
-Sie noch immer macOS benutzen (eventuell müssen Sie den instructionen aus den macOS-fehlermeldungen,
-wie sie macOS dazu bringen, den binärdateien zu vertrauen, folgen).")
- ("Word lists" . "Wortlisten")
- ("“Don’t Hang” by default uses the words from the " . "„Don’t Hang“ benutzt
-standardmäßig die wörter aus dem verzeichnis ")
- (" directory, but it can deal with any list of expressions in a text file
-with one expression per line. " . ", kann aber auch beliebige andere
-zeilenweise listen von ausdrücken aus einer textdatei lesen. ")
- ("Here" . "Hier")
- (" is an example word list file compiled with words from " . " ist eine
-beispiel-wortlistendatei, zusammengestellt mit wörtern aus ")
- ("Wiktionary’s list of 1000 basic English words" . "Wiktionarys liste von
-1000 grundlegenden englischen wörtern")
- (" which you can use if you want simpler words. This sample word list is
-available under the terms of " . ", welche einfachere wörter enthält. Diese
-beispiel-wortliste ist zu den bedingungen ")
- ("the CC-BY-SA 3.0 Unported license" . "der CC-BY-SA-3.0-Unported-licenz")
- (", because Wiktionary uses this license and the words are taken from there." . " verfügbar,
-da diese licenz von Wiktionary benutzt wird und die wörter von dort genommen wurden.")
- ("Please note that all words in the sample word list have been deliberately
-converted to upper case. The reason is that “Don’t Hang” displays words in upper case and storing
-the words in lower case would lead to errors in some locales, e.g. the English word “is” would
-become “İS” in a Turkish locale." . "Zu beachten ist, dass in der beispiel-wortliste
-alle wörter mit absicht in großbuchstaben geschrieben wurden, weil „Don’t Hang“ wörter
-in großbuchstaben anzeigt und das speichern der wörter in kleinbuchstaben zu fehlern
-in manchen regionalen varianten führen würde, z.b. würde das englische wort „is“ mit türkischer
-spracheinstellung zu „İS“ werden."))))
+;; TODO SET XERROR HANDLERS CORRECTLY BELOW:
+;;
+;; (define (xerror-handler severity message filename lineno column multiline-p1 message-text)
+;; (display "xerror occurred!"))
+;; (define ~xerror-handler
+;; (ffi:procedure->pointer
+;; ffi:void
+;; xerror-handler
+;; (list ffi:int
+;; '*
+;; '*
+;; ffi:size_t
+;; ffi:size_t
+;; ffi:int
+;; '*)))
+;;
+;; (define (xerror2-handler severity message
+;; filename1 lineno1 column1 multiline-p1 message-text1
+;; filename2 lineno2 column2 multiline-p2 message-text2)
+;; (display "xerror occurred!"))
+;; (define ~xerror2-handler
+;; (ffi:procedure->pointer
+;; ffi:void
+;; xerror2-handler
+;; (list ffi:int
+;; '*
+;; '*
+;; ffi:size_t
+;; ffi:size_t
+;; ffi:int
+;; '*
+;; '*
+;; '*
+;; ffi:size_t
+;; ffi:size_t
+;; ffi:int
+;; '*)))
+
+(define xerror-handler-struct
+ (make-struct-po_xerror_handler)) ; TODO SET HANDLERS:
+;; (let ((new (make-struct-po_xerror_handler)))
+;; (begin
+;; (fh-object-set! new 'xerror ~xerror-handler)
+;; (fh-object-set! new 'xerror2 ~xerror2-handler)
+;; new)))
+
+(define (translations-for-lingua lingua)
+ "Returns po/<lingua>.po converted to an association list of msgid–msgstr pairs."
+ ;; TODO: STILL DISREGARDING PLURALS AND OTHER INFORMATION
+ (let* ((po-file
+ (po_file_read_v3
+ (string-append "po/" lingua ".po")
+ (pointer-to xerror-handler-struct)))
+ (translations
+ (if (ffi:null-pointer? (unwrap~pointer po-file))
+ '()
+ ;; otherwise:
+ (let ((iter (po_message_iterator po-file ffi:%null-pointer)))
+ (let loop ((message (po_next_message iter)))
+ (if (ffi:null-pointer? (unwrap~pointer message))
+ (begin
+ (po_message_iterator_free iter)
+ '())
+ ;; otherwise:
+ (cons
+ (cons
+ (ffi:pointer->string (po_message_msgid message))
+ (ffi:pointer->string (po_message_msgstr message)))
+ (loop (po_next_message iter)))))))))
+ (if (not (ffi:null-pointer? (unwrap~pointer po-file)))
+ (po_file_free po-file))
+ translations))
+
+(define (translations-entry-for-lingua lingua)
+ "Returns a pair of LINGUA and an association list of its translations."
+ (cons
+ lingua
+ (translations-for-lingua lingua)))
+
+(define translated-msg
+ ;; gettext is not used directly because it would require repeated
+ ;; setlocale calls, which should not be necessary.
+ ;; See: https://stackoverflow.com/questions/3398113/php-gettext-problems
+ (let ((translation-lists
+ (map translations-entry-for-lingua linguas)))
(define (with-default value default)
(if value value
default))
- (match lingua
- ("de"
- (with-default
- (assoc-ref german-translations msg)
- msg))
- ("en"
- (with-default
- (assoc-ref english-translations msg)
- msg))
- (anything-else ; just return message
- msg))))
-
-;;; shorthand for translated-msg with what currently is current-lingua:
+ (lambda (msgid lingua)
+ "Returns the msgstr for MSGID from the po file for LINGUA."
+ (let ((translations (assoc-ref translation-lists lingua)))
+ (with-default
+ (assoc-ref translations msgid)
+ msgid)))))
+
+;; TODO: Unused translations; incorporate into po file later:
+;;
+;; ("Unsigned " . "Unsignierte ")
+;; ("macOS binaries (10.10 Yosemite or newer)" . "macOS-binärdateien (10.10 Yosemite oder neuer)")
+;; (" if you are still using macOS (you may need to follow the instructions
+;; +from the macOS error messages on how to make macOS trust the binaries)." . ", falls
+;; Sie noch immer macOS benutzen (eventuell müssen Sie den instructionen aus den macOS-fehlermeldungen,
+;; wie sie macOS dazu bringen, den binärdateien zu vertrauen, folgen).")
+
(define-syntax _
(lambda (x)
+ "Gettext-like shorthand for translated-msg with what currently is current-lingua."
(syntax-case x ()
((_ msg)
(with-syntax ((current-lingua (datum->syntax x 'current-lingua)))
#'(translated-msg msg current-lingua))))))
(define (date->string-for-lingua date lingua)
+ "Custom date->string* variant that deals with lingua and my no longer common German language \
+orthographic preferences."
(match lingua
("de"
(string-append
diff --git a/po/LINGUAS b/po/LINGUAS
new file mode 100644
index 0000000..996888b
--- /dev/null
+++ b/po/LINGUAS
@@ -0,0 +1,2 @@
+de
+en
diff --git a/po/POTFILES b/po/POTFILES
new file mode 100644
index 0000000..dcf8537
--- /dev/null
+++ b/po/POTFILES
@@ -0,0 +1 @@
+haunt.scm
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000..9665fb1
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,309 @@
+# German translations for pelzfloriande-website package.
+# This file is put in the public domain.
+# Automatically generated, 2017.
+# Florian Pelz <pelzflorian@pelzflorian.de>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pelzfloriande-website\n"
+"Report-Msgid-Bugs-To: pelzflorian@pelzflorian.de\n"
+"POT-Creation-Date: 2017-12-09 02:27+0100\n"
+"PO-Revision-Date: 2017-12-09 12:02+0100\n"
+"Last-Translator: Florian Pelz <pelzflorian@pelzflorian.de>\n"
+"Language-Team: English <pelzflorian@pelzflorian.de>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Gtranslator 2.91.7\n"
+
+#: haunt.scm:355
+msgid "← Back to home page"
+msgstr "← Zurück zur hauptseite"
+
+#: haunt.scm:363
+msgid "See other posts"
+msgstr "Andere einträge ansehen"
+
+#: haunt.scm:373
+msgid "See other posts about "
+msgstr "Andere einträge ansehen über "
+
+#: haunt.scm:382
+msgid "Tags:"
+msgstr "Schlüsselwörter:"
+
+#: haunt.scm:424
+msgid "My blog in English"
+msgstr "Mein blog auf deutsch"
+
+#: haunt.scm:430
+msgid "@ietf-lang-tag"
+msgstr "de"
+
+#: haunt.scm:473
+msgid "Git Projects"
+msgstr "Git-projecte"
+
+#: haunt.scm:476 haunt.scm:602 haunt.scm:696
+msgid "Don’t Hang"
+msgstr "Don’t Hang"
+
+#: haunt.scm:479 haunt.scm:594
+msgid "Old stuff"
+msgstr "Alter kram"
+
+#: haunt.scm:482
+msgid "GTK+ Workshop 2017"
+msgstr "GTK+-Workshop 2017"
+
+#: haunt.scm:485
+msgid "GTK+ Workshop 2016"
+msgstr "GTK+-Workshop 2016"
+
+#: haunt.scm:488
+msgid "Subscribe to Atom feed"
+msgstr "Als Atom-feed abonnieren"
+
+#: haunt.scm:495
+msgid "Contact me:"
+msgstr "So erreichen Sie mich:"
+
+#: haunt.scm:497
+msgid "Mail:"
+msgstr "E-mail:"
+
+#: haunt.scm:507
+msgid "GnuPG key:"
+msgstr "GnuPG-schlüssel:"
+
+#: haunt.scm:512
+msgid "valid until"
+msgstr "gültig bis"
+
+#: haunt.scm:515
+msgid "Find the source code for this website"
+msgstr "Den quellcode dieser Web-seite gibt es"
+
+#: haunt.scm:518 haunt.scm:857 haunt.scm:862
+msgid "here"
+msgstr "hier"
+
+#: haunt.scm:521
+msgid "Powered by"
+msgstr "Sie läuft dank"
+
+#: haunt.scm:526
+msgid "and"
+msgstr "und"
+
+#: haunt.scm:551 haunt.scm:921 haunt.scm:927
+msgid "Recent posts"
+msgstr "Neue einträge"
+
+#: haunt.scm:574
+msgid "Lecture notes"
+msgstr "Vorlesungsnoticen"
+
+#: haunt.scm:575
+msgid "Some German lecture summaries I made for lectures I heard in 2013:"
+msgstr ""
+"Ein paar selbst erstellte zusammenfassungen zu vorlesungen, die ich im "
+"sommersemester 2013 gehört habe:"
+
+#: haunt.scm:585
+msgid "C exercises (German)"
+msgstr "C-übungen (deutsch)"
+
+#: haunt.scm:586
+msgid "Includes a cheat sheet for working with C."
+msgstr "Enthält einen spickzettel für die arbeit mit C."
+
+#: haunt.scm:590
+msgid "C Exercises"
+msgstr "C-übungen"
+
+#: haunt.scm:608
+msgid "A simple GTK+ hangman game inspired by bsd-games’ hangman."
+msgstr "Ein einfaches GTK+-galgenmännchen-spiel, inspiriert von bsd-games."
+
+#: haunt.scm:609
+msgid ""
+"“Don’t Hang” is a simple hangman game for acquiring and consolidating\n"
+"a basic vocabulary in a foreign language. It supports loading custom word "
+"lists and works with\n"
+"Unicode and bidirectional text. It also supports pasting characters from the "
+"clipboard."
+msgstr ""
+"„Don’t Hang“ soll beim erlernen und festigen eines grundwortschatzes in\n"
+"einer fremdsprache helfen. Das spiel unterstützt eigene wortlisten sowie\n"
+"Unicode und bidirectionalen text. Außerdem bietet es die möglichkeit,\n"
+"zeichen aus der zwischenablage einzufügen."
+
+#: haunt.scm:612
+msgid "It is free software and also publicly available at no cost."
+msgstr "Es ist freie software und kostenlos verfügbar."
+
+#: haunt.scm:614
+msgid "Screenshots"
+msgstr "Screenshots"
+
+#: haunt.scm:616
+msgid "Guessing an expression"
+msgstr "Beim erraten eines ausdrucks"
+
+#: haunt.scm:617
+msgid "Right-to-left support"
+msgstr "Rechts-nach-links-unterstützung"
+
+#: haunt.scm:626
+msgid "News"
+msgstr "Neuigkeiten"
+
+#: haunt.scm:632
+msgid "“Don’t Hang”"
+msgstr "„Don’t Hang“"
+
+#: haunt.scm:636
+msgid "Downloads"
+msgstr "Herunterladen"
+
+#: haunt.scm:640
+msgid "“Don’t Hang” version 1.1 Source code."
+msgstr "„Don’t Hang“: Quellcode von version 1.1."
+
+#: haunt.scm:643
+msgid "Current development version."
+msgstr "Momentaner entwicklungsstand."
+
+#: haunt.scm:646
+msgid "“Don’t Hang” for Arch Linux"
+msgstr "„Don’t Hang“ für Arch Linux"
+
+#: haunt.scm:647
+msgid " and derivative GNU distributions such as "
+msgstr " und abgeleitete GNU-distributionen wie "
+
+#: haunt.scm:650
+msgid "Parabola GNU/Linux-libre"
+msgstr "Parabola GNU/Linux-libre"
+
+#: haunt.scm:659
+msgid "“portable” binaries without installer"
+msgstr "„portable“ binärdateien ohne installation"
+
+#: haunt.scm:660
+msgid " if you are still using Windows, all built using "
+msgstr ""
+" stehen zur verfügung, falls Sie noch immer Windows benutzen, gebaut mit "
+
+#: haunt.scm:662
+msgid ""
+" for which the source files are available at their\n"
+"home page."
+msgstr ", dessen quelldateien auf deren homepage zu finden sind."
+
+#: haunt.scm:671
+msgid "Word lists"
+msgstr "Wortlisten"
+
+#: haunt.scm:672
+msgid "“Don’t Hang” by default uses the words from the "
+msgstr "„Don’t Hang“ benutzt standardmäßig die wörter aus dem verzeichnis "
+
+#: haunt.scm:675
+msgid ""
+" directory, but it can deal with any list of expressions in a text file\n"
+"with one expression per line. "
+msgstr ""
+", kann aber auch beliebige andere zeilenweise listen von ausdrücken aus "
+"einer textdatei lesen. "
+
+#: haunt.scm:679
+msgid "Here"
+msgstr "Hier"
+
+#: haunt.scm:680
+msgid " is an example word list file compiled with words from "
+msgstr " ist eine beispiel-wortlistendatei, zusammengestellt mit wörtern aus "
+
+#: haunt.scm:683
+msgid "Wiktionary’s list of 1000 basic English words"
+msgstr "Wiktionarys liste von 1000 grundlegenden englischen wörtern"
+
+#: haunt.scm:684
+msgid ""
+" which you can use if you want simpler words. This sample word list is\n"
+"available under the terms of "
+msgstr ""
+", welche einfachere wörter enthält. Diese beispiel-wortliste ist zu den "
+"bedingungen "
+
+#: haunt.scm:688
+msgid "the CC-BY-SA 3.0 Unported license"
+msgstr "der CC-BY-SA-3.0-Unported-licenz"
+
+#: haunt.scm:689
+msgid ""
+", because Wiktionary uses this license and the words are taken from there."
+msgstr ""
+" verfügbar, da diese licenz von Wiktionary benutzt wird und die wörter von "
+"dort genommen wurden."
+
+#: haunt.scm:690
+msgid ""
+"Please note that all words in the sample word list have been deliberately\n"
+"converted to upper case. The reason is that “Don’t Hang” displays words in "
+"upper case and storing\n"
+"the words in lower case would lead to errors in some locales, e.g. the "
+"English word “is” would\n"
+"become “İS” in a Turkish locale."
+msgstr ""
+"Zu beachten ist, dass in der beispiel-wortliste alle wörter mit absicht in "
+"großbuchstaben geschrieben wurden, weil „Don’t Hang“ wörter in "
+"großbuchstaben anzeigt und das speichern der wörter in kleinbuchstaben zu "
+"fehlern in manchen regionalen varianten führen würde, z.b. würde das "
+"englische wort „is“ mit türkischer spracheinstellung zu „İS“ werden."
+
+#: haunt.scm:772 haunt.scm:839
+msgid "All source code for the workshop."
+msgstr "Aller Quellcode zum Workshop."
+
+#: haunt.scm:851
+msgid ""
+"Thank you for your interest in my workshop\n"
+"“GUI Programming with GTK+”. "
+msgstr ""
+"Vielen Dank für Ihr Interesse an meinem Workshop „GUI-Programmierung mit GTK"
+"+”. "
+
+#: haunt.scm:855
+msgid "To register please go "
+msgstr "Zur Anmeldung geht es "
+
+#: haunt.scm:860
+msgid "For more information see "
+msgstr "Weitere Informationen siehe "
+
+#: haunt.scm:870
+msgid "GUI Programming with GTK+ "
+msgstr "GUI-Programmierung mit GTK+ "
+
+#: haunt.scm:884
+msgid "Home page"
+msgstr "Hauptseite"
+
+#: haunt.scm:887
+msgid "Welcome"
+msgstr "Willkommen"
+
+#: haunt.scm:888
+msgid ""
+"Welcome to my personal web site. My\n"
+"name is Florian Pelz and I live in Kaiserslautern in Germany. When I\n"
+"have interesting things to share, I’ll put them up here."
+msgstr ""
+"Willkommen auf meiner Web-seite. Ich heiße Florian Pelz und wohne in "
+"Kaiserslautern. Wenn ich interessante sachen teilen möchte, lade ich sie "
+"hier hoch."
diff --git a/po/en.po b/po/en.po
new file mode 100644
index 0000000..600af63
--- /dev/null
+++ b/po/en.po
@@ -0,0 +1,309 @@
+# English translations for pelzfloriande-website package.
+# This file is put in the public domain.
+# Automatically generated, 2017.
+# Florian Pelz <pelzflorian@pelzflorian.de>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pelzfloriande-website\n"
+"Report-Msgid-Bugs-To: pelzflorian@pelzflorian.de\n"
+"POT-Creation-Date: 2017-12-09 02:27+0100\n"
+"PO-Revision-Date: 2017-12-09 02:41+0100\n"
+"Last-Translator: Florian Pelz <pelzflorian@pelzflorian.de>\n"
+"Language-Team: English <pelzflorian@pelzflorian.de>\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Gtranslator 2.91.7\n"
+
+#: haunt.scm:355
+msgid "← Back to home page"
+msgstr "← Back to home page"
+
+#: haunt.scm:363
+msgid "See other posts"
+msgstr "See other posts"
+
+#: haunt.scm:373
+msgid "See other posts about "
+msgstr "See other posts about "
+
+#: haunt.scm:382
+msgid "Tags:"
+msgstr "Tags:"
+
+#: haunt.scm:424
+msgid "My blog in English"
+msgstr "My blog in English"
+
+#: haunt.scm:430
+msgid "@ietf-lang-tag"
+msgstr "en"
+
+#: haunt.scm:473
+msgid "Git Projects"
+msgstr "Git Projects"
+
+#: haunt.scm:476 haunt.scm:602 haunt.scm:696
+msgid "Don’t Hang"
+msgstr "Don’t Hang"
+
+#: haunt.scm:479 haunt.scm:594
+msgid "Old stuff"
+msgstr "Old stuff"
+
+#: haunt.scm:482
+msgid "GTK+ Workshop 2017"
+msgstr "GTK+ Workshop 2017"
+
+#: haunt.scm:485
+msgid "GTK+ Workshop 2016"
+msgstr "GTK+ Workshop 2016"
+
+#: haunt.scm:488
+msgid "Subscribe to Atom feed"
+msgstr "Subscribe to Atom feed"
+
+#: haunt.scm:495
+msgid "Contact me:"
+msgstr "Contact me:"
+
+#: haunt.scm:497
+msgid "Mail:"
+msgstr "Mail:"
+
+#: haunt.scm:507
+msgid "GnuPG key:"
+msgstr "GnuPG key:"
+
+#: haunt.scm:512
+msgid "valid until"
+msgstr "valid until"
+
+#: haunt.scm:515
+msgid "Find the source code for this website"
+msgstr "Find the source code for this website"
+
+#: haunt.scm:518 haunt.scm:857 haunt.scm:862
+msgid "here"
+msgstr "here"
+
+#: haunt.scm:521
+msgid "Powered by"
+msgstr "Powered by"
+
+#: haunt.scm:526
+msgid "and"
+msgstr "and"
+
+#: haunt.scm:551 haunt.scm:921 haunt.scm:927
+msgid "Recent posts"
+msgstr "Recent posts"
+
+#: haunt.scm:574
+msgid "Lecture notes"
+msgstr "Lecture notes"
+
+#: haunt.scm:575
+msgid "Some German lecture summaries I made for lectures I heard in 2013:"
+msgstr "Some German lecture summaries I made for lectures I heard in 2013:"
+
+#: haunt.scm:585
+msgid "C exercises (German)"
+msgstr "C exercises (German)"
+
+#: haunt.scm:586
+msgid "Includes a cheat sheet for working with C."
+msgstr "Includes a cheat sheet for working with C."
+
+#: haunt.scm:590
+msgid "C Exercises"
+msgstr "C Exercises"
+
+#: haunt.scm:608
+msgid "A simple GTK+ hangman game inspired by bsd-games’ hangman."
+msgstr "A simple GTK+ hangman game inspired by bsd-games’ hangman."
+
+#: haunt.scm:609
+msgid ""
+"“Don’t Hang” is a simple hangman game for acquiring and consolidating\n"
+"a basic vocabulary in a foreign language. It supports loading custom word "
+"lists and works with\n"
+"Unicode and bidirectional text. It also supports pasting characters from the "
+"clipboard."
+msgstr ""
+"“Don’t Hang” is a simple hangman game for acquiring and consolidating\n"
+"a basic vocabulary in a foreign language. It supports loading custom word "
+"lists and works with\n"
+"Unicode and bidirectional text. It also supports pasting characters from the "
+"clipboard."
+
+#: haunt.scm:612
+msgid "It is free software and also publicly available at no cost."
+msgstr "It is free software and also publicly available at no cost."
+
+#: haunt.scm:614
+msgid "Screenshots"
+msgstr "Screenshots"
+
+#: haunt.scm:616
+msgid "Guessing an expression"
+msgstr "Guessing an expression"
+
+#: haunt.scm:617
+msgid "Right-to-left support"
+msgstr "Right-to-left support"
+
+#: haunt.scm:626
+msgid "News"
+msgstr "News"
+
+#: haunt.scm:632
+msgid "“Don’t Hang”"
+msgstr "“Don’t Hang”"
+
+#: haunt.scm:636
+msgid "Downloads"
+msgstr "Downloads"
+
+#: haunt.scm:640
+msgid "“Don’t Hang” version 1.1 Source code."
+msgstr "“Don’t Hang” version 1.1 Source code."
+
+#: haunt.scm:643
+msgid "Current development version."
+msgstr "Current development version."
+
+#: haunt.scm:646
+msgid "“Don’t Hang” for Arch Linux"
+msgstr "“Don’t Hang” for Arch Linux"
+
+#: haunt.scm:647
+msgid " and derivative GNU distributions such as "
+msgstr " and derivative GNU distributions such as "
+
+#: haunt.scm:650
+msgid "Parabola GNU/Linux-libre"
+msgstr "Parabola GNU/Linux-libre"
+
+#: haunt.scm:659
+msgid "“portable” binaries without installer"
+msgstr "“portable” binaries without installer"
+
+#: haunt.scm:660
+msgid " if you are still using Windows, all built using "
+msgstr " if you are still using Windows, all built using "
+
+#: haunt.scm:662
+msgid ""
+" for which the source files are available at their\n"
+"home page."
+msgstr ""
+" for which the source files are available at their\n"
+"home page."
+
+#: haunt.scm:671
+msgid "Word lists"
+msgstr "Word lists"
+
+#: haunt.scm:672
+msgid "“Don’t Hang” by default uses the words from the "
+msgstr "“Don’t Hang” by default uses the words from the "
+
+#: haunt.scm:675
+msgid ""
+" directory, but it can deal with any list of expressions in a text file\n"
+"with one expression per line. "
+msgstr ""
+" directory, but it can deal with any list of expressions in a text file\n"
+"with one expression per line. "
+
+#: haunt.scm:679
+msgid "Here"
+msgstr "Here"
+
+#: haunt.scm:680
+msgid " is an example word list file compiled with words from "
+msgstr " is an example word list file compiled with words from "
+
+#: haunt.scm:683
+msgid "Wiktionary’s list of 1000 basic English words"
+msgstr "Wiktionary’s list of 1000 basic English words"
+
+#: haunt.scm:684
+msgid ""
+" which you can use if you want simpler words. This sample word list is\n"
+"available under the terms of "
+msgstr ""
+" which you can use if you want simpler words. This sample word list is\n"
+"available under the terms of "
+
+#: haunt.scm:688
+msgid "the CC-BY-SA 3.0 Unported license"
+msgstr "the CC-BY-SA 3.0 Unported license"
+
+#: haunt.scm:689
+msgid ""
+", because Wiktionary uses this license and the words are taken from there."
+msgstr ""
+", because Wiktionary uses this license and the words are taken from there."
+
+#: haunt.scm:690
+msgid ""
+"Please note that all words in the sample word list have been deliberately\n"
+"converted to upper case. The reason is that “Don’t Hang” displays words in "
+"upper case and storing\n"
+"the words in lower case would lead to errors in some locales, e.g. the "
+"English word “is” would\n"
+"become “İS” in a Turkish locale."
+msgstr ""
+"Please note that all words in the sample word list have been deliberately\n"
+"converted to upper case. The reason is that “Don’t Hang” displays words in "
+"upper case and storing\n"
+"the words in lower case would lead to errors in some locales, e.g. the "
+"English word “is” would\n"
+"become “İS” in a Turkish locale."
+
+#: haunt.scm:772 haunt.scm:839
+msgid "All source code for the workshop."
+msgstr "All source code for the workshop."
+
+#: haunt.scm:851
+msgid ""
+"Thank you for your interest in my workshop\n"
+"“GUI Programming with GTK+”. "
+msgstr ""
+"Thank you for your interest in my workshop\n"
+"“GUI Programming with GTK+”. "
+
+#: haunt.scm:855
+msgid "To register please go "
+msgstr "To register please go "
+
+#: haunt.scm:860
+msgid "For more information see "
+msgstr "For more information see "
+
+#: haunt.scm:870
+msgid "GUI Programming with GTK+ "
+msgstr "GUI Programming with GTK+ "
+
+#: haunt.scm:884
+msgid "Home page"
+msgstr "Home page"
+
+#: haunt.scm:887
+msgid "Welcome"
+msgstr "Welcome"
+
+#: haunt.scm:888
+msgid ""
+"Welcome to my personal web site. My\n"
+"name is Florian Pelz and I live in Kaiserslautern in Germany. When I\n"
+"have interesting things to share, I’ll put them up here."
+msgstr ""
+"Welcome to my personal web site. My\n"
+"name is Florian Pelz and I live in Kaiserslautern in Germany. When I\n"
+"have interesting things to share, I’ll put them up here."