Πρώτο commit
Αυτό το commit περιλαμβάνεται σε:
commit
8ec8e9bee2
451 αρχεία άλλαξαν με 46736 προσθήκες και 0 διαγραφές
370
content/articles/12/03_nls2.md
Κανονικό αρχείο
370
content/articles/12/03_nls2.md
Κανονικό αρχείο
|
@ -0,0 +1,370 @@
|
|||
+++
|
||||
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>
|
Φόρτωση…
Προσθήκη πίνακα
Προσθήκη υπερσυνδέσμου
Παράθεση σε νέο ζήτημα