[4686] | 1 | PHP-gettext 1.0 (https://launchpad.net/php-gettext) |
---|
| 2 | |
---|
| 3 | Copyright 2003, 2006, 2009 -- 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 | Report them on https://bugs.launchpad.net/php-gettext |
---|
| 63 | |
---|
| 64 | Usage |
---|
| 65 | |
---|
| 66 | Put files streams.php and gettext.php somewhere you can load them |
---|
| 67 | from, and require 'em in where you want to use them. |
---|
| 68 | |
---|
| 69 | Then, create one 'stream reader' (a class that provides functions |
---|
| 70 | like read(), seekto(), currentpos() and length()) which will |
---|
| 71 | provide data for the 'gettext_reader', with eg. |
---|
| 72 | $streamer = new FileStream('data.mo'); |
---|
| 73 | |
---|
| 74 | Then, use that as a parameter to gettext_reader constructor: |
---|
| 75 | $wohoo = new gettext_reader($streamer); |
---|
| 76 | |
---|
| 77 | If you want to disable pre-loading of entire message catalog in |
---|
| 78 | memory (if, for example, you have a multi-thousand message catalog |
---|
| 79 | which you'll use only occasionally), use "false" for second |
---|
| 80 | parameter to gettext_reader constructor: |
---|
| 81 | $wohoo = new gettext_reader($streamer, false); |
---|
| 82 | |
---|
| 83 | From now on, you have all the benefits of gettext data at your |
---|
| 84 | disposal, so may run: |
---|
| 85 | print $wohoo->translate("This is a test"); |
---|
| 86 | print $wohoo->ngettext("%d bird", "%d birds", $birds); |
---|
| 87 | |
---|
| 88 | You might need to pass parameter "-k" to xgettext to make it |
---|
| 89 | extract all the strings. In above example, try with |
---|
| 90 | xgettext -ktranslate -kngettext:1,2 file.php |
---|
| 91 | what should create messages.po which contains two messages for |
---|
| 92 | translation. |
---|
| 93 | |
---|
| 94 | I suggest creating simple aliases for these functions (see |
---|
| 95 | example/pigs.php for how do I do it, which means it's probably a |
---|
| 96 | bad way). |
---|
| 97 | |
---|
| 98 | |
---|
| 99 | Usage with gettext.inc (standard gettext interfaces emulation) |
---|
| 100 | |
---|
| 101 | Check example in examples/pig_dropin.php, basically you include |
---|
| 102 | gettext.inc and use all the standard gettext interfaces as |
---|
| 103 | documented on: |
---|
| 104 | |
---|
| 105 | http://www.php.net/gettext |
---|
| 106 | |
---|
| 107 | The only catch is that you can check return value of setlocale() |
---|
| 108 | to see if your locale is system supported or not. |
---|
| 109 | |
---|
| 110 | |
---|
| 111 | Example |
---|
| 112 | |
---|
| 113 | See in examples/ subdirectory. There are a couple of files. |
---|
| 114 | pigs.php is an example, serbian.po is a translation to Serbian |
---|
| 115 | language, and serbian.mo is generated with |
---|
| 116 | msgfmt -o serbian.mo serbian.po |
---|
| 117 | There is also simple "update" script that can be used to generate |
---|
| 118 | POT file and to update the translation using msgmerge. |
---|
| 119 | |
---|
| 120 | TODO: |
---|
| 121 | |
---|
| 122 | o Improve speed to be even more comparable to the native gettext |
---|
| 123 | implementation. |
---|
| 124 | |
---|
| 125 | o Try to use hash tables in MO files: with pre-loading, would it |
---|
| 126 | be useful at all? |
---|
| 127 | |
---|
| 128 | Never-asked-questions: |
---|
| 129 | |
---|
| 130 | o Why did you mark this as version 1.0 when this is the first code |
---|
| 131 | release? |
---|
| 132 | |
---|
| 133 | Well, it's quite simple. I consider that the first released thing |
---|
| 134 | should be labeled "version 1" (first, right?). Zero is there to |
---|
| 135 | indicate that there's zero improvement and/or change compared to |
---|
| 136 | "version 1". |
---|
| 137 | |
---|
| 138 | I plan to use version numbers 1.0.* for small bugfixes, and to |
---|
| 139 | release 1.1 as "first stable release of version 1". |
---|
| 140 | |
---|
| 141 | This may trick someone that this is actually useful software, but |
---|
| 142 | as with any other free software, I take NO RESPONSIBILITY for |
---|
| 143 | creating such a masterpiece that will smoke crack, trash your |
---|
| 144 | hard disk, and make lasers in your CD device dance to the tune of |
---|
| 145 | Mozart's 40th Symphony (there is one like that, right?). |
---|
| 146 | |
---|
| 147 | o Can I...? |
---|
| 148 | |
---|
| 149 | Yes, you can. This is free software (as in freedom, free speech), |
---|
| 150 | and you might do whatever you wish with it, provided you do not |
---|
| 151 | limit freedom of others (GPL). |
---|
| 152 | |
---|
| 153 | I'm considering licensing this under LGPL, but I *do* want |
---|
| 154 | *every* PHP-gettext user to contribute and respect ideas of free |
---|
| 155 | software, so don't count on it happening anytime soon. |
---|
| 156 | |
---|
| 157 | I'm sorry that I'm taking away your freedom of taking others' |
---|
| 158 | freedom away, but I believe that's neglible as compared to what |
---|
| 159 | freedoms you could take away. ;-) |
---|
| 160 | |
---|
| 161 | Uhm, whatever. |
---|