Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+169 -145
View File
@@ -2,9 +2,9 @@
/**
* @brief Language Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Feb 2013
* @version SVN_VERSION_NUMBER
*/
@@ -289,7 +289,7 @@ class _Lang extends \IPS\Node\Model
}
else
{
\IPS\DB::i()->replace( 'core_sys_lang_words', array(
\IPS\Db::i()->replace( 'core_sys_lang_words', array(
'lang_id' => $langId,
'word_app' => $app,
'word_key' => $key,
@@ -376,21 +376,7 @@ class _Lang extends \IPS\Node\Model
}
}
foreach( explode( ";", $currentLocale ) as $locale )
{
if( mb_strpos( $locale, '=' ) !== FALSE )
{
$parts = explode( "=", $locale );
if( in_array( $parts[0], array( 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME' ) ) )
{
setlocale( constant( $parts[0] ), $parts[1] );
}
}
else
{
setLocale( LC_ALL, $locale );
}
}
static::restoreLocale( $currentLocale );
if ( $success === FALSE )
{
@@ -416,7 +402,7 @@ class _Lang extends \IPS\Node\Model
require \IPS\ROOT_PATH . "/applications/{$app}/dev/lang.php";
\IPS\DB::i()->delete( 'core_sys_lang_words', array( 'word_app=? AND word_export=1', $app ) );
\IPS\Db::i()->delete( 'core_sys_lang_words', array( 'word_app=? AND word_export=1', $app ) );
foreach ( $lang as $k => $v )
{
@@ -504,6 +490,31 @@ class _Lang extends \IPS\Node\Model
}
}
/**
* Restore a previous locale
*
* @param string $previousLocale Value from setlocale( LC_ALL, '0' )
* @return void
*/
public static function restoreLocale( $previousLocale )
{
foreach( explode( ";", $previousLocale ) as $locale )
{
if( mb_strpos( $locale, '=' ) !== FALSE )
{
$parts = explode( "=", $locale );
if( in_array( $parts[0], array( 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME' ) ) )
{
setlocale( constant( $parts[0] ), $parts[1] );
}
}
else
{
setlocale( LC_ALL, $locale );
}
}
}
/**
* Get the preferred date format for this locale
*
@@ -515,7 +526,7 @@ class _Lang extends \IPS\Node\Model
$this->setLocale();
$date = new \IPS\DateTime('1992-03-04');
return str_replace( array( '1992', '92', '03', '3', $date->strFormat('%B'), '04', ' 4', '4' ), array( 'yy', 'yy', 'mm', 'mm', 'mm', 'dd', 'dd', 'dd' ), $date->localeDate() );
return str_replace( array( '1992', '92', '03', '3', $date->strFormat('%B'), '04', ' 4', '4' ), array( 'YY', 'YY', 'MM', 'MM', 'MM', 'DD', 'DD', 'DD' ), $date->localeDate() );
}
/**
@@ -570,6 +581,11 @@ class _Lang extends \IPS\Node\Model
{
return TRUE;
}
else if ( array_key_exists( $key, $this->words ) and $this->words[ $key ] === NULL )
{
/* Language key has been preloaded but does not exist */
return FALSE;
}
else if( $this->wordsLoaded or \IPS\IN_DEV )
{
return FALSE;
@@ -599,7 +615,7 @@ class _Lang extends \IPS\Node\Model
*/
public function get( $key )
{
$return = NULL;
$return = array();
$keysToLoad = array();
if ( is_array( $key ) )
@@ -623,7 +639,7 @@ class _Lang extends \IPS\Node\Model
}
else
{
if ( in_array( $key, array_keys( $this->words ) ) )
if ( isset( $this->words[ $key ] ) )
{
return $this->words[ $key ];
}
@@ -640,7 +656,7 @@ class _Lang extends \IPS\Node\Model
}
/* If we're using an array, fill any missings strings with NULL to prevent duplicate queries */
if ( $return !== NULL and is_array( $key ) and ( count( $return ) !== count( $key ) ) )
if ( is_array( $key ) )
{
foreach( $key as $k )
{
@@ -708,8 +724,9 @@ class _Lang extends \IPS\Node\Model
{
$i = 0;
$numberFormatter = array( $this, 'formatNumber' );
return preg_replace_callback( '/\{(!|\d+?)?#(.*?)\}/', function( $format ) use ( $params, $i, $numberFormatter )
return preg_replace_callback( '/\{!?(\d+?)?#(.*?)\}/', function( $format ) use ( $params, $i, $numberFormatter )
{
$originalNumber = $format[1];
if ( !$format[1] or $format[1] == '!' )
{
$format[1] = $i;
@@ -719,38 +736,41 @@ class _Lang extends \IPS\Node\Model
/* Format now so that 0 is really 0 and not '' or null */
$params[ $format[1] ] = call_user_func( $numberFormatter, $params[ $format[1] ] );
$fallback = NULL;
$value = NULL;
preg_match_all( '/\[(.+?):(.+?)\]/', $format[2], $matches );
$value = NULL;
/* This regex is tricky: It matches [ followed by anything NOT : until :, then any character, then everything that is not a [ until ] */
preg_match_all( '/\[([^:]+):(.[^\[]*)\]/', $format[2], $matches );
foreach ( $matches[1] as $k => $v )
{
if ( $v == '?' )
{
$fallback = str_replace( '#', $params[ $format[1] ], $matches[2][ $k ] );
$fallback = preg_replace( '/(?!&)#(?!\d{2,4};)/', $params[ $format[1] ], $matches[2][ $k ] );
}
elseif( ( mb_substr( $v, 0, 1 ) === '%' and ( mb_substr( $v, 1 ) == $params[ $format[1] ] ) ) )
{
$value = str_replace( '#', $params[ $format[1] ], $matches[2][ $k ] );
$value = preg_replace( '/(?!&)#(?!\d{2,4};)/', $params[ $format[1] ], $matches[2][ $k ] );
// We don't break in case there is a better match
}
elseif( ( mb_substr( $v, 0, 1 ) === '*' and ( mb_substr( $v, -( mb_strlen( mb_substr( $v, 1 ) ) ) ) == mb_substr( $params[ $format[1] ], -( mb_strlen( mb_substr( $v, 1 ) ) ) ) ) ) )
{
$value = str_replace( '#', $params[ $format[1] ], $matches[2][ $k ] );
$value = preg_replace( '/(?!&)#(?!\d{2,4};)/', $params[ $format[1] ], $matches[2][ $k ] );
// We don't break in case there is a better match
}
elseif ( ( $v == $params[ $format[1] ] ) )
elseif ( ( $v === $params[ $format[1] ] ) )
{
$value = str_replace( '#', $params[ $format[1] ], $matches[2][ $k ] );
$value = preg_replace( '/(?!&)#(?!\d{2,4};)/', $params[ $format[1] ], $matches[2][ $k ] );
break;
}
}
$return = rtrim( ltrim( $format[0], '{' ), '}' );
$return = str_replace( '!#', '', $return );
$return = str_replace( "!{$originalNumber}#", '', $return );
$return = str_replace( array( "{$format[1]}#", '#' ), $params[ $format[1] ], $return );
$return = preg_replace( '/\[.+\]/', ( $value === NULL ? $fallback : $value ), $return );
return $return;
}, $string );
}, $string );
}
/**
@@ -813,7 +833,7 @@ class _Lang extends \IPS\Node\Model
}
}
preg_match( '/(^|^(.+?)\s)(a)(.+?\s)(b)(.+?\s)(c)(.+?)?$/i', $format, $matches );
preg_match( '/(^|^(.+?)\s)\b(a)\b(.+?\s?)\b(b)\b(.+?\s?)\b(c)\b(.+?)?$/i', $format, $matches );
$return = $matches[1];
for ( $i = 0; $i<count( $items ); $i++ )
@@ -856,7 +876,7 @@ class _Lang extends \IPS\Node\Model
*
* @param string $prefix Prefix used
* @param string $query Search query
* @param bool alsoSearchDefault If TRUE, will also search the default value
* @param bool $alsoSearchDefault If TRUE, will also search the default value
* @return array
*/
public function searchCustom( $prefix, $query, $alsoSearchDefault=FALSE )
@@ -1057,21 +1077,7 @@ class _Lang extends \IPS\Node\Model
}
}
foreach( explode( ";", $currentLocale ) as $locale )
{
if( mb_strpos( $locale, '=' ) !== FALSE )
{
$parts = explode( "=", $locale );
if( in_array( $parts[0], array( 'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME' ) ) )
{
setlocale( constant( $parts[0] ), $parts[1] );
}
}
else
{
setLocale( LC_ALL, $locale );
}
}
static::restoreLocale( $currentLocale );
}
foreach ( $values as $k => $v )
@@ -1083,7 +1089,7 @@ class _Lang extends \IPS\Node\Model
if( isset( $values['lang_default'] ) and $values['lang_default'] )
{
$this->enabled = TRUE;
\IPS\DB::i()->update( 'core_sys_lang', array( 'lang_default' => 0 ) );
\IPS\Db::i()->update( 'core_sys_lang', array( 'lang_default' => 0 ) );
unset( \IPS\Data\Store::i()->languages );
}
@@ -1108,12 +1114,45 @@ class _Lang extends \IPS\Node\Model
*/
public function get__icon()
{
//if ( preg_match( '/^\w{2}[-_]\w{2}(\..+?)?$/', $this->short ) )
//{
$country = ( mb_strpos( $this->short, '_' ) !== FALSE ) ? mb_strtolower( mb_substr( $this->short, mb_strpos( $this->short, '_' ) + 1, 2 ) ) : mb_strtolower( mb_substr( $this->short, 0, 2 ) );
return "ipsFlag ipsFlag-{$country}";
//}
return NULL;
return "ipsFlag ipsFlag-{$this->getCountry()}";
}
/**
* Return country code
*
* @return string
*/
protected function getCountry()
{
/* We may need to remap some entries for Windows */
if( mb_strtolower( mb_substr( PHP_OS, 0, 3 ) ) === 'win' )
{
/* If it's just "english", consider that US */
if( mb_strtolower( $this->short ) === 'english' )
{
return 'us';
}
elseif( mb_strtolower( $this->short ) === 'german' )
{
return 'de';
}
if( mb_strpos( $this->short, '_' ) !== FALSE )
{
$pieces = explode( '_', $this->short );
if( mb_strpos( mb_strtolower( $pieces[0] ), 'chinese' ) === 0 )
{
return 'cn';
}
elseif( mb_strtolower( $pieces[0] ) === 'english' AND mb_strtolower( $pieces[1] ) === 'uk' )
{
return 'gb';
}
}
}
return ( mb_strpos( $this->short, '_' ) !== FALSE ) ? mb_strtolower( mb_substr( $this->short, mb_strpos( $this->short, '_' ) + 1, 2 ) ) : mb_strtolower( mb_substr( $this->short, 0, 2 ) );
}
/**
@@ -1349,7 +1388,7 @@ class _Lang extends \IPS\Node\Model
}
else
{
setLocale( LC_ALL, $locale );
setlocale( LC_ALL, $locale );
}
}
}
@@ -1449,6 +1488,7 @@ class _Lang extends \IPS\Node\Model
public function parseEmail( &$output )
{
$this->parseOutputForDisplay( $output );
$output = $this->stripVLETags( $output );
$dir = ( $this->isrtl ) ? 'rtl' : 'ltr';
@@ -1495,48 +1535,15 @@ class _Lang extends \IPS\Node\Model
/**
* Insert <wbr> tags into long words
*
* @deprecated This is left here to prevent breaking third party addons, but no longer breaks words.
* @note You should use a container div with classes ipsContained and ipsType_break instead.
* Often you may want to also use ipsTruncate and ipsTruncate_line on an inline element (i.e. an <a> tag) wrapping the text as well to truncate.
* @param string $data The string
* @return string
*/
public static function wordbreak( $data )
{
$return = '';
$charactersWithoutASpace = 0;
$inEntity = FALSE;
for ( $i = 0; $i < mb_strlen( $data ); $i++ )
{
$char = mb_substr( $data, $i, 1 );
if ( $char !== ' ' )
{
$charactersWithoutASpace++;
}
else
{
$charactersWithoutASpace = 0;
}
if ( $char === '&' )
{
$inEntity = TRUE;
}
if ( !$inEntity AND $charactersWithoutASpace > 0 AND $charactersWithoutASpace % 20 == 0 )
{
$return .= '<wbr>';
}
if ( $inEntity and $char === ';' )
{
$inEntity = FALSE;
}
$return .= $char;
}
return $return;
return $data;
}
/**
@@ -1588,6 +1595,12 @@ class _Lang extends \IPS\Node\Model
*/
public function replaceWords( &$output )
{
/* It's possible to call this method and not pass in any content - it's a waste of resources to run replacements on an empty string */
if( !$output )
{
return;
}
$replacements = array();
foreach ( $this->outputStack as $key => $values )
@@ -1602,6 +1615,49 @@ class _Lang extends \IPS\Node\Model
if ( isset( $this->words[ $values[ 'key' ] ] ) )
{
$replacement = $this->words[ $values[ 'key' ] ];
/* Parse URLs */
if ( mb_strpos( $replacement, "{external" ) !== false )
{
$replacement = preg_replace_callback(
"/{external\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::ips( 'docs/' . $matches[ 1 ] );
},
$replacement
);
}
if ( mb_strpos( $replacement, "{internal" ) !== false )
{
$replacement = preg_replace_callback(
"/{internal\.([a-zA-Z]+?)\.(.+?)\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 2 ], $matches[ 1 ], $matches[ 3 ] );
},
$replacement
);
$replacement = preg_replace_callback(
"/{internal\.([a-zA-Z]+?)\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 2 ], $matches[ 1 ] );
},
$replacement
);
$replacement = preg_replace_callback(
"/{internal\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 1 ] );
},
$replacement
);
}
$sprintf = array();
if ( isset( $values[ 'options' ][ 'flipsprintf' ] ) AND $values[ 'options' ][ 'flipsprintf' ] === true )
@@ -1659,7 +1715,7 @@ class _Lang extends \IPS\Node\Model
if ( !empty( $values[ 'options' ][ 'pluralize' ] ) )
{
$replacement = \IPS\Member::loggedIn()->language()->pluralize(
$replacement = $this->pluralize(
$replacement,
$values[ 'options' ][ 'pluralize' ]
);
@@ -1675,6 +1731,11 @@ class _Lang extends \IPS\Node\Model
{
$replacement = \IPS\Lang::wordbreak( $replacement );
}
if ( isset( $values[ 'options' ][ 'ucfirst' ] ) )
{
$replacement = mb_strtoupper( mb_substr( $replacement, 0, 1 ) ) . mb_substr( $replacement, 1 );
}
if ( isset( $values[ 'options' ][ 'strtoupper' ] ) )
{
@@ -1700,55 +1761,13 @@ class _Lang extends \IPS\Node\Model
{
$replacement = htmlspecialchars( $replacement, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', false );
}
/* Parse URLs */
if ( mb_strpos( $replacement, "{external" ) !== false )
{
$replacement = preg_replace_callback(
"/{external\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::ips( 'docs/' . $matches[ 1 ] );
},
$replacement
);
}
if ( mb_strpos( $replacement, "{internal" ) !== false )
{
$replacement = preg_replace_callback(
"/{internal\.([a-zA-Z]+?)\.(.+?)\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 2 ], $matches[ 1 ], $matches[ 3 ] );
},
$replacement
);
$replacement = preg_replace_callback(
"/{internal\.([a-zA-Z]+?)\.(.+?)\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 2 ], $matches[ 1 ], $matches[ 3 ] );
},
$replacement
);
$replacement = preg_replace_callback(
"/{internal\.([a-zA-Z]+?)\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 2 ], $matches[ 1 ] );
},
$replacement
);
$replacement = preg_replace_callback(
"/{internal\.(.+?)}/",
function ( $matches )
{
return \IPS\Http\Url::internal( $matches[ 1 ] );
},
$replacement
);
}
if ( isset( $values['options']['escape'] ) and isset( $values['options']['json'] ) )
{
/* Some browsers treat &#039; as a literal ' which can break things when used in JSON
A similar issue occurrs in IPS\gallery\Image::json() */
$replacement = str_replace( "&#039;", "&apos;", $replacement );
}
/* Add VLE tags */
if ( $values[ 'vle' ] and $replacement and isset( \IPS\Request::i(
@@ -1758,6 +1777,11 @@ class _Lang extends \IPS\Node\Model
{
$replacement = "#VLE#{$values['key']}#!#[{$replacement}]#!##";
}
if ( isset( $values[ 'options' ][ 'returnInto' ] ) )
{
$replacement = sprintf( $values[ 'options' ][ 'returnInto' ], $replacement );
}
$replacements[ $key ] = $replacement;
}
+2 -2
View File
@@ -2,9 +2,9 @@
/**
* @brief Setup Language Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Feb 2013
* @version SVN_VERSION_NUMBER
*/
+2 -2
View File
@@ -2,9 +2,9 @@
/**
* @brief Upgrader Language Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Feb 2015
* @version SVN_VERSION_NUMBER
*/