Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

+57 -19
View File
@@ -117,7 +117,7 @@ class _Lang extends \IPS\Node\Model
static::$multitons[ $id ] = static::constructFromData( $lang );
}
static::$outputSalt = uniqid();
static::$outputSalt = mt_rand();
static::$gotAll = TRUE;
}
@@ -513,6 +513,11 @@ class _Lang extends \IPS\Node\Model
}
}
}
/**
* @brief Cached preferred date format
*/
protected $preferredDateFormat = NULL;
/**
* Get the preferred date format for this locale
@@ -521,11 +526,16 @@ class _Lang extends \IPS\Node\Model
*/
public function preferredDateFormat()
{
/* Make sure the locale has been set, important for things like the js date_format variable */
$this->setLocale();
if( $this->preferredDateFormat === NULL )
{
/* Make sure the locale has been set, important for things like the js date_format variable */
$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() );
$date = new \IPS\DateTime('1992-03-04');
$this->preferredDateFormat = str_replace( array( '1992', '92', '03', '3', $date->strFormat('%B'), $date->strFormat('%b'), '04', ' 4', '4' ), array( 'YY', 'YY', 'MM', 'MM', 'MM', 'MM', 'DD', 'DD', 'DD' ), $date->localeDate() );
}
return $this->preferredDateFormat;
}
/**
@@ -694,7 +704,7 @@ class _Lang extends \IPS\Node\Model
/* Get it */
if( isset( $this->outputStack[ $key ] ) )
{
return htmlspecialchars( $key, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlspecialchars( $key, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE );
}
$id = md5( 'ipslang_' . static::$outputSalt . $key . json_encode( $options ) );
@@ -718,12 +728,25 @@ class _Lang extends \IPS\Node\Model
* @li % is an ending wildcard, so anything that BEGINS with the number supplied will match
* @li # (optional) will be replaced with the actual value
* @example {# [1:test][*2:tests][%3:no tests][?:finals]} will result in 1 test, 2 tests, 12 tests, 3 no tests, 35 no tests, 8 finals
* @example {!1#[1:January][2:February][3:March][4:April][5:May][6:June][7:July][8:August][9:September][10:October][11:November][12:December]} {0#}
* @example {!#[?:%s liked]} %s
*/
public function pluralize( $string, $params )
{
$i = 0;
$openCurly = '--' . mt_rand() . '--';
$closeCurly = '--' . mt_rand() . '--';
/* Prevent nested { } breaking the syntax */
$string = preg_replace_callback( '/(\{!(?:.+?)?(?:\d+?)?\#\[)(.*?)(\]\})/', function( $matches ) use ( $openCurly, $closeCurly )
{
$replaced = str_replace( '{', $openCurly, $matches[2] );
$replaced = str_replace( '}', $closeCurly, $replaced );
return $matches[1] . $replaced . $matches[3];
}, $string );
$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, $openCurly, $closeCurly )
{
$originalNumber = $format[1];
if ( !$format[1] or $format[1] == '!' )
@@ -736,10 +759,14 @@ class _Lang extends \IPS\Node\Model
$params[ $format[1] ] = call_user_func( $numberFormatter, $params[ $format[1] ] );
$fallback = NULL;
$value = NULL;
$token = '--' . mt_rand() . '--';
/* We want to ensure that manually escaped # are not switched */
$format[2] = str_replace( '\#', $token, $format[2] );
/* 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 == '?' )
@@ -768,7 +795,10 @@ class _Lang extends \IPS\Node\Model
$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;
$return = str_replace( $token, '#', $return );
$return = str_replace( $openCurly, '{', $return );
return str_replace( $closeCurly, '}', $return );
}, $string );
}
@@ -778,16 +808,10 @@ class _Lang extends \IPS\Node\Model
* @param number $number The number to format
* @param int $decimals Number of decimal places
* @return string
* @note number_format in PHP < 5.4.0 is not multibyte safe, so we have to work around this deficiency
*/
public function formatNumber( $number, $decimals=0 )
{
$placeholders = array( '@', '~' );
$replacements = array( $this->locale['decimal_point'], $this->locale['thousands_sep'] );
$result = number_format( floatval( $number ), floatval( $decimals ), $placeholders[0], $placeholders[1] );
return str_replace( $placeholders, $replacements, $result );
return number_format( floatval( $number ), floatval( $decimals ), $this->locale['decimal_point'], $this->locale['thousands_sep'] );
}
/**
@@ -837,6 +861,8 @@ class _Lang extends \IPS\Node\Model
$return = $matches[1];
for ( $i = 0; $i<count( $items ); $i++ )
{
/* Pluralize can be used after, so avoid triggering the '#', '#[...]' syntax there */
$items[ $i ] = preg_replace( '/#(\s|\[)/', '\#\1', $items[ $i ] );
$upper = FALSE;
if ( $i == 0 )
{
@@ -1679,7 +1705,7 @@ class _Lang extends \IPS\Node\Model
$sprintf = array_map(
function ( $val ) use ( $replacement )
{
return htmlspecialchars( trim( $val ), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', false );
return htmlspecialchars( trim( $val ), ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', false );
},
( is_array(
$values[ 'options' ][ 'sprintf' ]
@@ -1752,9 +1778,21 @@ class _Lang extends \IPS\Node\Model
$replacement = mb_strtolower( $replacement );
}
if ( isset( $values[ 'options' ][ 'seotitle' ] ) )
{
$replacement = \IPS\Http\Url\Friendly::seoTitle( $replacement );
}
if ( isset( $values[ 'options' ][ 'json' ] ) )
{
$replacement = mb_substr( json_encode( $replacement ), 1, -1 );
if( isset( $values['options']['jsonEscape'] ) )
{
$replacement = mb_substr( json_encode( $replacement, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS ), 1, -1 );
}
else
{
$replacement = mb_substr( json_encode( $replacement ), 1, -1 );
}
}
if ( isset( $values[ 'options' ][ 'striptags' ] ) )
@@ -1764,7 +1802,7 @@ class _Lang extends \IPS\Node\Model
if ( isset( $values[ 'options' ][ 'escape' ] ) )
{
$replacement = htmlspecialchars( $replacement, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', false );
$replacement = htmlspecialchars( $replacement, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', false );
}
if ( isset( $values['options']['escape'] ) and isset( $values['options']['json'] ) )