Root/
<?php /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* # ***** BEGIN LICENSE BLOCK ***** # This file is part of Plume Framework, a simple PHP Application Framework. # Copyright (C) 2001-2007 Loic d'Anterroches and contributors. # # Plume Framework 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. # # Plume Framework 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 program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # ***** END LICENSE BLOCK ***** */ /** * Translation utility. * * This class provides utilities to load and cache translation * strings. The functions using the values are directly available when * loading Pluf. They are __ and _n for simple translations and for * plural dependent translations respectively. * * Based on benchmarking by * localization-is-gettext-fast-enough/ the string id system is really * fast, so here the system is using a .ini file approach with a * string id cache. * * Why reimplementing a gettext system when one is already available? * It is because the PHP gettext extension requires the corresponding * locale to be installed system wide to load the corresponding * translations. If your host has no locales outside English * installed, you can only provide English to your users. Which is not * really nice. * */ class Pluf_Translation { public static $plural_forms = array ( 'fr' => 'plural_2gt1' , 'en' => 'plural_2not1' , // This is the default. 'de' => 'plural_2not1' , ); public static function loadSetLocale( $lang ) { $GLOBALS [ '_PX_current_locale' ] = $lang ; setlocale(LC_TIME, array ( $lang , $lang . '_' . strtoupper ( $lang ), $lang . '.UTF-8' , $lang . '_' . strtoupper ( $lang ). '.UTF-8' )); if (isset( $GLOBALS [ '_PX_locale' ][ $lang ])) { return ; // We consider that it was already loaded. } $GLOBALS [ '_PX_locale' ][ $lang ] = array (); foreach (Pluf::f( 'installed_apps' ) as $app ) { if (false != ( $pofile =Pluf::fileExists( $app . '/locale/' . $lang . '/' . strtolower ( $app ). '.po' ))) { $GLOBALS [ '_PX_locale' ][ $lang ] += Pluf_Translation::readPoFile( $pofile ); } } } public static function getLocale() { return $GLOBALS [ '_PX_current_locale' ]; } /** * Get the plural form for a given locale. */ public static function getPluralForm( $locale ) { if (isset(self:: $plural_forms [ $locale ])) { return self:: $plural_forms [ $locale ]; } if (isset(self:: $plural_forms [ substr ( $locale , 0, 2)])) { return self:: $plural_forms [ substr ( $locale , 0, 2)]; } return 'plural_2not1' ; } /** * Return the "best" accepted language from the list of available * languages. * * Use $_SERVER['HTTP_ACCEPT_LANGUAGE'] if the accepted language * list is empty. The list must be something like: * 'da, en-gb;q=0.8, en;q=0.7' * * @param array Available languages in the system * @param string String of comma separated accepted languages ('') * @return string Language 2 or 5 letter iso code, default is 'en' */ public static function getAcceptedLanguage( $available , $accepted = '' ) { if ( empty ( $accepted )) { if (! empty ( $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ])) { $accepted = $_SERVER [ 'HTTP_ACCEPT_LANGUAGE' ]; } else { return 'en' ; } } $acceptedlist = explode ( ',' , $accepted ); foreach ( $acceptedlist as $lang ) { $lang = explode ( ';' , $lang ); $lang = trim( $lang [0]); if (in_array( $lang , $available )) { return $lang ; } // for the xx-XX cases we may have only the "main" language // form like xx is available $lang = substr ( $lang , 0, 2); if (in_array( $lang , $available )) { return $lang ; } } $langs = Pluf::f( 'languages' , array ( 'en' )); return $langs [0]; } /** * Given a key indexed array, do replacement using the %%key%% in * the string. */ public static function sprintf( $string , $words = array ()) { foreach ( $words as $key => $word ) { $string = mb_ereg_replace( '%%' . $key . '%%' , $word , $string , 'm' ); } return $string ; } /** * French, Brazilian Portuguese */ public static function plural_2gt1( $n ) { return (int) ( $n >1); } public static function plural_2not1( $n ) { return (int) ( $n !=1); } /** * Read a .po file. * * Based on the work by Matthias Bauer with some little cosmetic fixes. * * @source http://wordpress-soc-2007.googlecode.com/svn/trunk/moeffju/php-msgfmt/msgfmt-functions.php * @copyright 2007 Matthias Bauer * @author Matthias Bauer * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License 2.1 * @license http://opensource.org/licenses/apache2.0.php Apache License 2.0 */ public static function readPoFile( $file ) { if (false !== ( $hash =self::getCachedFile( $file ))) { return $hash ; } // read .po file $fc = file_get_contents ( $file ); // normalize newlines $fc = str_replace ( array ( "\r\n" , "\r" ), array ( "\n" , "\n" ), $fc ); // results array $hash = array (); // temporary array $temp = array (); // state $state = null; $fuzzy = false; // iterate over lines foreach ( explode ( "\n" , $fc ) as $line ) { $line = trim( $line ); if ( $line === '' ) continue ; if (false === strpos ( $line , ' ' )) { $key = $line ; $data = '' ; } else { list ( $key , $data )= explode ( ' ' , $line , 2); } switch ( $key ) { case '#,' : // flag... $fuzzy = in_array( 'fuzzy' , preg_split( '/,\s*/' , $data )); case '#' : // translator-comments case '#.' : // extracted-comments case '#:' : // reference... case '#|' : // msgid previous-untranslated-string case '#~' : // deprecated translations // start a new entry if (sizeof( $temp ) && array_key_exists ( 'msgid' , $temp ) && array_key_exists ( 'msgstr' , $temp )) { if (! $fuzzy ) $hash []= $temp ; $temp = array (); $state = null; $fuzzy = false; } break ; case 'msgctxt' : // context case 'msgid' : // untranslated-string case 'msgid_plural' : // untranslated-string-plural $state = $key ; $temp [ $state ]= $data ; break ; case 'msgstr' : // translated-string $state = 'msgstr' ; $temp [ $state ][]= $data ; break ; default : if ( strpos ( $key , 'msgstr[' ) !== False) { // translated-string-case-n $state = 'msgstr' ; $temp [ $state ][]= $data ; } else { // continued lines switch ( $state ) { case 'msgctxt' : case 'msgid' : case 'msgid_plural' : $temp [ $state ] .= "\n" . $line ; break ; case 'msgstr' : $temp [ $state ][sizeof( $temp [ $state ]) - 1] .= "\n" . $line ; break ; default : // parse error return False; } } break ; } } // add final entry if ( $state == 'msgstr' ) $hash []= $temp ; // Cleanup data, merge multiline entries, reindex hash for ksort $temp = $hash ; $hash = array (); foreach ( $temp as $entry ) { foreach ( $entry as & $v ) { $v = Pluf_Translation_poCleanHelper( $v ); if ( $v === False) { // parse error return False; } } if (isset( $entry [ 'msgid_plural' ])) { $hash [ $entry [ 'msgid' ]. '#' . $entry [ 'msgid_plural' ]]= $entry [ 'msgstr' ]; } else { $hash [ $entry [ 'msgid' ]]= $entry [ 'msgstr' ]; } } self::cacheFile( $file , $hash ); return $hash ; } /** * Load optimized version of a language file if available. * * @return mixed false or array with value */ public static function getCachedFile( $file ) { $phpfile = Pluf::f( 'tmp_folder' ). '/Pluf_L10n-' .md5( $file ). '.phps' ; if ( file_exists ( $phpfile ) && ( filemtime ( $file ) < filemtime ( $phpfile ))) { return include $phpfile ; } return false; } /** * Cache an optimized version of a language file. * * @param string File * @param array Parsed hash */ public static function cacheFile( $file , $hash ) { $phpfile = Pluf::f( 'tmp_folder' ). '/Pluf_L10n-' .md5( $file ). '.phps' ; file_put_contents ( $phpfile , '<?php return ' .var_export( $hash , true). '; ?>' , LOCK_EX); @ chmod ( $phpfile , 0666); } } function Pluf_Translation_poCleanHelper( $x ) { if ( is_array ( $x )) { foreach ( $x as $k => $v ) { $x [ $k ]= Pluf_Translation_poCleanHelper( $v ); } } else { if ( $x [0] == '"' ) $x = substr ( $x , 1, -1); $x = str_replace ( "\"\n\"" , '' , $x ); $x = str_replace ( '$' , '\\$' , $x ); $x = @ eval ( "return \"$x\";" ); } return $x ; } |