c7525e29c9005fb793b0954dbbe1fc9a949f6a6c
[scuttle] / includes / php-gettext / README
1 PHP-gettext 1.0
2
3 Copyright 2003, 2006 -- Danilo "angry with PHP[1]" Segan
4 Licensed under GPLv2 (or any later version, see COPYING)
5
6 [1] PHP is actually cyrillic, and translates roughly to 
7     "works-doesn't-work" (UTF-8: Ради-Не-Ради)
8
9
10 Introduction
11
12     How many times did you look for a good translation tool, and
13     found out that gettext is best for the job? Many times.
14
15     How many times did you try to use gettext in PHP, but failed
16     miserably, because either your hosting provider didn't support
17     it, or the server didn't have adequate locale? Many times.
18
19     Well, this is a solution to your needs. It allows using gettext
20     tools for managing translations, yet it doesn't require gettext
21     library at all. It parses generated MO files directly, and thus
22     might be a bit slower than the (maybe provided) gettext library.
23
24     PHP-gettext is a simple reader for GNU gettext MO files. Those
25     are binary containers for translations, produced by GNU msgfmt.
26
27 Why?
28
29     I got used to having gettext work even without gettext
30     library. It's there in my favourite language Python, so I was
31     surprised that I couldn't find it in PHP. I even Googled for it,
32     but to no avail.
33
34     So, I said, what the heck, I'm going to write it for this
35     disguisting language of PHP, because I'm often constrained to it.
36
37 Features
38
39   o Support for simple translations
40     Just define a simple alias for translate() function (suggested
41     use of _() or gettext(); see provided example).
42
43   o Support for ngettext calls (plural forms, see a note under bugs)
44     You may also use plural forms. Translations in MO files need to
45     provide this, and they must also provide "plural-forms" header.
46     Please see 'info gettext' for more details.
47
48   o Support for reading straight files, or strings (!!!)
49     Since I can imagine many different backends for reading in the MO
50     file data, I used imaginary abstract class StreamReader to do all
51     the input (check streams.php). For your convenience, I've already
52     provided two classes for reading files: FileReader and
53     StringReader (CachedFileReader is a combination of the two: it 
54     loads entire file contents into a string, and then works on that). 
55     See example below for usage. You can for instance use StringReader 
56     when you read in data from a database, or you can create your own 
57     derivative of StreamReader for anything you like. 
58     
59
60 Bugs
61
62     Plural-forms field in MO header (translation for empty string,
63     i.e. "") is treated according to PHP syntactic rules (it's
64     eval()ed). Since these should actually follow C syntax, there are
65     some problems.
66
67     For instance, I'm used to using this:
68       Plural-Forms: nplurals=3;    plural=n%10==1 && n%100!=11 ? 0 : \
69          n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
70     but it fails with PHP (it sets $plural=2 instead of 0 for $n==1).
71
72     The fix is usually simple, but I'm lazy to go into the details of
73     PHP operator precedence, and maybe try to fix it. In here, I had
74     to put everything after the first ':' in parenthesis:
75       Plural-Forms: nplurals=3;    plural=n%10==1 && n%100!=11 ? 0 : \
76          (n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
77     That works, and I'm satisfied.
78
79     Besides this one, there are probably a bunch of other bugs, since
80     I hate PHP (did I mention it already? no? strange), and don't
81     know it very well. So, feel free to fix any of those and report
82     them back to me at <danilo@kvota.net>.
83
84 Usage
85
86     Put files streams.php and gettext.php somewhere you can load them
87     from, and require 'em in where you want to use them.
88
89     Then, create one 'stream reader' (a class that provides functions
90     like read(), seekto(), currentpos() and length()) which will
91     provide data for the 'gettext_reader', with eg.
92       $streamer = new FileStream('data.mo');
93
94     Then, use that as a parameter to gettext_reader constructor:
95       $wohoo = new gettext_reader($streamer);
96
97     If you want to disable pre-loading of entire message catalog in 
98     memory (if, for example, you have a multi-thousand message catalog 
99     which you'll use only occasionally), use "false" for second 
100     parameter to gettext_reader constructor:
101       $wohoo = new gettext_reader($streamer, false);
102
103     From now on, you have all the benefits of gettext data at your
104     disposal, so may run: 
105       print $wohoo->translate("This is a test");
106       print $wohoo->ngettext("%d bird", "%d birds", $birds);
107
108     You might need to pass parameter "-k" to xgettext to make it
109     extract all the strings. In above example, try with 
110       xgettext -ktranslate -kngettext:1,2 file.php
111     what should create messages.po which contains two messages for
112     translation.
113
114     I suggest creating simple aliases for these functions (see
115     example/pigs.php for how do I do it, which means it's probably a
116     bad way).
117
118
119 Usage with gettext.inc (standard gettext interfaces emulation)
120
121     Check example in examples/pig_dropin.php, basically you include 
122     gettext.inc and use all the standard gettext interfaces as 
123     documented on:
124
125        http://www.php.net/gettext
126
127     The only catch is that you can check return value of setlocale()
128     to see if your locale is system supported or not.
129
130
131 Example
132
133     See in examples/ subdirectory. There are a couple of files.
134     pigs.php is an example, serbian.po is a translation to Serbian
135     language, and serbian.mo is generated with
136        msgfmt -o serbian.mo serbian.po
137     There is also simple "update" script that can be used to generate
138     POT file and to update the translation using msgmerge.
139
140 Interesting TODO:
141
142   o Try to parse "plural-forms" header field, and to follow C syntax
143     rules. This won't be easy.
144
145 Boring TODO:
146
147   o Learn PHP and fix bugs, slowness and other stuff resulting from
148     my lack of knowledge (but *maybe*, it's not my knowledge that is
149     bad, but PHP itself ;-).  
150
151     (This is mostly done thanks to Nico Kaiser.)
152
153   o Try to use hash tables in MO files: with pre-loading, would it 
154     be useful at all?
155
156 Never-asked-questions:
157
158   o Why did you mark this as version 1.0 when this is the first code
159     release?
160
161     Well, it's quite simple. I consider that the first released thing
162     should be labeled "version 1" (first, right?). Zero is there to
163     indicate that there's zero improvement and/or change compared to 
164     "version 1".
165
166     I plan to use version numbers 1.0.* for small bugfixes, and to
167     release 1.1 as "first stable release of version 1".
168
169     This may trick someone that this is actually useful software, but
170     as with any other free software, I take NO RESPONSIBILITY for
171     creating such a masterpiece that will smoke crack, trash your
172     hard disk, and make lasers in your CD device dance to the tune of
173     Mozart's 40th Symphony (there is one like that, right?).
174
175   o Can I...?
176     
177     Yes, you can. This is free software (as in freedom, free speech),
178     and you might do whatever you wish with it, provided you do not
179     limit freedom of others (GPL).
180
181     I'm considering licensing this under LGPL, but I *do* want
182     *every* PHP-gettext user to contribute and respect ideas of free
183     software, so don't count on it happening anytime soon.
184
185     I'm sorry that I'm taking away your freedom of taking others'
186     freedom away, but I believe that's neglible as compared to what
187     freedoms you could take away. ;-)
188
189     Uhm, whatever.

Benjamin Mako Hill || Want to submit a patch?