Add php-gettext and smarty-gettext
Add php-gettext and smarty-gettext

  Danilo Segan <danilo@kvota.net>
  Nico Kaiser <nico@siriux.net> (contributed most changes between 1.0.2 and 1.0.3, bugfix for 1.0.5)
  Steven Armstrong <sa@c-area.ch> (gettext.inc, leading to 1.0.6)
 
  GNU GENERAL PUBLIC LICENSE
  Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
  Preamble
 
  The licenses for most software are designed to take away your
  freedom to share and change it. By contrast, the GNU General Public
  License is intended to guarantee your freedom to share and change free
  software--to make sure the software is free for all its users. This
  General Public License applies to most of the Free Software
  Foundation's software and to any other program whose authors commit to
  using it. (Some other Free Software Foundation software is covered by
  the GNU Library General Public License instead.) You can apply it to
  your programs, too.
 
  When we speak of free software, we are referring to freedom, not
  price. Our General Public Licenses are designed to make sure that you
  have the freedom to distribute copies of free software (and charge for
  this service if you wish), that you receive source code or can get it
  if you want it, that you can change the software or use pieces of it
  in new free programs; and that you know you can do these things.
 
  To protect your rights, we need to make restrictions that forbid
  anyone to deny you these rights or to ask you to surrender the rights.
  These restrictions translate to certain responsibilities for you if you
  distribute copies of the software, or if you modify it.
 
  For example, if you distribute copies of such a program, whether
  gratis or for a fee, you must give the recipients all the rights that
  you have. You must make sure that they, too, receive or can get the
  source code. And you must show them these terms so they know their
  rights.
 
  We protect your rights with two steps: (1) copyright the software, and
  (2) offer you this license which gives you legal permission to copy,
  distribute and/or modify the software.
 
  Also, for each author's protection and ours, we want to make certain
  that everyone understands that there is no warranty for this free
  software. If the software is modified by someone else and passed on, we
  want its recipients to know that what they have is not the original, so
  that any problems introduced by others will not reflect on the original
  authors' reputations.
 
  Finally, any free program is threatened constantly by software
  patents. We wish to avoid the danger that redistributors of a free
  program will individually obtain patent licenses, in effect making the
  program proprietary. To prevent this, we have made it clear that any
  patent must be licensed for everyone's free use or not licensed at all.
 
  The precise terms and conditions for copying, distribution and
  modification follow.
 
  GNU GENERAL PUBLIC LICENSE
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
  0. This License applies to any program or other work which contains
  a notice placed by the copyright holder saying it may be distributed
  under the terms of this General Public License. The "Program", below,
  refers to any such program or work, and a "work based on the Program"
  means either the Program or any derivative work under copyright law:
  that is to say, a work containing the Program or a portion of it,
  either verbatim or with modifications and/or translated into another
  language. (Hereinafter, translation is included without limitation in
  the term "modification".) Each licensee is addressed as "you".
 
  Activities other than copying, distribution and modification are not
  covered by this License; they are outside its scope. The act of
  running the Program is not restricted, and the output from the Program
  is covered only if its contents constitute a work based on the
  Program (independent of having been made by running the Program).
  Whether that is true depends on what the Program does.
 
  1. You may copy and distribute verbatim copies of the Program's
  source code as you receive it, in any medium, provided that you
  conspicuously and appropriately publish on each copy an appropriate
  copyright notice and disclaimer of warranty; keep intact all the
  notices that refer to this License and to the absence of any warranty;
  and give any other recipients of the Program a copy of this License
  along with the Program.
 
  You may charge a fee for the physical act of transferring a copy, and
  you may at your option offer warranty protection in exchange for a fee.
 
  2. You may modify your copy or copies of the Program or any portion
  of it, thus forming a work based on the Program, and copy and
  distribute such modifications or work under the terms of Section 1
  above, provided that you also meet all of these conditions:
 
  a) You must cause the modified files to carry prominent notices
  stating that you changed the files and the date of any change.
 
  b) You must cause any work that you distribute or publish, that in
  whole or in part contains or is derived from the Program or any
  part thereof, to be licensed as a whole at no charge to all third
  parties under the terms of this License.
 
  c) If the modified program normally reads commands interactively
  when run, you must cause it, when started running for such
  interactive use in the most ordinary way, to print or display an
  announcement including an appropriate copyright notice and a
  notice that there is no warranty (or else, saying that you provide
  a warranty) and that users may redistribute the program under
  these conditions, and telling the user how to view a copy of this
  License. (Exception: if the Program itself is interactive but
  does not normally print such an announcement, your work based on
  the Program is not required to print an announcement.)
 
  These requirements apply to the modified work as a whole. If
  identifiable sections of that work are not derived from the Program,
  and can be reasonably considered independent and separate works in
  themselves, then this License, and its terms, do not apply to those
  sections when you distribute them as separate works. But when you
  distribute the same sections as part of a whole which is a work based
  on the Program, the distribution of the whole must be on the terms of
  this License, whose permissions for other licensees extend to the
  entire whole, and thus to each and every part regardless of who wrote it.
 
  Thus, it is not the intent of this section to claim rights or contest
  your rights to work written entirely by you; rather, the intent is to
  exercise the right to control the distribution of derivative or
  collective works based on the Program.
 
  In addition, mere aggregation of another work not based on the Program
  with the Program (or with a work based on the Program) on a volume of
  a storage or distribution medium does not bring the other work under
  the scope of this License.
 
  3. You may copy and distribute the Program (or a work based on it,
  under Section 2) in object code or executable form under the terms of
  Sections 1 and 2 above provided that you also do one of the following:
 
  a) Accompany it with the complete corresponding machine-readable
  source code, which must be distributed under the terms of Sections
  1 and 2 above on a medium customarily used for software interchange; or,
 
  b) Accompany it with a written offer, valid for at least three
  years, to give any third party, for a charge no more than your
  cost of physically performing source distribution, a complete
  machine-readable copy of the corresponding source code, to be
  distributed under the terms of Sections 1 and 2 above on a medium
  customarily used for software interchange; or,
 
  c) Accompany it with the information you received as to the offer
  to distribute corresponding source code. (This alternative is
  allowed only for noncommercial distribution and only if you
  received the program in object code or executable form with such
  an offer, in accord with Subsection b above.)
 
  The source code for a work means the preferred form of the work for
  making modifications to it. For an executable work, complete source
  code means all the source code for all modules it contains, plus any
  associated interface definition files, plus the scripts used to
  control compilation and installation of the executable. However, as a
  special exception, the source code distributed need not include
  anything that is normally distributed (in either source or binary
  form) with the major components (compiler, kernel, and so on) of the
  operating system on which the executable runs, unless that component
  itself accompanies the executable.
 
  If distribution of executable or object code is made by offering
  access to copy from a designated place, then offering equivalent
  access to copy the source code from the same place counts as
  distribution of the source code, even though third parties are not
  compelled to copy the source along with the object code.
 
  4. You may not copy, modify, sublicense, or distribute the Program
  except as expressly provided under this License. Any attempt
  otherwise to copy, modify, sublicense or distribute the Program is
  void, and will automatically terminate your rights under this License.
  However, parties who have received copies, or rights, from you under
  this License will not have their licenses terminated so long as such
  parties remain in full compliance.
 
  5. You are not required to accept this License, since you have not
  signed it. However, nothing else grants you permission to modify or
  distribute the Program or its derivative works. These actions are
  prohibited by law if you do not accept this License. Therefore, by
  modifying or distributing the Program (or any work based on the
  Program), you indicate your acceptance of this License to do so, and
  all its terms and conditions for copying, distributing or modifying
  the Program or works based on it.
 
  6. Each time you redistribute the Program (or any work based on the
  Program), the recipient automatically receives a license from the
  original licensor to copy, distribute or modify the Program subject to
  these terms and conditions. You may not impose any further
  restrictions on the recipients' exercise of the rights granted herein.
  You are not responsible for enforcing compliance by third parties to
  this License.
 
  7. If, as a consequence of a court judgment or allegation of patent
  infringement or for any other reason (not limited to patent issues),
  conditions are imposed on you (whether by court order, agreement or
  otherwise) that contradict the conditions of this License, they do not
  excuse you from the conditions of this License. If you cannot
  distribute so as to satisfy simultaneously your obligations under this
  License and any other pertinent obligations, then as a consequence you
  may not distribute the Program at all. For example, if a patent
  license would not permit royalty-free redistribution of the Program by
  all those who receive copies directly or indirectly through you, then
  the only way you could satisfy both it and this License would be to
  refrain entirely from distribution of the Program.
 
  If any portion of this section is held invalid or unenforceable under
  any particular circumstance, the balance of the section is intended to
  apply and the section as a whole is intended to apply in other
  circumstances.
 
  It is not the purpose of this section to induce you to infringe any
  patents or other property right claims or to contest validity of any
  such claims; this section has the sole purpose of protecting the
  integrity of the free software distribution system, which is
  implemented by public license practices. Many people have made
  generous contributions to the wide range of software distributed
  through that system in reliance on consistent application of that
  system; it is up to the author/donor to decide if he or she is willing
  to distribute software through any other system and a licensee cannot
  impose that choice.
 
  This section is intended to make thoroughly clear what is believed to
  be a consequence of the rest of this License.
 
  8. If the distribution and/or use of the Program is restricted in
  certain countries either by patents or by copyrighted interfaces, the
  original copyright holder who places the Program under this License
  may add an explicit geographical distribution limitation excluding
  those countries, so that distribution is permitted only in or among
  countries not thus excluded. In such case, this License incorporates
  the limitation as if written in the body of this License.
 
  9. The Free Software Foundation may publish revised and/or new versions
  of the General Public License from time to time. Such new versions will
  be similar in spirit to the present version, but may differ in detail to
  address new problems or concerns.
 
  Each version is given a distinguishing version number. If the Program
  specifies a version number of this License which applies to it and "any
  later version", you have the option of following the terms and conditions
  either of that version or of any later version published by the Free
  Software Foundation. If the Program does not specify a version number of
  this License, you may choose any version ever published by the Free Software
  Foundation.
 
  10. If you wish to incorporate parts of the Program into other free
  programs whose distribution conditions are different, write to the author
  to ask for permission. For software which is copyrighted by the Free
  Software Foundation, write to the Free Software Foundation; we sometimes
  make exceptions for this. Our decision will be guided by the two goals
  of preserving the free status of all derivatives of our free software and
  of promoting the sharing and reuse of software generally.
 
  NO WARRANTY
 
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
  OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
  TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
  PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  REPAIR OR CORRECTION.
 
  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGES.
 
  END OF TERMS AND CONDITIONS
 
  How to Apply These Terms to Your New Programs
 
  If you develop a new program, and you want it to be of the greatest
  possible use to the public, the best way to achieve this is to make it
  free software which everyone can redistribute and change under these terms.
 
  To do so, attach the following notices to the program. It is safest
  to attach them to the start of each source file to most effectively
  convey the exclusion of warranty; and each file should have at least
  the "copyright" line and a pointer to where the full notice is found.
 
  <one line to give the program's name and a brief idea of what it does.>
  Copyright (C) <year> <name of author>
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
 
  Also add information on how to contact you by electronic and paper mail.
 
  If the program is interactive, make it output a short notice like this
  when it starts in an interactive mode:
 
  Gnomovision version 69, Copyright (C) year name of author
  Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  This is free software, and you are welcome to redistribute it
  under certain conditions; type `show c' for details.
 
  The hypothetical commands `show w' and `show c' should show the appropriate
  parts of the General Public License. Of course, the commands you use may
  be called something other than `show w' and `show c'; they could even be
  mouse-clicks or menu items--whatever suits your program.
 
  You should also get your employer (if you work as a programmer) or your
  school, if any, to sign a "copyright disclaimer" for the program, if
  necessary. Here is a sample; alter the names:
 
  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.
 
  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice
 
  This General Public License does not permit incorporating your program into
  proprietary programs. If your program is a subroutine library, you may
  consider it more useful to permit linking proprietary applications with the
  library. If this is what you want to do, use the GNU Library General
  Public License instead of this License.
 
  PACKAGE = php-gettext-$(VERSION)
  VERSION = 1.0.10
 
  DIST_FILES = \
  gettext.php \
  gettext.inc \
  streams.php \
  AUTHORS \
  README \
  COPYING \
  Makefile \
  examples/index.php \
  examples/pigs_dropin.php \
  examples/pigs_fallback.php \
  examples/locale/sr_CS/LC_MESSAGES/messages.po \
  examples/locale/sr_CS/LC_MESSAGES/messages.mo \
  examples/locale/de_CH/LC_MESSAGES/messages.po \
  examples/locale/de_CH/LC_MESSAGES/messages.mo \
  examples/update \
  tests/LocalesTest.php \
  tests/ParsingTest.php
 
  check:
  phpunit --verbose tests
 
  dist: check
  if [ -d $(PACKAGE) ]; then \
  rm -rf $(PACKAGE); \
  fi; \
  mkdir $(PACKAGE); \
  if [ -d $(PACKAGE) ]; then \
  cp -rp --parents $(DIST_FILES) $(PACKAGE); \
  tar cvzf $(PACKAGE).tar.gz $(PACKAGE); \
  rm -rf $(PACKAGE); \
  fi;
 
  clean:
  rm -f $(PACKAGE).tar.gz
 
  PHP-gettext 1.0 (https://launchpad.net/php-gettext)
 
  Copyright 2003, 2006, 2009 -- Danilo "angry with PHP[1]" Segan
  Licensed under GPLv2 (or any later version, see COPYING)
 
  [1] PHP is actually cyrillic, and translates roughly to
  "works-doesn't-work" (UTF-8: Ради-Не-Ради)
 
 
  Introduction
 
  How many times did you look for a good translation tool, and
  found out that gettext is best for the job? Many times.
 
  How many times did you try to use gettext in PHP, but failed
  miserably, because either your hosting provider didn't support
  it, or the server didn't have adequate locale? Many times.
 
  Well, this is a solution to your needs. It allows using gettext
  tools for managing translations, yet it doesn't require gettext
  library at all. It parses generated MO files directly, and thus
  might be a bit slower than the (maybe provided) gettext library.
 
  PHP-gettext is a simple reader for GNU gettext MO files. Those
  are binary containers for translations, produced by GNU msgfmt.
 
  Why?
 
  I got used to having gettext work even without gettext
  library. It's there in my favourite language Python, so I was
  surprised that I couldn't find it in PHP. I even Googled for it,
  but to no avail.
 
  So, I said, what the heck, I'm going to write it for this
  disguisting language of PHP, because I'm often constrained to it.
 
  Features
 
  o Support for simple translations
  Just define a simple alias for translate() function (suggested
  use of _() or gettext(); see provided example).
 
  o Support for ngettext calls (plural forms, see a note under bugs)
  You may also use plural forms. Translations in MO files need to
  provide this, and they must also provide "plural-forms" header.
  Please see 'info gettext' for more details.
 
  o Support for reading straight files, or strings (!!!)
  Since I can imagine many different backends for reading in the MO
  file data, I used imaginary abstract class StreamReader to do all
  the input (check streams.php). For your convenience, I've already
  provided two classes for reading files: FileReader and
  StringReader (CachedFileReader is a combination of the two: it
  loads entire file contents into a string, and then works on that).
  See example below for usage. You can for instance use StringReader
  when you read in data from a database, or you can create your own
  derivative of StreamReader for anything you like.
 
 
  Bugs
 
  Report them on https://bugs.launchpad.net/php-gettext
 
  Usage
 
  Put files streams.php and gettext.php somewhere you can load them
  from, and require 'em in where you want to use them.
 
  Then, create one 'stream reader' (a class that provides functions
  like read(), seekto(), currentpos() and length()) which will
  provide data for the 'gettext_reader', with eg.
  $streamer = new FileStream('data.mo');
 
  Then, use that as a parameter to gettext_reader constructor:
  $wohoo = new gettext_reader($streamer);
 
  If you want to disable pre-loading of entire message catalog in
  memory (if, for example, you have a multi-thousand message catalog
  which you'll use only occasionally), use "false" for second
  parameter to gettext_reader constructor:
  $wohoo = new gettext_reader($streamer, false);
 
  From now on, you have all the benefits of gettext data at your
  disposal, so may run:
  print $wohoo->translate("This is a test");
  print $wohoo->ngettext("%d bird", "%d birds", $birds);
 
  You might need to pass parameter "-k" to xgettext to make it
  extract all the strings. In above example, try with
  xgettext -ktranslate -kngettext:1,2 file.php
  what should create messages.po which contains two messages for
  translation.
 
  I suggest creating simple aliases for these functions (see
  example/pigs.php for how do I do it, which means it's probably a
  bad way).
 
 
  Usage with gettext.inc (standard gettext interfaces emulation)
 
  Check example in examples/pig_dropin.php, basically you include
  gettext.inc and use all the standard gettext interfaces as
  documented on:
 
  http://www.php.net/gettext
 
  The only catch is that you can check return value of setlocale()
  to see if your locale is system supported or not.
 
 
  Example
 
  See in examples/ subdirectory. There are a couple of files.
  pigs.php is an example, serbian.po is a translation to Serbian
  language, and serbian.mo is generated with
  msgfmt -o serbian.mo serbian.po
  There is also simple "update" script that can be used to generate
  POT file and to update the translation using msgmerge.
 
  TODO:
 
  o Improve speed to be even more comparable to the native gettext
  implementation.
 
  o Try to use hash tables in MO files: with pre-loading, would it
  be useful at all?
 
  Never-asked-questions:
 
  o Why did you mark this as version 1.0 when this is the first code
  release?
 
  Well, it's quite simple. I consider that the first released thing
  should be labeled "version 1" (first, right?). Zero is there to
  indicate that there's zero improvement and/or change compared to
  "version 1".
 
  I plan to use version numbers 1.0.* for small bugfixes, and to
  release 1.1 as "first stable release of version 1".
 
  This may trick someone that this is actually useful software, but
  as with any other free software, I take NO RESPONSIBILITY for
  creating such a masterpiece that will smoke crack, trash your
  hard disk, and make lasers in your CD device dance to the tune of
  Mozart's 40th Symphony (there is one like that, right?).
 
  o Can I...?
 
  Yes, you can. This is free software (as in freedom, free speech),
  and you might do whatever you wish with it, provided you do not
  limit freedom of others (GPL).
 
  I'm considering licensing this under LGPL, but I *do* want
  *every* PHP-gettext user to contribute and respect ideas of free
  software, so don't count on it happening anytime soon.
 
  I'm sorry that I'm taking away your freedom of taking others'
  freedom away, but I believe that's neglible as compared to what
  freedoms you could take away. ;-)
 
  Uhm, whatever.
 
  <html>
  <head>
  <title>PHP-gettext examples</title>
  </head>
  <body>
  <h1>PHP-gettext</h1>
 
  <h2>Introduction</h2>
  <p>PHP-gettext provides a simple gettext replacement that works independently from the system's gettext abilities.
  It can read MO files and use them for translating strings.</p>
  <p>This version has the ability to cache all strings and translations to speed up the string lookup.
  While the cache is enabled by default, it can be switched off with the second parameter in the constructor (e.g. when using very large MO files
  that you don't want to keep in memory)</p>
 
 
  <h2>Examples</h2>
  <ul>
  <li><a href="pigs_dropin.php">PHP-gettext as a dropin replacement</a></li>
  <li><a href="pigs_fallback.php">PHP-gettext as a fallback solution</a></li>
  </ul>
 
  <hr />
  <p>Copyright (c) 2003-2006 Danilo Segan</p>
  <p>Copyright (c) 2005-2006 Steven Armstrong</p>
 
  </body>
  </html>
 
 Binary files /dev/null and b/lib/php-gettext/examples/locale/de_CH/LC_MESSAGES/messages.mo differ
  # Sample translation for PHP-gettext 1.0
  # Copyright (c) 2003 Danilo Segan <danilo@kvota.net>
  #
  msgid ""
  msgstr ""
  "Project-Id-Version: pigs\n"
  "Report-Msgid-Bugs-To: \n"
  "POT-Creation-Date: 2003-10-23 04:50+0200\n"
  "PO-Revision-Date: 2003-11-01 23:40+0100\n"
  "Last-Translator: Danilo Segan <danilo@kvota.net>\n"
  "Language-Team: Serbian (sr) <danilo@kvota.net>\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"
 
  #: pigs.php:19
  msgid ""
  "This is how the story goes.\n"
  "\n"
  msgstr ""
  "Und so geht die Geschichte.\n"
  "\n"
 
  #: pigs.php:21
  #, php-format
  msgid "%d pig went to the market\n"
  msgid_plural "%d pigs went to the market\n"
  msgstr[0] "%d Schwein ging zum Markt\n"
  msgstr[1] "%d Schweine gingen zum Markt\n"
 
 Binary files /dev/null and b/lib/php-gettext/examples/locale/sr_CS/LC_MESSAGES/messages.mo differ
  # Sample translation for PHP-gettext 1.0
  # Copyright (c) 2003,2006 Danilo Segan <danilo@kvota.net>
  #
  msgid ""
  msgstr ""
  "Project-Id-Version: pigs\n"
  "Report-Msgid-Bugs-To: \n"
  "POT-Creation-Date: 2003-10-23 04:50+0200\n"
  "PO-Revision-Date: 2006-02-02 21:06+0100\n"
  "Last-Translator: Danilo Segan <danilo@kvota.net>\n"
  "Language-Team: Serbian (sr) <danilo@kvota.net>\n"
  "MIME-Version: 1.0\n"
  "Content-Type: text/plain; charset=UTF-8\n"
  "Content-Transfer-Encoding: 8bit\n"
  "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
  "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
 
  #: pigs.php:19
  msgid ""
  "This is how the story goes.\n"
  "\n"
  msgstr "Овако иде прича.\n\n"
 
  #: pigs.php:21
  #, php-format
  msgid "%d pig went to the market\n"
  msgid_plural "%d pigs went to the market\n"
  msgstr[0] "%d мало прасе је отишло на пијац\n"
  msgstr[1] "%d мала прасета су отишла на пијац\n"
  msgstr[2] "%d малих прасића је отишло на пијац\n"
 
  <?php
  /*
  Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
  Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
 
  This file is part of PHP-gettext.
 
  PHP-gettext is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  PHP-gettext is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with PHP-gettext; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
  */
 
  error_reporting(E_ALL | E_STRICT);
 
  // define constants
  define('PROJECT_DIR', realpath('./'));
  define('LOCALE_DIR', PROJECT_DIR .'/locale');
  define('DEFAULT_LOCALE', 'en_US');
 
  require_once('../gettext.inc');
 
  $supported_locales = array('en_US', 'sr_CS', 'de_CH');
  $encoding = 'UTF-8';
 
  $locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
 
  // gettext setup
  T_setlocale(LC_MESSAGES, $locale);
  // Set the text domain as 'messages'
  $domain = 'messages';
  bindtextdomain($domain, LOCALE_DIR);
  // bind_textdomain_codeset is supported only in PHP 4.2.0+
  if (function_exists('bind_textdomain_codeset'))
  bind_textdomain_codeset($domain, $encoding);
  textdomain($domain);
 
  header("Content-type: text/html; charset=$encoding");
  ?>
  <html>
  <head>
  <title>PHP-gettext dropin example</title>
  </head>
  <body>
  <h1>PHP-gettext as a dropin replacement</h1>
  <p>Example showing how to use PHP-gettext as a dropin replacement for the native gettext library.</p>
  <?php
  print "<p>";
  foreach($supported_locales as $l) {
  print "[<a href=\"?lang=$l\">$l</a>] ";
  }
  print "</p>\n";
 
  if (!locale_emulation()) {
  print "<p>locale '$locale' is supported by your system, using native gettext implementation.</p>\n";
  }
  else {
  print "<p>locale '$locale' is _not_ supported on your system, using the default locale '". DEFAULT_LOCALE ."'.</p>\n";
  }
  ?>
 
  <hr />
 
  <?php
  // using PHP-gettext
  print "<pre>";
  print _("This is how the story goes.\n\n");
  for ($number=6; $number>=0; $number--) {
  print sprintf(T_ngettext("%d pig went to the market\n",
  "%d pigs went to the market\n", $number),
  $number );
  }
  print "</pre>\n";
  ?>
 
  <hr />
  <p>&laquo; <a href="./">back</a></p>
  </body>
  </html>
 
  <?php
  /*
  Copyright (c) 2003,2004,2005,2009 Danilo Segan <danilo@kvota.net>.
  Copyright (c) 2005,2006 Steven Armstrong <sa@c-area.ch>
 
  This file is part of PHP-gettext.
 
  PHP-gettext is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  PHP-gettext is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with PHP-gettext; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
  */
 
  error_reporting(E_ALL | E_STRICT);
 
  // define constants
  define('PROJECT_DIR', realpath('./'));
  define('LOCALE_DIR', PROJECT_DIR .'/locale');
  define('DEFAULT_LOCALE', 'en_US');
 
  require_once('../gettext.inc');
 
  $supported_locales = array('en_US', 'sr_CS', 'de_CH');
  $encoding = 'UTF-8';
 
  $locale = (isset($_GET['lang']))? $_GET['lang'] : DEFAULT_LOCALE;
 
  // gettext setup
  T_setlocale(LC_MESSAGES, $locale);
  // Set the text domain as 'messages'
  $domain = 'messages';
  T_bindtextdomain($domain, LOCALE_DIR);
  T_bind_textdomain_codeset($domain, $encoding);
  T_textdomain($domain);
 
  header("Content-type: text/html; charset=$encoding");
  ?>
  <html>
  <head>
  <title>PHP-gettext fallback example</title>
  </head>
  <body>
  <h1>PHP-gettext as a fallback solution</h1>
  <p>Example showing how to use PHP-gettext as a fallback solution if the native gettext library is not available or the system does not support the requested locale.</p>
 
  <?php
  print "<p>";
  foreach($supported_locales as $l) {
  print "[<a href=\"?lang=$l\">$l</a>] ";
  }
  print "</p>\n";
 
  if (!locale_emulation()) {
  print "<p>locale '$locale' is supported by your system, using native gettext implementation.</p>\n";
  }
  else {
  print "<p>locale '$locale' is <strong>not</strong> supported on your system, using custom gettext implementation.</p>\n";
  }
  ?>
 
  <hr />
 
  <?php
  // using PHP-gettext
  print "<pre>";
  print T_("This is how the story goes.\n\n");
  for ($number=6; $number>=0; $number--) {
  print sprintf( T_ngettext("%d pig went to the market\n",
  "%d pigs went to the market\n", $number),
  $number );
  }
  print "</pre>\n";
  ?>
 
  <hr />
  <p>&laquo; <a href="./">back</a></p>
  </body>
  </html>
 
  #!/bin/sh
  TEMPLATE=pigs.pot
  xgettext -kT_ngettext:1,2 -kT_ -L PHP -o $TEMPLATE pigs_dropin.php
  if [ "x$1" = "x-p" ]; then
  msgfmt --statistics $TEMPLATE
  else
  if [ -f $1.po ]; then
  msgmerge -o .tmp$1.po $1.po $TEMPLATE
  mv .tmp$1.po $1.po
  msgfmt --statistics $1.po
  else
  echo "Usage: $0 [-p|<basename>]"
  fi
  fi
 
  <?php
  /*
  Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
  Copyright (c) 2009 Danilo Segan <danilo@kvota.net>
 
  Drop in replacement for native gettext.
 
  This file is part of PHP-gettext.
 
  PHP-gettext is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  PHP-gettext is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with PHP-gettext; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
  */
  /*
  LC_CTYPE 0
  LC_NUMERIC 1
  LC_TIME 2
  LC_COLLATE 3
  LC_MONETARY 4
  LC_MESSAGES 5
  LC_ALL 6
  */
 
 
  // LC_MESSAGES is not available if php-gettext is not loaded
  // while the other constants are already available from session extension.
  if (!defined('LC_MESSAGES')) {
  define('LC_MESSAGES', 5);
  }
 
  require('streams.php');
  require('gettext.php');
 
 
  // Variables
 
  global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
  $text_domains = array();
  $default_domain = 'messages';
  $LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
  $EMULATEGETTEXT = 0;
  $CURRENTLOCALE = '';
 
  /* Class to hold a single domain included in $text_domains. */
  class domain {
  var $l10n;
  var $path;
  var $codeset;
  }
 
  // Utility functions
 
  /**
  * Return a list of locales to try for any POSIX-style locale specification.
  */
  function get_list_of_locales($locale) {
  /* Figure out all possible locale names and start with the most
  * specific ones. I.e. for sr_CS.UTF-8@latin, look through all of
  * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr.
  */
  $locale_names = array();
  $lang = NULL;
  $country = NULL;
  $charset = NULL;
  $modifier = NULL;
  if ($locale) {
  if (preg_match("/^(?P<lang>[a-z]{2,3})" // language code
  ."(?:_(?P<country>[A-Z]{2}))?" // country code
  ."(?:\.(?P<charset>[-A-Za-z0-9_]+))?" // charset
  ."(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/", // @ modifier
  $locale, $matches)) {
 
  if (isset($matches["lang"])) $lang = $matches["lang"];
  if (isset($matches["country"])) $country = $matches["country"];
  if (isset($matches["charset"])) $charset = $matches["charset"];
  if (isset($matches["modifier"])) $modifier = $matches["modifier"];
 
  if ($modifier) {
  if ($country) {
  if ($charset)
  array_push($locale_names, "${lang}_$country.$charset@$modifier");
  array_push($locale_names, "${lang}_$country@$modifier");
  } elseif ($charset)
  array_push($locale_names, "${lang}.$charset@$modifier");
  array_push($locale_names, "$lang@$modifier");
  }
  if ($country) {
  if ($charset)
  array_push($locale_names, "${lang}_$country.$charset");
  array_push($locale_names, "${lang}_$country");
  } elseif ($charset)
  array_push($locale_names, "${lang}.$charset");
  array_push($locale_names, $lang);
  }
 
  // If the locale name doesn't match POSIX style, just include it as-is.
  if (!in_array($locale, $locale_names))
  array_push($locale_names, $locale);
  }
  return $locale_names;
  }
 
  /**
  * Utility function to get a StreamReader for the given text domain.
  */
  function _get_reader($domain=null, $category=5, $enable_cache=true) {
  global $text_domains, $default_domain, $LC_CATEGORIES;
  if (!isset($domain)) $domain = $default_domain;
  if (!isset($text_domains[$domain]->l10n)) {
  // get the current locale
  $locale = _setlocale(LC_MESSAGES, 0);
  $bound_path = isset($text_domains[$domain]->path) ?
  $text_domains[$domain]->path : './';
  $subpath = $LC_CATEGORIES[$category] ."/$domain.mo";
 
  $locale_names = get_list_of_locales($locale);
  $input = null;
  foreach ($locale_names as $locale) {
  $full_path = $bound_path . $locale . "/" . $subpath;
  if (file_exists($full_path)) {
  $input = new FileReader($full_path);
  break;
  }
  }
 
  if (!array_key_exists($domain, $text_domains)) {
  // Initialize an empty domain object.
  $text_domains[$domain] = new domain();
  }
  $text_domains[$domain]->l10n = new gettext_reader($input,
  $enable_cache);
  }
  return $text_domains[$domain]->l10n;
  }
 
  /**
  * Returns whether we are using our emulated gettext API or PHP built-in one.
  */
  function locale_emulation() {
  global $EMULATEGETTEXT;
  return $EMULATEGETTEXT;
  }
 
  /**
  * Checks if the current locale is supported on this system.
  */
  function _check_locale_and_function($function=false) {
  global $EMULATEGETTEXT;
  if ($function and !function_exists($function))
  return false;
  return !$EMULATEGETTEXT;
  }
 
  /**
  * Get the codeset for the given domain.
  */
  function _get_codeset($domain=null) {
  global $text_domains, $default_domain, $LC_CATEGORIES;
  if (!isset($domain)) $domain = $default_domain;
  return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
  }
 
  /**
  * Convert the given string to the encoding set by bind_textdomain_codeset.
  */
  function _encode($text) {
  $source_encoding = mb_detect_encoding($text);
  $target_encoding = _get_codeset();
  if ($source_encoding != $target_encoding) {
  return mb_convert_encoding($text, $target_encoding, $source_encoding);
  }
  else {
  return $text;
  }
  }
 
 
  // Custom implementation of the standard gettext related functions
 
  /**
  * Returns passed in $locale, or environment variable $LANG if $locale == ''.
  */
  function _get_default_locale($locale) {
  if ($locale == '') // emulate variable support
  return getenv('LANG');
  else
  return $locale;
  }
 
  /**
  * Sets a requested locale, if needed emulates it.
  */
  function _setlocale($category, $locale) {
  global $CURRENTLOCALE, $EMULATEGETTEXT;
  if ($locale === 0) { // use === to differentiate between string "0"
  if ($CURRENTLOCALE != '')
  return $CURRENTLOCALE;
  else
  // obey LANG variable, maybe extend to support all of LC_* vars
  // even if we tried to read locale without setting it first
  return _setlocale($category, $CURRENTLOCALE);
  } else {
  if (function_exists('setlocale')) {
  $ret = setlocale($category, $locale);
  if (($locale == '' and !$ret) or // failed setting it by env
  ($locale != '' and $ret != $locale)) { // failed setting it
  // Failed setting it according to environment.
  $CURRENTLOCALE = _get_default_locale($locale);
  $EMULATEGETTEXT = 1;
  } else {
  $CURRENTLOCALE = $ret;
  $EMULATEGETTEXT = 0;
  }
  } else {
  // No function setlocale(), emulate it all.
  $CURRENTLOCALE = _get_default_locale($locale);
  $EMULATEGETTEXT = 1;
  }
  // Allow locale to be changed on the go for one translation domain.
  global $text_domains, $default_domain;
  unset($text_domains[$default_domain]->l10n);
  return $CURRENTLOCALE;
  }
  }
 
  /**
  * Sets the path for a domain.
  */
  function _bindtextdomain($domain, $path) {
  global $text_domains;
  // ensure $path ends with a slash ('/' should work for both, but lets still play nice)
  if (substr(php_uname(), 0, 7) == "Windows") {
  if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/')
  $path .= '\\';
  } else {
  if ($path[strlen($path)-1] != '/')
  $path .= '/';
  }
  if (!array_key_exists($domain, $text_domains)) {
  // Initialize an empty domain object.
  $text_domains[$domain] = new domain();
  }
  $text_domains[$domain]->path = $path;
  }
 
  /**
  * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
  */
  function _bind_textdomain_codeset($domain, $codeset) {
  global $text_domains;
  $text_domains[$domain]->codeset = $codeset;
  }
 
  /**
  * Sets the default domain.
  */
  function _textdomain($domain) {
  global $default_domain;
  $default_domain = $domain;
  }
 
  /**
  * Lookup a message in the current domain.
  */
  function _gettext($msgid) {
  $l10n = _get_reader();
  return _encode($l10n->translate($msgid));
  }
 
  /**
  * Alias for gettext.
  */
  function __($msgid) {
  return _gettext($msgid);
  }
 
  /**
  * Plural version of gettext.
  */
  function _ngettext($single, $plural, $number) {
  $l10n = _get_reader();
  return _encode($l10n->ngettext($single, $plural, $number));
  }
 
  /**
  * Override the current domain.
  */
  function _dgettext($domain, $msgid) {
  $l10n = _get_reader($domain);
  return _encode($l10n->translate($msgid));
  }
 
  /**
  * Plural version of dgettext.
  */
  function _dngettext($domain, $single, $plural, $number) {
  $l10n = _get_reader($domain);
  return _encode($l10n->ngettext($single, $plural, $number));
  }
 
  /**
  * Overrides the domain and category for a single lookup.
  */
  function _dcgettext($domain, $msgid, $category) {
  $l10n = _get_reader($domain, $category);
  return _encode($l10n->translate($msgid));
  }
  /**
  * Plural version of dcgettext.
  */
  function _dcngettext($domain, $single, $plural, $number, $category) {
  $l10n = _get_reader($domain, $category);
  return _encode($l10n->ngettext($single, $plural, $number));
  }
 
  /**
  * Context version of gettext.
  */
  function _pgettext($context, $msgid) {
  $l10n = _get_reader();
  return _encode($l10n->pgettext($context, $msgid));
  }
 
  /**
  * Override the current domain in a context gettext call.
  */
  function _dpgettext($domain, $context, $msgid) {
  $l10n = _get_reader($domain);
  return _encode($l10n->pgettext($context, $msgid));
  }
 
  /**
  * Overrides the domain and category for a single context-based lookup.
  */
  function _dcpgettext($domain, $context, $msgid, $category) {
  $l10n = _get_reader($domain, $category);
  return _encode($l10n->pgettext($context, $msgid));
  }
 
  /**
  * Context version of ngettext.
  */
  function _npgettext($context, $singular, $plural) {
  $l10n = _get_reader();
  return _encode($l10n->npgettext($context, $singular, $plural));
  }
 
  /**
  * Override the current domain in a context ngettext call.
  */
  function _dnpgettext($domain, $context, $singular, $plural) {
  $l10n = _get_reader($domain);
  return _encode($l10n->npgettext($context, $singular, $plural));
  }
 
  /**
  * Overrides the domain and category for a plural context-based lookup.
  */
  function _dcnpgettext($domain, $context, $singular, $plural, $category) {
  $l10n = _get_reader($domain, $category);
  return _encode($l10n->npgettext($context, $singular, $plural));
  }
 
 
 
  // Wrappers to use if the standard gettext functions are available,
  // but the current locale is not supported by the system.
  // Use the standard impl if the current locale is supported, use the
  // custom impl otherwise.
 
  function T_setlocale($category, $locale) {
  return _setlocale($category, $locale);
  }
 
  function T_bindtextdomain($domain, $path) {
  if (_check_locale_and_function()) return bindtextdomain($domain, $path);
  else return _bindtextdomain($domain, $path);
  }
  function T_bind_textdomain_codeset($domain, $codeset) {
  // bind_textdomain_codeset is available only in PHP 4.2.0+
  if (_check_locale_and_function('bind_textdomain_codeset'))
  return bind_textdomain_codeset($domain, $codeset);
  else return _bind_textdomain_codeset($domain, $codeset);
  }
  function T_textdomain($domain) {
  if (_check_locale_and_function()) return textdomain($domain);
  else return _textdomain($domain);
  }
  function T_gettext($msgid) {
  if (_check_locale_and_function()) return gettext($msgid);
  else return _gettext($msgid);
  }
  function T_($msgid) {
  if (_check_locale_and_function()) return _($msgid);
  return __($msgid);
  }
  function T_ngettext($single, $plural, $number) {
  if (_check_locale_and_function())
  return ngettext($single, $plural, $number);
  else return _ngettext($single, $plural, $number);
  }
  function T_dgettext($domain, $msgid) {
  if (_check_locale_and_function()) return dgettext($domain, $msgid);
  else return _dgettext($domain, $msgid);
  }
  function T_dngettext($domain, $single, $plural, $number) {
  if (_check_locale_and_function())
  return dngettext($domain, $single, $plural, $number);
  else return _dngettext($domain, $single, $plural, $number);
  }
  function T_dcgettext($domain, $msgid, $category) {
  if (_check_locale_and_function())
  return dcgettext($domain, $msgid, $category);
  else return _dcgettext($domain, $msgid, $category);
  }
  function T_dcngettext($domain, $single, $plural, $number, $category) {
  if (_check_locale_and_function())
  return dcngettext($domain, $single, $plural, $number, $category);
  else return _dcngettext($domain, $single, $plural, $number, $category);
  }
 
  function T_pgettext($context, $msgid) {
  if (_check_locale_and_function('pgettext'))
  return pgettext($context, $msgid);
  else
  return _pgettext($context, $msgid);
  }
 
  function T_dpgettext($domain, $context, $msgid) {
  if (_check_locale_and_function('dpgettext'))
  return dpgettext($domain, $context, $msgid);
  else
  return _dpgettext($domain, $context, $msgid);
  }
 
  function T_dcpgettext($domain, $context, $msgid, $category) {
  if (_check_locale_and_function('dcpgettext'))
  return dcpgettext($domain, $context, $msgid, $category);
  else
  return _dcpgettext($domain, $context, $msgid, $category);
  }
 
  function T_npgettext($context, $singular, $plural) {
  if (_check_locale_and_function('npgettext'))
  return npgettext($context, $single, $plural, $number);
  else
  return _npgettext($context, $single, $plural, $number);
  }
 
  function T_dnpgettext($domain, $context, $singular, $plural) {
  if (_check_locale_and_function('dnpgettext'))
  return dnpgettext($domain, $context, $single, $plural, $number);
  else
  return _dnpgettext($domain, $context, $single, $plural, $number);
  }
 
  function T_dcnpgettext($domain, $context, $singular, $plural, $category) {
  if (_check_locale_and_function('dcnpgettext'))
  return dcnpgettext($domain, $context, $single,
  $plural, $number, $category);
  else
  return _dcnpgettext($domain, $context, $single,
  $plural, $number, $category);
  }
 
 
 
  // Wrappers used as a drop in replacement for the standard gettext functions
 
  if (!function_exists('gettext')) {
  function bindtextdomain($domain, $path) {
  return _bindtextdomain($domain, $path);
  }
  function bind_textdomain_codeset($domain, $codeset) {
  return _bind_textdomain_codeset($domain, $codeset);
  }
  function textdomain($domain) {
  return _textdomain($domain);
  }
  function gettext($msgid) {
  return _gettext($msgid);
  }
  function _($msgid) {
  return __($msgid);
  }
  function ngettext($single, $plural, $number) {
  return _ngettext($single, $plural, $number);
  }
  function dgettext($domain, $msgid) {
  return _dgettext($domain, $msgid);
  }
  function dngettext($domain, $single, $plural, $number) {
  return _dngettext($domain, $single, $plural, $number);
  }
  function dcgettext($domain, $msgid, $category) {
  return _dcgettext($domain, $msgid, $category);
  }
  function dcngettext($domain, $single, $plural, $number, $category) {
  return _dcngettext($domain, $single, $plural, $number, $category);
  }
  function pgettext($context, $msgid) {
  return _pgettext($context, $msgid);
  }
  function npgettext($context, $single, $plural, $number) {
  return _npgettext($context, $single, $plural, $number);
  }
  function dpgettext($domain, $context, $msgid) {
  return _dpgettext($domain, $context, $msgid);
  }
  function dnpgettext($domain, $context, $single, $plural, $number) {
  return _dnpgettext($domain, $context, $single, $plural, $number);
  }
  function dcpgettext($domain, $context, $msgid, $category) {
  return _dcpgettext($domain, $context, $msgid, $category);
  }
  function dcnpgettext($domain, $context, $single, $plural,
  $number, $category) {
  return _dcnpgettext($domain, $context, $single, $plural,
  $number, $category);
  }
  }
 
  ?>
 
  <?php
  /*
  Copyright (c) 2003, 2009 Danilo Segan <danilo@kvota.net>.
  Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
 
  This file is part of PHP-gettext.
 
  PHP-gettext is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  PHP-gettext is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with PHP-gettext; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
  */
 
  /**
  * Provides a simple gettext replacement that works independently from
  * the system's gettext abilities.
  * It can read MO files and use them for translating strings.
  * The files are passed to gettext_reader as a Stream (see streams.php)
  *
  * This version has the ability to cache all strings and translations to
  * speed up the string lookup.
  * While the cache is enabled by default, it can be switched off with the
  * second parameter in the constructor (e.g. whenusing very large MO files
  * that you don't want to keep in memory)
  */
  class gettext_reader {
  //public:
  var $error = 0; // public variable that holds error code (0 if no error)
 
  //private:
  var $BYTEORDER = 0; // 0: low endian, 1: big endian
  var $STREAM = NULL;
  var $short_circuit = false;
  var $enable_cache = false;
  var $originals = NULL; // offset of original table
  var $translations = NULL; // offset of translation table
  var $pluralheader = NULL; // cache header field for plural forms
  var $total = 0; // total string count
  var $table_originals = NULL; // table for original strings (offsets)
  var $table_translations = NULL; // table for translated strings (offsets)
  var $cache_translations = NULL; // original -> translation mapping
 
 
  /* Methods */
 
 
  /**
  * Reads a 32bit Integer from the Stream
  *
  * @access private
  * @return Integer from the Stream
  */
  function readint() {
  if ($this->BYTEORDER == 0) {
  // low endian
  $input=unpack('V', $this->STREAM->read(4));
  return array_shift($input);
  } else {
  // big endian
  $input=unpack('N', $this->STREAM->read(4));
  return array_shift($input);
  }
  }
 
  function read($bytes) {
  return $this->STREAM->read($bytes);
  }
 
  /**
  * Reads an array of Integers from the Stream
  *
  * @param int count How many elements should be read
  * @return Array of Integers
  */
  function readintarray($count) {
  if ($this->BYTEORDER == 0) {
  // low endian
  return unpack('V'.$count, $this->STREAM->read(4 * $count));
  } else {
  // big endian
  return unpack('N'.$count, $this->STREAM->read(4 * $count));
  }
  }
 
  /**
  * Constructor
  *
  * @param object Reader the StreamReader object
  * @param boolean enable_cache Enable or disable caching of strings (default on)
  */
  function gettext_reader($Reader, $enable_cache = true) {
  // If there isn't a StreamReader, turn on short circuit mode.
  if (! $Reader || isset($Reader->error) ) {
  $this->short_circuit = true;
  return;
  }
 
  // Caching can be turned off
  $this->enable_cache = $enable_cache;
 
  $MAGIC1 = "\x95\x04\x12\xde";
  $MAGIC2 = "\xde\x12\x04\x95";
 
  $this->STREAM = $Reader;
  $magic = $this->read(4);
  if ($magic == $MAGIC1) {
  $this->BYTEORDER = 1;
  } elseif ($magic == $MAGIC2) {
  $this->BYTEORDER = 0;
  } else {
  $this->error = 1; // not MO file
  return false;
  }
 
  // FIXME: Do we care about revision? We should.
  $revision = $this->readint();
 
  $this->total = $this->readint();
  $this->originals = $this->readint();
  $this->translations = $this->readint();
  }
 
  /**
  * Loads the translation tables from the MO file into the cache
  * If caching is enabled, also loads all strings into a cache
  * to speed up translation lookups
  *
  * @access private
  */
  function load_tables() {
  if (is_array($this->cache_translations) &&
  is_array($this->table_originals) &&
  is_array($this->table_translations))
  return;
 
  /* get original and translations tables */
  if (!is_array($this->table_originals)) {
  $this->STREAM->seekto($this->originals);
  $this->table_originals = $this->readintarray($this->total * 2);
  }
  if (!is_array($this->table_translations)) {
  $this->STREAM->seekto($this->translations);
  $this->table_translations = $this->readintarray($this->total * 2);
  }
 
  if ($this->enable_cache) {
  $this->cache_translations = array ();
  /* read all strings in the cache */
  for ($i = 0; $i < $this->total; $i++) {
  $this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
  $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
  $this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
  $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
  $this->cache_translations[$original] = $translation;
  }
  }
  }
 
  /**
  * Returns a string from the "originals" table
  *
  * @access private
  * @param int num Offset number of original string
  * @return string Requested string if found, otherwise ''
  */
  function get_original_string($num) {
  $length = $this->table_originals[$num * 2 + 1];
  $offset = $this->table_originals[$num * 2 + 2];
  if (! $length)
  return '';
  $this->STREAM->seekto($offset);
  $data = $this->STREAM->read($length);
  return (string)$data;
  }
 
  /**
  * Returns a string from the "translations" table
  *
  * @access private
  * @param int num Offset number of original string
  * @return string Requested string if found, otherwise ''
  */
  function get_translation_string($num) {
  $length = $this->table_translations[$num * 2 + 1];
  $offset = $this->table_translations[$num * 2 + 2];
  if (! $length)
  return '';
  $this->STREAM->seekto($offset);
  $data = $this->STREAM->read($length);
  return (string)$data;
  }
 
  /**
  * Binary search for string
  *
  * @access private
  * @param string string
  * @param int start (internally used in recursive function)
  * @param int end (internally used in recursive function)
  * @return int string number (offset in originals table)
  */
  function find_string($string, $start = -1, $end = -1) {
  if (($start == -1) or ($end == -1)) {
  // find_string is called with only one parameter, set start end end
  $start = 0;
  $end = $this->total;
  }
  if (abs($start - $end) <= 1) {
  // We're done, now we either found the string, or it doesn't exist
  $txt = $this->get_original_string($start);
  if ($string == $txt)
  return $start;
  else
  return -1;
  } else if ($start > $end) {
  // start > end -> turn around and start over
  return $this->find_string($string, $end, $start);
  } else {
  // Divide table in two parts
  $half = (int)(($start + $end) / 2);
  $cmp = strcmp($string, $this->get_original_string($half));
  if ($cmp == 0)
  // string is exactly in the middle => return it
  return $half;
  else if ($cmp < 0)
  // The string is in the upper half
  return $this->find_string($string, $start, $half);
  else
  // The string is in the lower half
  return $this->find_string($string, $half, $end);
  }
  }
 
  /**
  * Translates a string
  *
  * @access public
  * @param string string to be translated
  * @return string translated string (or original, if not found)
  */
  function translate($string) {
  if ($this->short_circuit)
  return $string;
  $this->load_tables();
 
  if ($this->enable_cache) {
  // Caching enabled, get translated string from cache
  if (array_key_exists($string, $this->cache_translations))
  return $this->cache_translations[$string];
  else
  return $string;
  } else {
  // Caching not enabled, try to find string
  $num = $this->find_string($string);
  if ($num == -1)
  return $string;
  else
  return $this->get_translation_string($num);
  }
  }
 
  /**
  * Sanitize plural form expression for use in PHP eval call.
  *
  * @access private
  * @return string sanitized plural form expression
  */
  function sanitize_plural_expression($expr) {
  // Get rid of disallowed characters.
  $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
 
  // Add parenthesis for tertiary '?' operator.
  $expr .= ';';
  $res = '';
  $p = 0;
  for ($i = 0; $i < strlen($expr); $i++) {
  $ch = $expr[$i];
  switch ($ch) {
  case '?':
  $res .= ' ? (';
  $p++;
  break;
  case ':':
  $res .= ') : (';
  break;
  case ';':
  $res .= str_repeat( ')', $p) . ';';
  $p = 0;
  break;
  default:
  $res .= $ch;
  }
  }
  return $res;
  }
 
  /**
  * Parse full PO header and extract only plural forms line.
  *
  * @access private
  * @return string verbatim plural form header field
  */
  function extract_plural_forms_header_from_po_header($header) {
  if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs))
  $expr = $regs[2];
  else
  $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
  return $expr;
  }
 
  /**
  * Get possible plural forms from MO header
  *
  * @access private
  * @return string plural form header
  */
  function get_plural_forms() {
  // lets assume message number 0 is header
  // this is true, right?
  $this->load_tables();
 
  // cache header field for plural forms
  if (! is_string($this->pluralheader)) {
  if ($this->enable_cache) {
  $header = $this->cache_translations[""];
  } else {
  $header = $this->get_translation_string(0);
  }
  $expr = $this->extract_plural_forms_header_from_po_header($header);
  $this->pluralheader = $this->sanitize_plural_expression($expr);
  }
  return $this->pluralheader;
  }
 
  /**
  * Detects which plural form to take
  *
  * @access private
  * @param n count
  * @return int array index of the right plural form
  */
  function select_string($n) {
  $string = $this->get_plural_forms();
  $string = str_replace('nplurals',"\$total",$string);
  $string = str_replace("n",$n,$string);
  $string = str_replace('plural',"\$plural",$string);
 
  $total = 0;
  $plural = 0;
 
  eval("$string");
  if ($plural >= $total) $plural = $total - 1;
  return $plural;
  }
 
  /**
  * Plural version of gettext
  *
  * @access public
  * @param string single
  * @param string plural
  * @param string number
  * @return translated plural form
  */
  function ngettext($single, $plural, $number) {
  if ($this->short_circuit) {
  if ($number != 1)
  return $plural;
  else
  return $single;
  }
 
  // find out the appropriate form
  $select = $this->select_string($number);
 
  // this should contains all strings separated by NULLs
  $key = $single . chr(0) . $plural;
 
 
  if ($this->enable_cache) {
  if (! array_key_exists($key, $this->cache_translations)) {
  return ($number != 1) ? $plural : $single;
  } else {
  $result = $this->cache_translations[$key];
  $list = explode(chr(0), $result);
  return $list[$select];
  }
  } else {
  $num = $this->find_string($key);
  if ($num == -1) {
  return ($number != 1) ? $plural : $single;
  } else {
  $result = $this->get_translation_string($num);
  $list = explode(chr(0), $result);
  return $list[$select];
  }
  }
  }
 
  function pgettext($context, $msgid) {
  $key = $context . chr(4) . $msgid;
  return $this->translate($key);
  }
 
  function npgettext($context, $singular, $plural, $number) {
  $singular = $context . chr(4) . $singular;
  return $this->ngettext($singular, $plural, $number);
  }
  }
 
  ?>
 
  <?php
  /*
  Copyright (c) 2003, 2005, 2006, 2009 Danilo Segan <danilo@kvota.net>.
 
  This file is part of PHP-gettext.
 
  PHP-gettext is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  PHP-gettext is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License
  along with PHP-gettext; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
  */
 
 
  // Simple class to wrap file streams, string streams, etc.
  // seek is essential, and it should be byte stream
  class StreamReader {
  // should return a string [FIXME: perhaps return array of bytes?]
  function read($bytes) {
  return false;
  }
 
  // should return new position
  function seekto($position) {
  return false;
  }
 
  // returns current position
  function currentpos() {
  return false;
  }
 
  // returns length of entire stream (limit for seekto()s)
  function length() {
  return false;
  }
  };
 
  class StringReader {
  var $_pos;
  var $_str;
 
  function StringReader($str='') {
  $this->_str = $str;
  $this->_pos = 0;
  }
 
  function read($bytes) {
  $data = substr($this->_str, $this->_pos, $bytes);
  $this->_pos += $bytes;
  if (strlen($this->_str)<$this->_pos)
  $this->_pos = strlen($this->_str);
 
  return $data;
  }
 
  function seekto($pos) {
  $this->_pos = $pos;
  if (strlen($this->_str)<$this->_pos)
  $this->_pos = strlen($this->_str);
  return $this->_pos;
  }
 
  function currentpos() {
  return $this->_pos;
  }
 
  function length() {
  return strlen($this->_str);
  }
 
  };
 
 
  class FileReader {
  var $_pos;
  var $_fd;
  var $_length;
 
  function FileReader($filename) {
  if (file_exists($filename)) {
 
  $this->_length=filesize($filename);
  $this->_pos = 0;
  $this->_fd = fopen($filename,'rb');
  if (!$this->_fd) {
  $this->error = 3; // Cannot read file, probably permissions
  return false;
  }
  } else {
  $this->error = 2; // File doesn't exist
  return false;
  }
  }
 
  function read($bytes) {
  if ($bytes) {
  fseek($this->_fd, $this->_pos);
 
  // PHP 5.1.1 does not read more than 8192 bytes in one fread()
  // the discussions at PHP Bugs suggest it's the intended behaviour
  $data = '';
  while ($bytes > 0) {
  $chunk = fread($this->_fd, $bytes);
  $data .= $chunk;
  $bytes -= strlen($chunk);
  }
  $this->_pos = ftell($this->_fd);
 
  return $data;
  } else return '';
  }
 
  function seekto($pos) {
  fseek($this->_fd, $pos);
  $this->_pos = ftell($this->_fd);
  return $this->_pos;
  }
 
  function currentpos() {
  return $this->_pos;
  }
 
  function length() {
  return $this->_length;
  }
 
  function close() {
  fclose($this->_fd);
  }
 
  };
 
  // Preloads entire file in memory first, then creates a StringReader
  // over it (it assumes knowledge of StringReader internals)
  class CachedFileReader extends StringReader {
  function CachedFileReader($filename) {
  if (file_exists($filename)) {
 
  $length=filesize($filename);
  $fd = fopen($filename,'rb');
 
  if (!$fd) {
  $this->error = 3; // Cannot read file, probably permissions
  return false;
  }
  $this->_str = fread($fd, $length);
  fclose($fd);
 
  } else {
  $this->error = 2; // File doesn't exist
  return false;
  }
  }
  };
 
 
  ?>
 
  <?php
  require_once('PHPUnit/Framework.php');
  require_once('gettext.inc');
 
  class LocaleTest extends PHPUnit_Framework_TestCase
  {
  public function test_setlocale()
  {
  // _setlocale defaults to a locale name from environment variable LANG.
  putenv("LANG=sr_RS");
  $this->assertEquals('sr_RS', _setlocale(LC_MESSAGES, 0));
 
  // For an existing locale, it never needs emulation.
  putenv("LANG=C");
  _setlocale(LC_MESSAGES, "");
  $this->assertEquals(0, locale_emulation());
 
  // If we set it to a non-existent locale, it still works, but uses
  // emulation.
  _setlocale(LC_MESSAGES, "xxx_XXX");
  $this->assertEquals('xxx_XXX', _setlocale(LC_MESSAGES, 0));
  $this->assertEquals(1, locale_emulation());
  }
 
  public function test_get_list_of_locales()
  {
  // For a locale containing country code, we prefer
  // full locale name, but if that's not found, fall back
  // to the language only locale name.
  $this->assertEquals(array("sr_RS", "sr"),
  get_list_of_locales("sr_RS"));
 
  // If language code is used, it's the only thing returned.
  $this->assertEquals(array("sr"),
  get_list_of_locales("sr"));
 
  // There is support for language and charset only.
  $this->assertEquals(array("sr.UTF-8", "sr"),
  get_list_of_locales("sr.UTF-8"));
 
  // It can also split out character set from the full locale name.
  $this->assertEquals(array("sr_RS.UTF-8", "sr_RS", "sr"),
  get_list_of_locales("sr_RS.UTF-8"));
 
  // There is support for @modifier in locale names as well.
  $this->assertEquals(array("sr_RS.UTF-8@latin", "sr_RS@latin", "sr@latin",
  "sr_RS.UTF-8", "sr_RS", "sr"),
  get_list_of_locales("sr_RS.UTF-8@latin"));
 
  // We can pass in only language and modifier.
  $this->assertEquals(array("sr@latin", "sr"),
  get_list_of_locales("sr@latin"));
 
 
  // If locale name is not following the regular POSIX pattern,
  // it's used verbatim.
  $this->assertEquals(array("something"),
  get_list_of_locales("something"));
 
  // Passing in an empty string returns an empty array.
  $this->assertEquals(array(),
  get_list_of_locales(""));
  }
  }
 
  ?>
 
  <?php
  require_once('PHPUnit/Framework.php');
  //require_once('gettext.php');
 
  class ParsingTest extends PHPUnit_Framework_TestCase
  {
  public function test_extract_plural_forms_header_from_po_header()
  {
  $parser = new gettext_reader(NULL);
  // It defaults to a "Western-style" plural header.
  $this->assertEquals(
  'nplurals=2; plural=n == 1 ? 0 : 1;',
  $parser->extract_plural_forms_header_from_po_header(""));
 
  // Extracting it from the middle of the header works.
  $this->assertEquals(
  'nplurals=1; plural=0;',
  $parser->extract_plural_forms_header_from_po_header(
  "Content-type: text/html; charset=UTF-8\n"
  ."Plural-Forms: nplurals=1; plural=0;\n"
  ."Last-Translator: nobody\n"
  ));
 
  // It's also case-insensitive.
  $this->assertEquals(
  'nplurals=1; plural=0;',
  $parser->extract_plural_forms_header_from_po_header(
  "PLURAL-forms: nplurals=1; plural=0;\n"
  ));
 
  // It falls back to default if it's not on a separate line.
  $this->assertEquals(
  'nplurals=2; plural=n == 1 ? 0 : 1;',
  $parser->extract_plural_forms_header_from_po_header(
  "Content-type: text/html; charset=UTF-8" // note the missing \n here
  ."Plural-Forms: nplurals=1; plural=0;\n"
  ."Last-Translator: nobody\n"
  ));
 
  }
 
  }
  ?>
 
  GNU LESSER GENERAL PUBLIC LICENSE
  Version 2.1, February 1999
 
  Copyright (C) 1991, 1999 Free Software Foundation, Inc.
  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
  [This is the first released version of the Lesser GPL. It also counts
  as the successor of the GNU Library Public License, version 2, hence
  the version number 2.1.]
 
  Preamble
 
  The licenses for most software are designed to take away your
  freedom to share and change it. By contrast, the GNU General Public
  Licenses are intended to guarantee your freedom to share and change
  free software--to make sure the software is free for all its users.
 
  This license, the Lesser General Public License, applies to some
  specially designated software packages--typically libraries--of the
  Free Software Foundation and other authors who decide to use it. You
  can use it too, but we suggest you first think carefully about whether
  this license or the ordinary General Public License is the better
  strategy to use in any particular case, based on the explanations below.
 
  When we speak of free software, we are referring to freedom of use,
  not price. Our General Public Licenses are designed to make sure that
  you have the freedom to distribute copies of free software (and charge
  for this service if you wish); that you receive source code or can get
  it if you want it; that you can change the software and use pieces of
  it in new free programs; and that you are informed that you can do
  these things.
 
  To protect your rights, we need to make restrictions that forbid
  distributors to deny you these rights or to ask you to surrender these
  rights. These restrictions translate to certain responsibilities for
  you if you distribute copies of the library or if you modify it.
 
  For example, if you distribute copies of the library, whether gratis
  or for a fee, you must give the recipients all the rights that we gave
  you. You must make sure that they, too, receive or can get the source
  code. If you link other code with the library, you must provide
  complete object files to the recipients, so that they can relink them
  with the library after making changes to the library and recompiling
  it. And you must show them these terms so they know their rights.
 
  We protect your rights with a two-step method: (1) we copyright the
  library, and (2) we offer you this license, which gives you legal
  permission to copy, distribute and/or modify the library.
 
  To protect each distributor, we want to make it very clear that
  there is no warranty for the free library. Also, if the library is
  modified by someone else and passed on, the recipients should know
  that what they have is not the original version, so that the original
  author's reputation will not be affected by problems that might be
  introduced by others.
 
  Finally, software patents pose a constant threat to the existence of
  any free program. We wish to make sure that a company cannot
  effectively restrict the users of a free program by obtaining a
  restrictive license from a patent holder. Therefore, we insist that
  any patent license obtained for a version of the library must be
  consistent with the full freedom of use specified in this license.
 
  Most GNU software, including some libraries, is covered by the
  ordinary GNU General Public License. This license, the GNU Lesser
  General Public License, applies to certain designated libraries, and
  is quite different from the ordinary General Public License. We use
  this license for certain libraries in order to permit linking those
  libraries into non-free programs.
 
  When a program is linked with a library, whether statically or using
  a shared library, the combination of the two is legally speaking a
  combined work, a derivative of the original library. The ordinary
  General Public License therefore permits such linking only if the
  entire combination fits its criteria of freedom. The Lesser General
  Public License permits more lax criteria for linking other code with
  the library.
 
  We call this license the "Lesser" General Public License because it
  does Less to protect the user's freedom than the ordinary General
  Public License. It also provides other free software developers Less
  of an advantage over competing non-free programs. These disadvantages
  are the reason we use the ordinary General Public License for many
  libraries. However, the Lesser license provides advantages in certain
  special circumstances.
 
  For example, on rare occasions, there may be a special need to
  encourage the widest possible use of a certain library, so that it becomes
  a de-facto standard. To achieve this, non-free programs must be
  allowed to use the library. A more frequent case is that a free
  library does the same job as widely used non-free libraries. In this
  case, there is little to gain by limiting the free library to free
  software only, so we use the Lesser General Public License.
 
  In other cases, permission to use a particular library in non-free
  programs enables a greater number of people to use a large body of
  free software. For example, permission to use the GNU C Library in
  non-free programs enables many more people to use the whole GNU
  operating system, as well as its variant, the GNU/Linux operating
  system.
 
  Although the Lesser General Public License is Less protective of the
  users' freedom, it does ensure that the user of a program that is
  linked with the Library has the freedom and the wherewithal to run
  that program using a modified version of the Library.
 
  The precise terms and conditions for copying, distribution and
  modification follow. Pay close attention to the difference between a
  "work based on the library" and a "work that uses the library". The
  former contains code derived from the library, whereas the latter must
  be combined with the library in order to run.
 
  GNU LESSER GENERAL PUBLIC LICENSE
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
  0. This License Agreement applies to any software library or other
  program which contains a notice placed by the copyright holder or
  other authorized party saying it may be distributed under the terms of
  this Lesser General Public License (also called "this License").
  Each licensee is addressed as "you".
 
  A "library" means a collection of software functions and/or data
  prepared so as to be conveniently linked with application programs
  (which use some of those functions and data) to form executables.
 
  The "Library", below, refers to any such software library or work
  which has been distributed under these terms. A "work based on the
  Library" means either the Library or any derivative work under
  copyright law: that is to say, a work containing the Library or a
  portion of it, either verbatim or with modifications and/or translated
  straightforwardly into another language. (Hereinafter, translation is
  included without limitation in the term "modification".)
 
  "Source code" for a work means the preferred form of the work for
  making modifications to it. For a library, complete source code means
  all the source code for all modules it contains, plus any associated
  interface definition files, plus the scripts used to control compilation
  and installation of the library.
 
  Activities other than copying, distribution and modification are not
  covered by this License; they are outside its scope. The act of
  running a program using the Library is not restricted, and output from
  such a program is covered only if its contents constitute a work based
  on the Library (independent of the use of the Library in a tool for
  writing it). Whether that is true depends on what the Library does
  and what the program that uses the Library does.
 
  1. You may copy and distribute verbatim copies of the Library's
  complete source code as you receive it, in any medium, provided that
  you conspicuously and appropriately publish on each copy an
  appropriate copyright notice and disclaimer of warranty; keep intact
  all the notices that refer to this License and to the absence of any
  warranty; and distribute a copy of this License along with the
  Library.
 
  You may charge a fee for the physical act of transferring a copy,
  and you may at your option offer warranty protection in exchange for a
  fee.
 
  2. You may modify your copy or copies of the Library or any portion
  of it, thus forming a work based on the Library, and copy and
  distribute such modifications or work under the terms of Section 1
  above, provided that you also meet all of these conditions:
 
  a) The modified work must itself be a software library.
 
  b) You must cause the files modified to carry prominent notices
  stating that you changed the files and the date of any change.
 
  c) You must cause the whole of the work to be licensed at no
  charge to all third parties under the terms of this License.
 
  d) If a facility in the modified Library refers to a function or a
  table of data to be supplied by an application program that uses
  the facility, other than as an argument passed when the facility
  is invoked, then you must make a good faith effort to ensure that,
  in the event an application does not supply such function or
  table, the facility still operates, and performs whatever part of
  its purpose remains meaningful.
 
  (For example, a function in a library to compute square roots has
  a purpose that is entirely well-defined independent of the
  application. Therefore, Subsection 2d requires that any
  application-supplied function or table used by this function must
  be optional: if the application does not supply it, the square
  root function must still compute square roots.)
 
  These requirements apply to the modified work as a whole. If
  identifiable sections of that work are not derived from the Library,
  and can be reasonably considered independent and separate works in
  themselves, then this License, and its terms, do not apply to those
  sections when you distribute them as separate works. But when you
  distribute the same sections as part of a whole which is a work based
  on the Library, the distribution of the whole must be on the terms of
  this License, whose permissions for other licensees extend to the
  entire whole, and thus to each and every part regardless of who wrote
  it.
 
  Thus, it is not the intent of this section to claim rights or contest
  your rights to work written entirely by you; rather, the intent is to
  exercise the right to control the distribution of derivative or
  collective works based on the Library.
 
  In addition, mere aggregation of another work not based on the Library
  with the Library (or with a work based on the Library) on a volume of
  a storage or distribution medium does not bring the other work under
  the scope of this License.
 
  3. You may opt to apply the terms of the ordinary GNU General Public
  License instead of this License to a given copy of the Library. To do
  this, you must alter all the notices that refer to this License, so
  that they refer to the ordinary GNU General Public License, version 2,
  instead of to this License. (If a newer version than version 2 of the
  ordinary GNU General Public License has appeared, then you can specify
  that version instead if you wish.) Do not make any other change in
  these notices.
 
  Once this change is made in a given copy, it is irreversible for
  that copy, so the ordinary GNU General Public License applies to all
  subsequent copies and derivative works made from that copy.
 
  This option is useful when you wish to copy part of the code of
  the Library into a program that is not a library.
 
  4. You may copy and distribute the Library (or a portion or
  derivative of it, under Section 2) in object code or executable form
  under the terms of Sections 1 and 2 above provided that you accompany
  it with the complete corresponding machine-readable source code, which
  must be distributed under the terms of Sections 1 and 2 above on a
  medium customarily used for software interchange.
 
  If distribution of object code is made by offering access to copy
  from a designated place, then offering equivalent access to copy the
  source code from the same place satisfies the requirement to
  distribute the source code, even though third parties are not
  compelled to copy the source along with the object code.
 
  5. A program that contains no derivative of any portion of the
  Library, but is designed to work with the Library by being compiled or
  linked with it, is called a "work that uses the Library". Such a
  work, in isolation, is not a derivative work of the Library, and
  therefore falls outside the scope of this License.
 
  However, linking a "work that uses the Library" with the Library
  creates an executable that is a derivative of the Library (because it
  contains portions of the Library), rather than a "work that uses the
  library". The executable is therefore covered by this License.
  Section 6 states terms for distribution of such executables.
 
  When a "work that uses the Library" uses material from a header file
  that is part of the Library, the object code for the work may be a
  derivative work of the Library even though the source code is not.
  Whether this is true is especially significant if the work can be
  linked without the Library, or if the work is itself a library. The
  threshold for this to be true is not precisely defined by law.
 
  If such an object file uses only numerical parameters, data
  structure layouts and accessors, and small macros and small inline
  functions (ten lines or less in length), then the use of the object
  file is unrestricted, regardless of whether it is legally a derivative
  work. (Executables containing this object code plus portions of the
  Library will still fall under Section 6.)
 
  Otherwise, if the work is a derivative of the Library, you may
  distribute the object code for the work under the terms of Section 6.
  Any executables containing that work also fall under Section 6,
  whether or not they are linked directly with the Library itself.
 
  6. As an exception to the Sections above, you may also combine or
  link a "work that uses the Library" with the Library to produce a
  work containing portions of the Library, and distribute that work
  under terms of your choice, provided that the terms permit
  modification of the work for the customer's own use and reverse
  engineering for debugging such modifications.
 
  You must give prominent notice with each copy of the work that the
  Library is used in it and that the Library and its use are covered by
  this License. You must supply a copy of this License. If the work
  during execution displays copyright notices, you must include the
  copyright notice for the Library among them, as well as a reference
  directing the user to the copy of this License. Also, you must do one
  of these things:
 
  a) Accompany the work with the complete corresponding
  machine-readable source code for the Library including whatever
  changes were used in the work (which must be distributed under
  Sections 1 and 2 above); and, if the work is an executable linked
  with the Library, with the complete machine-readable "work that
  uses the Library", as object code and/or source code, so that the
  user can modify the Library and then relink to produce a modified
  executable containing the modified Library. (It is understood
  that the user who changes the contents of definitions files in the
  Library will not necessarily be able to recompile the application
  to use the modified definitions.)
 
  b) Use a suitable shared library mechanism for linking with the
  Library. A suitable mechanism is one that (1) uses at run time a
  copy of the library already present on the user's computer system,
  rather than copying library functions into the executable, and (2)
  will operate properly with a modified version of the library, if
  the user installs one, as long as the modified version is
  interface-compatible with the version that the work was made with.
 
  c) Accompany the work with a written offer, valid for at
  least three years, to give the same user the materials
  specified in Subsection 6a, above, for a charge no more
  than the cost of performing this distribution.
 
  d) If distribution of the work is made by offering access to copy
  from a designated place, offer equivalent access to copy the above
  specified materials from the same place.
 
  e) Verify that the user has already received a copy of these
  materials or that you have already sent this user a copy.
 
  For an executable, the required form of the "work that uses the
  Library" must include any data and utility programs needed for
  reproducing the executable from it. However, as a special exception,
  the materials to be distributed need not include anything that is
  normally distributed (in either source or binary form) with the major
  components (compiler, kernel, and so on) of the operating system on
  which the executable runs, unless that component itself accompanies
  the executable.
 
  It may happen that this requirement contradicts the license
  restrictions of other proprietary libraries that do not normally
  accompany the operating system. Such a contradiction means you cannot
  use both them and the Library together in an executable that you
  distribute.
 
  7. You may place library facilities that are a work based on the
  Library side-by-side in a single library together with other library
  facilities not covered by this License, and distribute such a combined
  library, provided that the separate distribution of the work based on
  the Library and of the other library facilities is otherwise
  permitted, and provided that you do these two things:
 
  a) Accompany the combined library with a copy of the same work
  based on the Library, uncombined with any other library
  facilities. This must be distributed under the terms of the
  Sections above.
 
  b) Give prominent notice with the combined library of the fact
  that part of it is a work based on the Library, and explaining
  where to find the accompanying uncombined form of the same work.
 
  8. You may not copy, modify, sublicense, link with, or distribute
  the Library except as expressly provided under this License. Any
  attempt otherwise to copy, modify, sublicense, link with, or
  distribute the Library is void, and will automatically terminate your
  rights under this License. However, parties who have received copies,
  or rights, from you under this License will not have their licenses
  terminated so long as such parties remain in full compliance.
 
  9. You are not required to accept this License, since you have not
  signed it. However, nothing else grants you permission to modify or
  distribute the Library or its derivative works. These actions are
  prohibited by law if you do not accept this License. Therefore, by
  modifying or distributing the Library (or any work based on the
  Library), you indicate your acceptance of this License to do so, and
  all its terms and conditions for copying, distributing or modifying
  the Library or works based on it.
 
  10. Each time you redistribute the Library (or any work based on the
  Library), the recipient automatically receives a license from the
  original licensor to copy, distribute, link with or modify the Library
  subject to these terms and conditions. You may not impose any further
  restrictions on the recipients' exercise of the rights granted herein.
  You are not responsible for enforcing compliance by third parties with
  this License.
 
  11. If, as a consequence of a court judgment or allegation of patent
  infringement or for any other reason (not limited to patent issues),
  conditions are imposed on you (whether by court order, agreement or
  otherwise) that contradict the conditions of this License, they do not
  excuse you from the conditions of this License. If you cannot
  distribute so as to satisfy simultaneously your obligations under this
  License and any other pertinent obligations, then as a consequence you
  may not distribute the Library at all. For example, if a patent
  license would not permit royalty-free redistribution of the Library by
  all those who receive copies directly or indirectly through you, then
  the only way you could satisfy both it and this License would be to
  refrain entirely from distribution of the Library.
 
  If any portion of this section is held invalid or unenforceable under any
  particular circumstance, the balance of the section is intended to apply,
  and the section as a whole is intended to apply in other circumstances.
 
  It is not the purpose of this section to induce you to infringe any
  patents or other property right claims or to contest validity of any
  such claims; this section has the sole purpose of protecting the
  integrity of the free software distribution system which is
  implemented by public license practices. Many people have made
  generous contributions to the wide range of software distributed
  through that system in reliance on consistent application of that
  system; it is up to the author/donor to decide if he or she is willing
  to distribute software through any other system and a licensee cannot
  impose that choice.
 
  This section is intended to make thoroughly clear what is believed to
  be a consequence of the rest of this License.
 
  12. If the distribution and/or use of the Library is restricted in
  certain countries either by patents or by copyrighted interfaces, the
  original copyright holder who places the Library under this License may add
  an explicit geographical distribution limitation excluding those countries,
  so that distribution is permitted only in or among countries not thus
  excluded. In such case, this License incorporates the limitation as if
  written in the body of this License.
 
  13. The Free Software Foundation may publish revised and/or new
  versions of the Lesser General Public License from time to time.
  Such new versions will be similar in spirit to the present version,
  but may differ in detail to address new problems or concerns.
 
  Each version is given a distinguishing version number. If the Library
  specifies a version number of this License which applies to it and
  "any later version", you have the option of following the terms and
  conditions either of that version or of any later version published by
  the Free Software Foundation. If the Library does not specify a
  license version number, you may choose any version ever published by
  the Free Software Foundation.
 
  14. If you wish to incorporate parts of the Library into other free
  programs whose distribution conditions are incompatible with these,
  write to the author to ask for permission. For software which is
  copyrighted by the Free Software Foundation, write to the Free
  Software Foundation; we sometimes make exceptions for this. Our
  decision will be guided by the two goals of preserving the free status
  of all derivatives of our free software and of promoting the sharing
  and reuse of software generally.
 
  NO WARRANTY
 
  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
  WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
  OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
  LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
  THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 
  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
  WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
  AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
  FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
  CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
  LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
  RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
  FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
  SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  DAMAGES.
 
  END OF TERMS AND CONDITIONS
 
  2005-07-27 Sagi Bashari <sagi@boom.org.il>
  * README:
  - Redone
 
  * smarty-gettext.php:
  - Renamed file to block.t.php
 
  * block.t.php:
  - Rename smarty_translate() to smarty_block_t()
  - Rename strarg() to smarty_gettext_strarg
  - Better comments, new installation method
  - url escaping method
 
  * tsmarty2c.php:
  - Use 'env php' as php bin path
  - Output file name along with ripped strings
  - Comments, wrapping
 
  2004-04-30 Sagi Bashari <sagi@boom.org.il>
 
  * README:
  - replace smarty_gettext with smarty-gettext
  - correct package name, project urls, add vrsion
 
  * tsmarty2.c:
  - check if file extension exists before checking if is in array (Florian Lanthaler <florian@phpbitch.net>)
  - correct package name, project urls, add version
 
  * smarty_gettext:
  - rename to smarty-gettext
  - correct package name, project urls, add version
 
  2004-03-01 Sagi Bashari <sagi@boom.org.il>
 
  * tsmarty2c.php:
  - added support for directories (originally by Uros Gruber <uros.gruber@vizija.si>)
  - fixed bug that prevented more than 1 block per line (reported by Eneko Lacunza <enlar@euskal.org>)
  - convert new line to \n in output string
 
  * smarty_gettext.php:
  - run nl2br() when escaping html
 
  $Id: README,v 1.4 2005/07/27 18:14:59 sagi Exp $
 
  ------------------------------------------------
  | smarty-gettext - Gettext support for Smarty |
  | |
  | Author: Sagi Bashari <sagi@boom.org.il> |
  | URL: http://smarty-gettext.sourceforge.net/ |
  ------------------------------------------------
 
  smarty-gettext provides gettext support for Smarty,
  the popular PHP templating engine (http://smarty.php.net/).
 
  This README assumes that you already know what is gettext and how to
  use it with PHP.
 
  If you don't, please visit the following websites before trying to
  use this package:
  - http://www.php.net/gettext
  - http://www.onlamp.com/pub/a/php/2002/06/13/php.html
 
  If you encounter problems when using the native gettext extension,
  you may want to try the php-gettext module, which emulates the behavior
  of the C extension, but is written in pure PHP:
  http://savannah.nongnu.org/projects/php-gettext/
 
  This package has two parts:
  1. block.t.php - The Smarty plugin.
  2. tsmarty2c.php - A command line utility that rips gettext strings
  from smarty source files and converts them to C format.
 
  ---------------------------------
  | block.t.php - The Smarty plugin |
  ---------------------------------
 
  Installation
  ------------
 
  Simply copy block.t.php to your smarty plugins directory.
 
  Usage
  ------
 
  The content of the block function is the string that you want to translate.
  For example, for translating 'Hello World', use: {t}Hello World{/t}.
 
  If you have dynamic parameters that should be set inside the string,
  pass them to the block function, and they will be replaced with %n,
  where n is 1 for the 1st parameter and so on.
 
  For example, {t name="sagi"}my name is %1{/t} will replace %1 with sagi.
 
  The parameter name is ignored, unless it is one of the reserved
  names (see below). Only the parameters order matters.
 
  Example for using multiple parameters:
  {t 1='one' 2='two' 3='three'}The 1st parameter is %1, the 2nd is %2
  and the 3nd %3.{/t}
 
  NOTE: I decided to use numeric arguments instead of sprintf(),
  mainly because its syntax is simpler for the translators
  (especially when wanting to change the parameter order).
 
  You can also use this method in your PHP code, by using the
  smarty_gettext_strarg() function. It is only loaded after block.t.php is
  included, so you probably want to copy it elsewhere.
  I usually name the global version of this function strarg(), and use it like this:
  echo strarg(_('hi %1'), $name [,..]);
 
  By default, all the translated strings will be automatically HTML escaped.
  You may control this by setting the 'escape' parameter. Possible values:
  - 'html' for HTML escaping, this is the default.
  - 'js' for javascript escaping.
  - 'url' for url escaping.
  - 'no'/'off'/0 - disables escaping.
  Example:
  {t escape=no url="http://www.php.net/" name="PHP website"}
  <a href="%1">%2</a>
  {/t}
 
  Plural support
  --------------
 
  The package also provides support for plural forms (see ngettext).
 
  To provide a plural form:
  1. Set a parameter named 'plural' with the plural version of the string.
  2. Set a parameter named 'count' with the variable count.
 
  Plural and count are special parameters, and therefore, are not available
  as numeric arguments. If you wish to use the count value inside the string,
  you will have to set it again, as a numeric argument.
 
  Example:
  {t count=$files|@count 1=$files|@count plural="%1 files"}One file{/t}
 
  Modifier support
  ----------------
 
  A Smarty modifier support is not provided by this package.
 
  I believe variables should be trnalsated in the application level
  and provided after translation to the template.
 
  If you need it anyway, it is easy to create such modifier, by simply
  registering the PHP gettext command as one.
 
  ------------------------------------------
  | tsmarty2c.php - the command line utility |
  ------------------------------------------
 
  This utility will rip the translation strings from the smarty files,
  and convert them to gettext calls in C.
 
  The C output may later be used with the standard gettext tools (see xgettext).
 
  Usage:
  ./tsmarty2c.php <filename or directory> <file2> <..> > smarty.c
 
  If a parameter is a directory, the template files within will
  be parsed, recursively.
 
  TIP:
  The output also contains comments that point to the location of the file
  that the string has been ripped from.
 
  You can use the '--add-comments' parameter of xgettext to make it include
  these comments inside the PO file (suggested by Mike van Lammeren).
 
  NOTE:
  You may need to adjust the PHP bin path at the top of the file,
  or use 'php tsmarty2c.php' to run the script.
 
  -----------
  | Copyright |
  -----------
 
  Copyright (c) 2004-2005 Sagi Bashari
 
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
 
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.
 
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
  <?php
  /**
  * block.t.php - Smarty gettext block plugin
  *
  * ------------------------------------------------------------------------- *
  * This library is free software; you can redistribute it and/or *
  * modify it under the terms of the GNU Lesser General Public *
  * License as published by the Free Software Foundation; either *
  * version 2.1 of the License, or (at your option) any later version. *
  * *
  * This library is distributed in the hope that it will be useful, *
  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  * Lesser General Public License for more details. *
  * *
  * You should have received a copy of the GNU Lesser General Public *
  * License along with this library; if not, write to the Free Software *
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
  * ------------------------------------------------------------------------- *
  *
  * Installation: simply copy this file to the smarty plugins directory.
  *
  * @package smarty-gettext
  * @version $Id: block.t.php,v 1.1 2005/07/27 17:58:56 sagi Exp $
  * @link http://smarty-gettext.sourceforge.net/
  * @author Sagi Bashari <sagi@boom.org.il>
  * @copyright 2004-2005 Sagi Bashari
  */
 
  /**
  * Replaces arguments in a string with their values.
  * Arguments are represented by % followed by their number.
  *
  * @param string Source string
  * @param mixed Arguments, can be passed in an array or through single variables.
  * @returns string Modified string
  */
  function smarty_gettext_strarg($str)
  {
  $tr = array();
  $p = 0;
 
  for ($i=1; $i < func_num_args(); $i++) {
  $arg = func_get_arg($i);
 
  if (is_array($arg)) {
  foreach ($arg as $aarg) {
  $tr['%'.++$p] = $aarg;
  }
  } else {
  $tr['%'.++$p] = $arg;
  }
  }
 
  return strtr($str, $tr);
  }
 
  /**
  * Smarty block function, provides gettext support for smarty.
  *
  * The block content is the text that should be translated.
  *
  * Any parameter that is sent to the function will be represented as %n in the translation text,
  * where n is 1 for the first parameter. The following parameters are reserved:
  * - escape - sets escape mode:
  * - 'html' for HTML escaping, this is the default.
  * - 'js' for javascript escaping.
  * - 'url' for url escaping.
  * - 'no'/'off'/0 - turns off escaping
  * - plural - The plural version of the text (2nd parameter of ngettext())
  * - count - The item count for plural mode (3rd parameter of ngettext())
  */
  function smarty_block_t($params, $text, &$smarty)
  {
  $text = stripslashes($text);
 
  // set escape mode
  if (isset($params['escape'])) {
  $escape = $params['escape'];
  unset($params['escape']);
  }
 
  // set plural version
  if (isset($params['plural'])) {
  $plural = $params['plural'];
  unset($params['plural']);
 
  // set count
  if (isset($params['count'])) {
  $count = $params['count'];
  unset($params['count']);
  }
  }
 
  // use plural if required parameters are set
  if (isset($count) && isset($plural)) {
  $text = ngettext($text, $plural, $count);
  } else { // use normal
  $text = gettext($text);
  }
 
  // run strarg if there are parameters
  if (count($params)) {
  $text = smarty_gettext_strarg($text, $params);
  }
 
  if (!isset($escape) || $escape == 'html') { // html escape, default
  $text = nl2br(htmlspecialchars($text));
  } elseif (isset($escape)) {
  switch ($escape) {
  case 'javascript':
  case 'js':
  // javascript escape
  $text = str_replace('\'', '\\\'', stripslashes($text));
  break;
  case 'url':
  // url escape
  $text = urlencode($text);
  break;
  }
  }
 
  return $text;
  }
 
  ?>
 
  #!/usr/bin/env php
  <?php
  /**
  * tsmarty2c.php - rips gettext strings from smarty template
  *
  * ------------------------------------------------------------------------- *
  * This library is free software; you can redistribute it and/or *
  * modify it under the terms of the GNU Lesser General Public *
  * License as published by the Free Software Foundation; either *
  * version 2.1 of the License, or (at your option) any later version. *
  * *
  * This library is distributed in the hope that it will be useful, *
  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  * Lesser General Public License for more details. *
  * *
  * You should have received a copy of the GNU Lesser General Public *
  * License along with this library; if not, write to the Free Software *
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
  * ------------------------------------------------------------------------- *
  *
  * This command line script rips gettext strings from smarty file,
  * and prints them to stdout in C format, that can later be used with the
  * standard gettext tools.
  *
  * Usage:
  * ./tsmarty2c.php <filename or directory> <file2> <..> > smarty.c
  *
  * If a parameter is a directory, the template files within will be parsed.
  *
  * @package smarty-gettext
  * @version $Id: tsmarty2c.php,v 1.3 2005/07/27 17:59:39 sagi Exp $
  * @link http://smarty-gettext.sf.net/
  * @author Sagi Bashari <sagi@boom.org.il>
  * @copyright 2004-2005 Sagi Bashari
  */
 
  // smarty open tag
  $ldq = preg_quote('{');
 
  // smarty close tag
  $rdq = preg_quote('}');
 
  // smarty command
  $cmd = preg_quote('t');
 
  // extensions of smarty files, used when going through a directory
  $extensions = array('tpl');
 
  // "fix" string - strip slashes, escape and convert new lines to \n
  function fs($str)
  {
  $str = stripslashes($str);
  $str = str_replace('"', '\"', $str);
  $str = str_replace("\n", '\n', $str);
  return $str;
  }
 
  // rips gettext strings from $file and prints them in C format
  function do_file($file)
  {
  $content = @file_get_contents($file);
 
  if (empty($content)) {
  return;
  }
 
  global $ldq, $rdq, $cmd;
 
  preg_match_all(
  "/{$ldq}\s*({$cmd})\s*([^{$rdq}]*){$rdq}([^{$ldq}]*){$ldq}\/\\1{$rdq}/",
  $content,
  $matches
  );
 
  for ($i=0; $i < count($matches[0]); $i++) {
  // TODO: add line number
  echo "/* $file */\n"; // credit: Mike van Lammeren 2005-02-14
 
  if (preg_match('/plural\s*=\s*["\']?\s*(.[^\"\']*)\s*["\']?/', $matches[2][$i], $match)) {
  echo 'ngettext("'.fs($matches[3][$i]).'","'.fs($match[1]).'",x);'."\n";
  } else {
  echo 'gettext("'.fs($matches[3][$i]).'");'."\n";
  }
 
  echo "\n";
  }
  }
 
  // go through a directory
  function do_dir($dir)
  {
  $d = dir($dir);
 
  while (false !== ($entry = $d->read())) {
  if ($entry == '.' || $entry == '..') {
  continue;
  }
 
  $entry = $dir.'/'.$entry;
 
  if (is_dir($entry)) { // if a directory, go through it
  do_dir($entry);
  } else { // if file, parse only if extension is matched
  $pi = pathinfo($entry);
 
  if (isset($pi['extension']) && in_array($pi['extension'], $GLOBALS['extensions'])) {
  do_file($entry);
  }
  }
  }
 
  $d->close();
  }
 
  for ($ac=1; $ac < $_SERVER['argc']; $ac++) {
  if (is_dir($_SERVER['argv'][$ac])) { // go through directory
  do_dir($_SERVER['argv'][$ac]);
  } else { // do file
  do_file($_SERVER['argv'][$ac]);
  }
  }
 
  ?>
 
comments