371 γραμμές
18 KiB
Markdown
371 γραμμές
18 KiB
Markdown
|
+++
|
|||
|
title = 'NLS+GNU - Τι-πώς-πού-πότε-γιατί;'
|
|||
|
date = '1999-02-01T00:00:00Z'
|
|||
|
description = ''
|
|||
|
author = 'Νίκος Μαυρογιαννόπουλος'
|
|||
|
issue = ['Magaz 12']
|
|||
|
issue_weight = 3
|
|||
|
+++
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
*Μιας και το nls χρησιμοποιείται όλο και περισσότερο στα νέα προγράμματα (ιδιαίτερα αυτά που αποτελούν το GNU σύστημα), είναι αναγκαίο να κάνουμε μια περιγραφή
|
|||
|
της διαδικασίας που χρειάζεται για να το ενσωματώσουμε και στα δικά μας προγράμματα.*
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Η άδεια του gettext για τα κομμάτια που θα ενσωματώσουμε στο προγραμμά μας είναι η GNU LGPL που δεν μας περιορίζει στον καθορισμό της άδειας του προγράμματός
|
|||
|
μας. Κοιτάξτε την πάντως για να δείτε αν είστε συμβατοί(!).
|
|||
|
|
|||
|
Ας προσπεράσουμε όμως τα \"τυπικά\" και ας περάσουμε στο ψητό. Τα προγράμματα που θα χρειαστούμε είναι τα GNU autoconf και gettext-0.10, και βρίσκονται στο πιο
|
|||
|
κοντινό gnu mirror.
|
|||
|
|
|||
|
\* Εδώ θα προσπαθήσουμε να προσθέσουμε υποστήριξη εθνικής/τοπικής γλώσσας (nls) σε ένα προγραμμα γραμμένο σε C. Ας δούμε ένα απλό πρόγραμμα, που τυπώνει την ώρα
|
|||
|
στην οθόνη:
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <time.h>
|
|||
|
|
|||
|
main ()
|
|||
|
{
|
|||
|
time_t tv;
|
|||
|
|
|||
|
printf( "The time is: " );
|
|||
|
time(&tv);
|
|||
|
printf ( "%s",ctime(&tv) );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
\* Η ώρα όπως και το μήνυμα τυπώνεται στα αγγλικά. Επειδή η μετάφραση πρέπει να γίνει γενικά - δηλαδή το ίδιο πρόγραμμα να τρέχει και στα γερμανικά και στα
|
|||
|
ελληνικά και σε οποιαδήποτε άλλη γλώσσα - δεν μεταφράζουμε απ\'ευθείας το κείμενο. Χρησιμοποιούμε τα localedata και την βιβλιοθήκη intl της C βιβλιοθήκης. Ας
|
|||
|
χρησιμοποιήσουμε τα localedata (τοπικά δεδομένα) για την ώρα.
|
|||
|
|
|||
|
Το ίδιο πρόγραμμα τώρα γίνεται:
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <time.h>
|
|||
|
#include <locale.h>
|
|||
|
|
|||
|
main ()
|
|||
|
{
|
|||
|
struct tm *tp;
|
|||
|
char buf[80];
|
|||
|
time_t date;
|
|||
|
|
|||
|
/* Θέτει το locale σύμφωνα με την μεταβλητή περιβάλλοντος LANG ή LANGUAGE
|
|||
|
* Για τα ελληνικά πρεπει να είναι el (ISO639) */
|
|||
|
setlocale (LC_TIME, ""); /* Για την ώρα και μόνο */
|
|||
|
|
|||
|
printf( "The time is: " );
|
|||
|
|
|||
|
time(&date);
|
|||
|
|
|||
|
/* Μετατρέπει την ώρα έκφραση που συνδέεται με την ζώνη ώρας */
|
|||
|
tp = localtime(&date);
|
|||
|
strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %z %Y", tp);
|
|||
|
|
|||
|
/* εκτυπώνει την ώρα */
|
|||
|
printf ("%s\n",buf);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Η ώρα τώρα θα τυπωθεί στην μορφή: `Τετ Νοέ 11 22:44:29 +0200 1998` με ελληνικούς χαρακτήρες όπως βλέπετε (αν LANG=el ή gr για τις
|
|||
|
παλιές glibc2). Γι\'αυτό ξεχάστε το ctime και ασχοληθείτε με το strftime().
|
|||
|
|
|||
|
\* Σε περίπτωση που δεν είδατε ελληνικούς χαρακτήρες ελέγξτε αν στο /usr/share/locale/el υπάρχουν τα απαραίτητα αρχεία. Αν δεν υπάρχουν προμηθευτείτε ένα νέο
|
|||
|
localedata - συμπεριλαμβάνεται συνήθως στην libc ή εγκαταστήστε το tarball που βρίσκεται στο
|
|||
|
<ftp://argeas.cs-net.gr/pub/unix/linux/GREEK/locale.glibc2.el.tar.gz>
|
|||
|
|
|||
|
\* Για την μετάφραση των μηνυμάτων, που είναι και η κυριότερη ιδιότητα του NLS χρησιμοποιείται ο εξής τρόπος:
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <time.h>
|
|||
|
#include <locale.h>
|
|||
|
#include <libintl.h> /* αρχείο της GNU libc */
|
|||
|
|
|||
|
main ()
|
|||
|
{
|
|||
|
struct tm *tp;
|
|||
|
char buf[80];
|
|||
|
time_t date;
|
|||
|
|
|||
|
/* πέρα απο το LC_ALL υπάρχουν τα LC_TIME, LC_MESSAGES κλπ, τα οποία
|
|||
|
* προσδιορίζουν επ'ακριβώς τί μεταφράσεις θα χρησιμοποιήσουμε.
|
|||
|
*/
|
|||
|
setlocale (LC_ALL, "");
|
|||
|
|
|||
|
bindtextdomain ("my_time", "/usr/share/locale");
|
|||
|
textdomain ("my_time");
|
|||
|
|
|||
|
printf( gettext("The time is: ") );
|
|||
|
|
|||
|
time(&date);
|
|||
|
tp = localtime(&date);
|
|||
|
strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %z %Y", tp);
|
|||
|
|
|||
|
printf ("%s\n",buf);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Οι εντολές bindtextdomain() και textdomain() αφορούν την nls βιβλιοθήκη (libintl) και την πληροφορούν ότι η μετάφραση του προγράμματος βρίσκεται στο my\_time.mo
|
|||
|
στον κατάλογο /usr/share/locale/XX, όπου ΧΧ η γλώσσα του χρήστη (καθορίζεται απο την μεταβλητή LANG ή LANGUAGE).
|
|||
|
|
|||
|
Επειδή πολλές φορές το να γράφουμε gettext(\...) είναι επίπονο για πολλά μηνύματα, χρησιμοποιούμε το:
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
#define _(Text) gettext(Text) /* στις επικέφαλίδες */
|
|||
|
|
|||
|
printf( _("The time is: ") );
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Το πρόγραμμα δεν θα λειτουργήσει ακομη με ελληνικά. Χρειάζεται ακόμη την δημιουργία του .po αρχείου. Αυτό είναι σχετικά απλό αν γίνει με το πρόγραμμα xgettext
|
|||
|
(από το πακέτο GNU gettext). Για το συγκεκριμένο πρόγραμμα η έξοδος του xgettext είναι: (σύνταξη \"xgettext my\_time.c\")
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
# messages.po
|
|||
|
# SOME DESCRIPTIVE TITLE.
|
|||
|
# Copyright (C) YEAR Free Software Foundation, Inc.
|
|||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
|||
|
#
|
|||
|
#, fuzzy
|
|||
|
msgid ""
|
|||
|
msgstr ""
|
|||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
|||
|
"POT-Creation-Date: 1998-11-11 22:52+0200\n"
|
|||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|||
|
"MIME-Version: 1.0\n"
|
|||
|
"Content-Type: text/plain; charset=CHARSET\n"
|
|||
|
"Content-Transfer-Encoding: ENCODING\n"
|
|||
|
|
|||
|
#: c.c:16
|
|||
|
msgid "The time is: "
|
|||
|
msgstr ""
|
|||
|
|
|||
|
#end of messages.po
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
και εδώ μετονομάζουμε το messages.po σε el.po, προσθέτοντας ταυτόχρονα στο msgstr την μετάφραση, πχ: msgstr \"Η ώρα είναι: \"
|
|||
|
|
|||
|
\* Τελευταίο μέλημα του προγραμματιστή είναι να μετατρέψει αυτό το .po αρχείο σε .mo ή .gmo μορφή. Αυτό επιτυγχάνεται με το πρόγραμμα msgfmt (από το GNU gettext
|
|||
|
πάλι). πχ msgfmt el.po -o el.gmo και μετά να αντιγραφεί στο /usr/share/locale/el/LC\_MESSAGES/ το el.gmo σαν my\_time.mo (αυτά τα τελευταία καλό είναι να γίνουν
|
|||
|
μέσω κάποιου makefile).
|
|||
|
|
|||
|
\* Autoconf Το σημαντικότερο τώρα είναι να αυτοματοποιήσουμε αυτή τη διαδικασία. Αυτό επιτυγχάνεται με το GNU autoconf. Ας φτιάξουμε ένα configure.in που θα
|
|||
|
ελέγχει κατά πόσο υπάρχει υποστήριξη nls από την libc και καθώς και του strftime. (για καλύτερες διαμορφώσεις κοιτάξτε στο:
|
|||
|
<http://teamball.sdsu.edu/doc/texi/gettext_toc.html>)
|
|||
|
|
|||
|
Για να απλοποιήσουμε τα πράγματα θεωρούμε την εξής διαμόρφωση των αρχείων του προγράμματος: (έστω ότι το πρόγραμμα είναι στο /xxx) στον κατάλογο /xxx/
|
|||
|
configure.in: Χρειάζεται για το autoconf (δείτε παρακάτω) config.h.in : (δείτε παρακάτω)
|
|||
|
|
|||
|
στον κατάλογο /xxx/src/
|
|||
|
my_time.c : Το πρόγραμμα
|
|||
|
|
|||
|
στον κατάλογο /xxx/po/
|
|||
|
my_time.pot : Αυτό είναι το messages.po που δημιουργείται απο το
|
|||
|
xgettext απλώς μετονομασμένο
|
|||
|
el.po : Το my_time.pot μεταφρασμένο στα ελληνικά
|
|||
|
POTFILES.in : Εδώ προσθέτετε όλα τα .c αρχεία στο src που χρησιμοποιούν
|
|||
|
το gettext. πχ:
|
|||
|
/xxx/src/my_time.c
|
|||
|
|
|||
|
Αρκεί τώρα να αντιγράψετε απο το πακέτο gettext-0.10 τα po/Makefile.in στον κατάλογο του προγραμματός /xxx/po/ , όλο τον κατάλογο intl/ στον /xxx/intl/ και τα
|
|||
|
ABOUT-NLS, aclocal.m4 στον /xxx .
|
|||
|
|
|||
|
Πάμε τώρα στον πρωταρχικό κατάλογο του προγράμματός μας (/xxx) και ας φτιάξουμε το configure.in απο το οποίο θα προκύψει το γνωστό(;) script configure.
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
# configure.in for my_time.c
|
|||
|
AC_INIT()
|
|||
|
AC_CONFIG_HEADER(config.h)
|
|||
|
|
|||
|
AC_PROG_CC
|
|||
|
AC_PATH_PROG(MAKE,make)
|
|||
|
AC_PROG_INSTALL
|
|||
|
|
|||
|
VERSION=1.0
|
|||
|
PROGRAMS="my_time"
|
|||
|
|
|||
|
AC_PREFIX_DEFAULT(/usr/local)
|
|||
|
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
|
|||
|
AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
|
|||
|
AC_SUBST(PACKAGE)
|
|||
|
AC_SUBST(VERSION)
|
|||
|
AC_SUBST(PROGRAMS)
|
|||
|
|
|||
|
dnl υποστηρίζουμε ελληνικά (τό el είναι απο το iso639 που πρέπει να
|
|||
|
dnl χρησιμοποιείται για την ένδειξη γλώσσας στις μεταφράσεις σύμφωνα με το
|
|||
|
dnl εγχειρίδιο το gettext.)
|
|||
|
ALL_LINGUAS="el"
|
|||
|
|
|||
|
dnl Για το gettext 0.10.
|
|||
|
ud_GNU_GETTEXT
|
|||
|
|
|||
|
AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
|
|||
|
|
|||
|
AC_FUNC_STRFTIME
|
|||
|
|
|||
|
AC_OUTPUT([Makefile src/Makefile intl/Makefile po/Makefile.in
|
|||
|
[sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile])
|
|||
|
|
|||
|
#end of configure.in
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
και αμέσως μετά δημιουργούμε ένα config.h.in (είναι βάση του αρχείου config.h που θα συμπεριλαμβάνεται στο πρόγραμμά μας. Η δημιουργία του config.h γίνεται απο
|
|||
|
το script configure.) Το config.h.in θα περιέχει:
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
# config.h.in for my_time.c
|
|||
|
/* Το όνομα του πακέτου (θα χρησιμοποιηθεί για το textdomain) */
|
|||
|
#undef PACKAGE
|
|||
|
#undef VERSION
|
|||
|
|
|||
|
/* strftime */
|
|||
|
#undef HAVE_STRFTIME
|
|||
|
#undef ENABLE_NLS
|
|||
|
|
|||
|
#end of config.h.in
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Το Makefile.in για το πρόγραμμα (το Makefile δημιουργείται επίσης αυτόματα απο το configure), πρέπει να έχει σε γενικές γραμμές τα:
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
# Makefile.in
|
|||
|
CC = @CC@
|
|||
|
LIBS = @LIBS@
|
|||
|
CCOPTS = @CFLAGS@ -I. -I..
|
|||
|
LN = @LN_S@
|
|||
|
INSTALL = @INSTALL@
|
|||
|
prefix = @prefix@
|
|||
|
exec_prefix = @prefix@
|
|||
|
datadir = $(prefix)/lib
|
|||
|
bin = $(prefix)/bin
|
|||
|
localedir = $(datadir)/locale
|
|||
|
DEFS = -DLOCALEDIR=\"$(localedir)\"
|
|||
|
SUBDIRS = @INTLSUB@ src @POSUB@
|
|||
|
MAKE = @MAKE@
|
|||
|
INSTALL = @INSTALL@
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
\#Εάν ο κώδικας σας δεν είναι στον src/ κατάλογο χρειάζεται ορισμένες αλλαγές
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
all:
|
|||
|
@for subdir in $(SUBDIRS); do \
|
|||
|
echo making all in $$subdir; \
|
|||
|
(cd $$subdir && $(MAKE) all) \
|
|||
|
|| case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
|
|||
|
done && test -z "$$fail"
|
|||
|
|
|||
|
install:
|
|||
|
@$(INSTALL) my_time $(bin)
|
|||
|
@$(MAKE) -C po/ install
|
|||
|
|
|||
|
# end of makefile.in
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
# src/Makefile.in
|
|||
|
# Εδώ οι επικεφαλίδες είναι περίπου ίδιες με πριν:
|
|||
|
CC = @CC@
|
|||
|
LIBS = @LIBS@
|
|||
|
CCOPTS = @CFLAGS@ -I../intl -I. -I..
|
|||
|
LN = @LN_S@
|
|||
|
INSTALL = @INSTALL@
|
|||
|
prefix = @prefix@
|
|||
|
exec_prefix = @prefix@
|
|||
|
datadir = $(prefix)/lib
|
|||
|
localedir = $(datadir)/locale
|
|||
|
DEFS = -DLOCALEDIR=\"$(localedir)\"
|
|||
|
|
|||
|
all: my_time
|
|||
|
|
|||
|
my_time: my_time.o
|
|||
|
$(CC) $(OBJECTS) -o ../my_time $(LIBDIRS) $(LIBS)
|
|||
|
|
|||
|
my_time.o: my_time.c
|
|||
|
$(CC) -c my_time.c $(CCOPTS) $(DEFS)
|
|||
|
|
|||
|
#end of src/Makefile.in
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Το πρόγραμμα τώρα θα γίνει:
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
# src/my_time.c
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include <time.h>
|
|||
|
#include <config.h> /* ή "config.h" αν δεν βάλετε το -I. στο Makefile */
|
|||
|
|
|||
|
#ifdef ENABLE_NLS
|
|||
|
#include <libintl.h>
|
|||
|
#endif
|
|||
|
|
|||
|
main ()
|
|||
|
{
|
|||
|
#ifdef HAVE_STRFTIME
|
|||
|
struct tm *tp;
|
|||
|
char buf[80];
|
|||
|
time_t date;
|
|||
|
#else
|
|||
|
time_t tv;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
#ifdef ENABLE_NLS
|
|||
|
setlocale (LC_ALL, "");
|
|||
|
bindtextdomain (PACKAGE, LOCALEDIR);
|
|||
|
textdomain (PACKAGE);
|
|||
|
# define _(Text) gettext(Text)
|
|||
|
#else
|
|||
|
# define _(Text) (Text)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
printf( _("The time is: ") );
|
|||
|
|
|||
|
#ifdef HAVE_STRFTIME_H
|
|||
|
time(&date);
|
|||
|
tp = localtime(&date);
|
|||
|
strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %z %Y", tp);
|
|||
|
printf ("%s\n",buf);
|
|||
|
#else
|
|||
|
time(&tv);
|
|||
|
printf ( "%s",ctime(&tv) );
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#end of src/my_time.c
|
|||
|
|
|||
|
----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|||
|
|
|||
|
Τώρα τρέχουμε το autoconf που δημιουργεί το configure script. Aν όλα πήγαν καλά έχουμε ένα πρόγραμμα που μιλάει ξένες γλώσσες!
|
|||
|
|
|||
|
\* Το παραπάνω κείμενο είναι μια εισαγωγή μόνο στο θέμα. Δεν έιναι σε καμιά περίπτωση πλήρες, αν θέλετε παραπάνω πληροφορίες συμβουλευτείτε τα εγχειρίδια των
|
|||
|
προγραμμάτων autoconf, gettext. Περισσότερα για το gettext (και την χρήση του με το autoconf) στο: <http://teamball.sdsu.edu/doc/texi/gettext_toc.html>
|