dvadf
File manager - Edit - /home/theblueo/tv/wp-includes/pomo/lib/gettext.tar
Back
Data.php 0000666 00000030751 15214170700 0006135 0 ustar 00 <?php loco_require_lib('compiled/gettext.php'); /** * Wrapper for array forms of parsed PO data */ class Loco_gettext_Data extends LocoPoIterator implements JsonSerializable { /** * Normalize file extension to internal type * @param Loco_fs_File * @return string "po", "pot" or "mo" * @throws Loco_error_Exception */ public static function ext( Loco_fs_File $file ){ $ext = rtrim( strtolower( $file->extension() ), '~' ); if( 'po' === $ext || 'pot' === $ext || 'mo' === $ext ){ return $ext; } // translators: Error thrown when attempting to parse a file that is not PO, POT or MO throw new Loco_error_Exception( sprintf( __('%s is not a Gettext file'), $file->basename() ) ); } /** * @param Loco_fs_File * @return Loco_gettext_Data */ public static function load( Loco_fs_File $file ){ $type = strtoupper( self::ext($file) ); // catch parse errors so we can inform user of which file is bad try { if( 'MO' === $type ){ return self::fromBinary( $file->getContents() ); } else { return self::fromSource( $file->getContents() ); } } catch( Loco_error_ParseException $e ){ $path = $file->getRelativePath( loco_constant('WP_CONTENT_DIR') ); Loco_error_AdminNotices::debug( sprintf('Failed to parse %s as a %s file',$path,$type) ); throw new Loco_error_ParseException( sprintf('Invalid %s file: %s',$type,basename($path)) ); } } /** * Like load but just pulls header, saving a full parse. PO only * @param Loco_fs_File * @return Loco_gettext_Data * @throws InvalidArgumentException */ public static function head( Loco_fs_File $file ){ if( 'mo' === self::ext($file) ){ throw new InvalidArgumentException('PO only'); } $po = new LocoPoParser( $file->getContents() ); return new Loco_gettext_Data( $po->parse(1) ); } /** * @param string assumed PO source * @return Loco_gettext_Data */ public static function fromSource( $src ){ $p = new LocoPoParser($src); return new Loco_gettext_Data( $p->parse() ); } /** * @param string assumed MO bytes * @return Loco_gettext_Data */ public static function fromBinary( $bin ){ $p = new LocoMoParser($bin); return new Loco_gettext_Data( $p->parse() ); } /** * Create a dummy/empty instance with minimum content to be a valid PO file. * @return Loco_gettext_Data */ public static function dummy(){ return new Loco_gettext_Data( array( array('source'=>'','target'=>'Language:') ) ); } /** * Ensure PO source is UTF-8. * Required if we want PO code when we're not parsing it. e.g. source view * @param string * @return string */ public static function ensureUtf8( $src ){ loco_check_extension('mbstring'); $src = loco_remove_bom($src,$cs); if( ! $cs ){ // read PO header, requiring partial parse try { $cs = LocoPoHeaders::fromSource($src)->getCharset(); } catch( Loco_error_ParseException $e ){ Loco_error_AdminNotices::debug( $e->getMessage() ); } // fall back on detection which will only work for latin1 if( ! $cs ){ $cs = mb_detect_encoding($src,array('UTF-8','ISO-8859-1'),true); } } if( $cs && 'UTF-8' !== $cs ){ $src = mb_convert_encoding($src,'UTF-8',array($cs) ); } return $src; } /** * Compile messages to binary MO format * @return string MO file source * @throws Loco_error_Exception */ public function msgfmt(){ if( 2 !== strlen("\xC2\xA3") ){ throw new Loco_error_Exception('Refusing to compile MO file. Please disable mbstring.func_overload'); // @codeCoverageIgnore } $mo = new LocoMo( $this, $this->getHeaders() ); $opts = Loco_data_Settings::get(); if( $opts->gen_hash ){ $mo->enableHash(); } if( $opts->use_fuzzy ){ $mo->useFuzzy(); } return $mo->compile(); } /** * Get final UTF-8 string for writing to file * @param bool whether to sort output, generally only for extracting strings * @return string */ public function msgcat( $sort = false ){ // set maximum line width, zero or >= 15 $this->wrap( Loco_data_Settings::get()->po_width ); // concat with default text sorting if specified $po = $this->render( $sort ? array( 'LocoPoIterator', 'compare' ) : null ); // Prepend byte order mark only if configured if( Loco_data_Settings::get()->po_utf8_bom ){ $po = "\xEF\xBB\xBF".$po; } return $po; } /** * Split JavaScript messages out of document, based on file reference mapping * @return array */ public function splitJs(){ // TODO take file extension from config $messages = $this->splitRefs( array('js'=>'js','jsx'=>'js') ); return isset($messages['js']) ? $messages['js'] : array(); } /** * Compile JED flavour JSON * @param string text domain for JED metadata * @param LocoPoMessage[] pre-compiled messages * @return string */ public function jedize( $domain, array $po ){ $head = $this->getHeaders(); // start locale_data with JED header $data = array( '' => array ( 'domain' => $domain, 'lang' => $head['language'], 'plural-forms' => $head['plural-forms'], ) ); /* @var LocoPoMessage $msg */ foreach( $po as $msg ){ $data[ $msg->getKey() ] = $msg->getMsgstrs(); } // pretty formatting for debugging $json_options = 0; if( Loco_data_Settings::get()->jed_pretty ){ $json_options |= loco_constant('JSON_PRETTY_PRINT') | loco_constant('JSON_UNESCAPED_SLASHES') | loco_constant('JSON_UNESCAPED_UNICODE'); } return json_encode( array ( 'translation-revision-date' => $head['po-revision-date'], 'generator' => $head['x-generator'], 'domain' => $domain, 'locale_data' => array ( $domain => $data, ), ), $json_options ); } /** * @return array */ public function jsonSerialize(){ $po = $this->getArrayCopy(); // exporting headers non-scalar so js doesn't have to parse them try { $headers = $this->getHeaders(); if( count($headers) && '' === $po[0]['source'] ){ $po[0]['target'] = $headers->getArrayCopy(); } } // suppress header errors when serializing // @codeCoverageIgnoreStart catch( Exception $e ){ } // @codeCoverageIgnoreEnd return $po; } /** * Export to JSON for JavaScript editor * @return string */ public function exportJson(){ return json_encode( $this->jsonSerialize() ); } /** * Create a signature for use in comparing source strings between documents * @return string */ public function getSourceDigest(){ $data = $this->getHashes(); return md5( implode("\1",$data) ); } /** * @param Loco_Locale * @param array custom headers * @return Loco_gettext_Data */ public function localize( Loco_Locale $locale, array $custom = null ){ $date = gmdate('Y-m-d H:i').'+0000'; // <- forcing UCT $headers = $this->getHeaders(); // headers that must always be set if absent $defaults = array ( 'Project-Id-Version' => '', 'Report-Msgid-Bugs-To' => '', 'POT-Creation-Date' => $date, ); // headers that must always override when localizing $required = array ( 'PO-Revision-Date' => $date, 'Last-Translator' => '', 'Language-Team' => $locale->getName(), 'Language' => (string) $locale, 'Plural-Forms' => $locale->getPluralFormsHeader(), 'MIME-Version' => '1.0', 'Content-Type' => 'text/plain; charset=UTF-8', 'Content-Transfer-Encoding' => '8bit', 'X-Generator' => 'Loco https://localise.biz/', 'X-Loco-Version' => sprintf('%s; wp-%s', loco_plugin_version(), $GLOBALS['wp_version'] ), ); // set user's preferred Last-Translator credit if configured if( function_exists('get_current_user_id') && get_current_user_id() ){ $prefs = Loco_data_Preferences::get(); $credit = (string) $prefs->credit; if( '' === $credit ){ $credit = $prefs->default_credit(); } // filter credit with current user name and email $user = wp_get_current_user(); $credit = apply_filters( 'loco_current_translator', $credit, $user->get('display_name'), $user->get('email') ); if( '' !== $credit ){ $required['Last-Translator'] = $credit; } } // only set absent or empty headers from default list foreach( $defaults as $key => $value ){ if( ! $headers[$key] ){ $headers[$key] = $value; } } // add required headers with custom ones overriding if( is_array($custom) ){ $required = array_merge( $required, $custom ); } foreach( $required as $key => $value ){ $headers[$key] = $value; } // avoid non-empty POT placeholders that won't have been set from $defaults if( 'PACKAGE VERSION' === $headers['Project-Id-Version'] ){ $headers['Project-Id-Version'] = ''; } // header message must be un-fuzzied if it was formerly a POT file return $this->initPo(); } /** * @return Loco_gettext_Data */ public function templatize(){ $date = gmdate('Y-m-d H:i').'+0000'; // <- forcing UCT $headers = $this->getHeaders(); $required = array ( 'Project-Id-Version' => 'PACKAGE VERSION', 'Report-Msgid-Bugs-To' => '', 'POT-Creation-Date' => $date, 'PO-Revision-Date' => 'YEAR-MO-DA HO:MI+ZONE', 'Last-Translator' => 'FULL NAME <EMAIL@ADDRESS>', 'Language-Team' => '', 'Language' => '', 'Plural-Forms' => 'nplurals=INTEGER; plural=EXPRESSION;', 'MIME-Version' => '1.0', 'Content-Type' => 'text/plain; charset=UTF-8', 'Content-Transfer-Encoding' => '8bit', 'X-Generator' => 'Loco https://localise.biz/', 'X-Loco-Version' => sprintf('%s; wp-%s', loco_plugin_version(), $GLOBALS['wp_version'] ), ); foreach( $required as $key => $value ){ $headers[$key] = $value; } return $this->initPot(); } /** * Remap proprietary base path when PO file is moving to another location. * * @param Loco_fs_File the file that was originally extracted to (POT) * @param Loco_fs_File the file that must now target references relative to itself * @param string vendor name used in header keys * @return bool whether base header was alterered */ public function rebaseHeader( Loco_fs_File $origin, Loco_fs_File $target, $vendor ){ $base = $target->getParent(); $head = $this->getHeaders(); $key = 'X-'.$vendor.'-Basepath'; if( $key = $head->normalize($key) ){ $oldRelBase = $head[$key]; $oldAbsBase = new Loco_fs_Directory($oldRelBase); $oldAbsBase->normalize( $origin->getParent() ); $newRelBase = $oldAbsBase->getRelativePath($base); // new base path is relative to $target location $head[$key] = $newRelBase; return true; } return false; } /** * @param string date format as Gettext states "YEAR-MO-DA HO:MI+ZONE" * @return int */ public static function parseDate( $podate ){ if( method_exists('DateTime', 'createFromFormat') ){ $objdate = DateTime::createFromFormat('Y-m-d H:iO', $podate); if( $objdate instanceof DateTime ){ return $objdate->getTimestamp(); } } return strtotime($podate); } } WordCount.php 0000666 00000005477 15214170700 0007217 0 ustar 00 <?php /** * Experimental PO/POT file word counter. * Word counts are approximate, including numbers and sprintf tokens. * Currently only used for source words in latin script, presumed to be in English. */ class Loco_gettext_WordCount implements Countable { /** * @var LocoPoIterator */ private $po; /** * Source Words: Cached count of "msgid" fields, presumed en_US * @var int */ private $sw; /** * Create counter for a pre-parsed PO/POT file. */ public function __construct( Loco_gettext_Data $po ){ $this->po = $po; } /** * @internal */ private function countField( $f ){ $n = 0; foreach( $this->po as $r ){ $n += self::simpleCount( $r[$f] ); } return $n; } /** * Default count function returns source words (msgid) in current file. * @return int */ public function count(){ $n = $this->sw; if( is_null($n) ){ $n = $this->countField('source'); $this->sw = $n; } return $n; } /** * Very simple word count, only suitable for latin characters, and biased toward English. * @param string * @return int */ public static function simpleCount( $str ){ $n = 0; if( is_string($str) && '' !== $str ){ // TODO should we strip PHP string formatting? // e.g. "Hello %s" currently counts as 2 words. // $str = preg_replace('/%(?:\\d+\\$)?(?:\'.|[-+0 ])*\\d*(?:\\.\\d+)?[suxXbcdeEfFgGo%]/', '', $str ); // Strip HTML (but only if open and close tags detected, else "< foo" would be stripped to nothing if( false !== strpos($str,'<') && false !== strpos($str,'>') ){ $str = strip_tags($str); } // always html-decode, else escaped punctuation will be counted as words $str = html_entity_decode( $str, ENT_QUOTES, 'UTF-8'); // Collapsing apostrophe'd words into single units: // Simplest way to handle ambiguity of "It's Tim's" (technically three words in English) $str = preg_replace('/(\\w+)\'(\\w)(\\W|$)/u', '\\1\\2\\3', $str ); // Combining floating numbers into single units // e.g. "£1.50" and "€1,50" should be one word each $str = preg_replace('/\\d[\\d,\\.]+/', '0', $str ); // count words by standard Unicode word boundaries $words = preg_split( '/\\W+/u', $str, -1, PREG_SPLIT_NO_EMPTY ); $n += count($words); /*/ TODO should we exclude some words (like numbers)? foreach( $words as $word ){ if( ! ctype_digit($word) ){ $n++; } }*/ } return $n; } } Extraction.php 0000666 00000012661 15214170700 0007404 0 ustar 00 <?php loco_require_lib('compiled/gettext.php'); /** * String extraction from source code. */ class Loco_gettext_Extraction { /** * @var Loco_package_Bundle */ private $bundle; /** * @var LocoExtracted */ private $extracted; /** * Extra strings to be pushed into domains * @var array */ private $extras; /** * List of files skipped due to memory limit * @var Loco_fs_FileList */ private $skipped; /** * Size in bytes of largest file encountered * @var int */ private $maxbytes = 0; /** * Initialize extractor for a given bundle * @param Loco_package_Bundle */ public function __construct( Loco_package_Bundle $bundle ){ loco_check_extension('ctype'); loco_check_extension('mbstring'); if( ! loco_check_extension('tokenizer') ){ throw new Loco_error_Exception('String extraction not available without required extension'); } $this->bundle = $bundle; $this->extracted = new LocoExtracted; $this->extracted->setDomain('default'); $this->extras = array(); if( $default = $bundle->getDefaultProject() ){ $domain = (string) $default->getDomain(); // wildcard stands in for empty text domain, meaning unspecified or dynamic domains will be included. // note that strings intended to be in "default" domain must specify explicitly, or be included here too. if( '*' === $domain ){ $domain = ''; $this->extracted->setDomain(''); } // pull bundle's default metadata. these are translations that may not be encountered in files $extras = array(); $header = $bundle->getHeaderInfo(); foreach( $bundle->getMetaTranslatable() as $prop => $notes ){ if( $source = $header->__get($prop) ){ if( is_string($source) ){ $extras[] = array( $source, $notes ); } } } if( $extras ){ $this->extras[$domain] = $extras; } } } /** * @param Loco_package_Project * @return Loco_gettext_Extraction */ public function addProject( Loco_package_Project $project ){ $base = $this->bundle->getDirectoryPath(); // skip files larger than configured maximum $opts = Loco_data_Settings::get(); $max = wp_convert_hr_to_bytes( $opts->max_php_size ); // *attempt* to raise memory limit to WP_MAX_MEMORY_LIMIT if( function_exists('wp_raise_memory_limit') ){ wp_raise_memory_limit('loco'); } /* @var $file Loco_fs_File */ foreach( $project->findSourceFiles() as $file ){ $type = $opts->ext2type( $file->extension() ); $extr = loco_wp_extractor($type); if( 'js' !== $type ) { // skip large files for PHP, because token_get_all is hungry $size = $file->size(); $this->maxbytes = max( $this->maxbytes, $size ); if( $size > $max ){ $list = $this->skipped or $list = ( $this->skipped = new Loco_fs_FileList() ); $list->add( $file ); continue; } // extract headers from theme PHP files in if( $project->getBundle()->isTheme() ){ $extr->headerize( array ( 'Template Name' => 'Name of the template', ), (string) $project->getDomain() ); } } $this->extracted->extractSource( $extr, $file->getContents(), $file->getRelativePath( $base ) ); } return $this; } /** * Add metadata strings deferred from construction. Note this will alter domain counts * @return Loco_gettext_Extraction */ public function includeMeta(){ foreach( $this->extras as $domain => $extras ){ foreach( $extras as $args ){ $this->extracted->pushMeta( $args[0], $args[1], $domain ); } } $this->extras = array(); return $this; } /** * Get number of unique strings across all domains extracted (excluding additional metadata) * @return array { default: x, myDomain: y } */ public function getDomainCounts(){ return $this->extracted->getDomainCounts(); } /** * Pull extracted data into POT, filtering out any unwanted domains * @param string * @return Loco_gettext_Data */ public function getTemplate( $domain ){ $data = new Loco_gettext_Data( $this->extracted->filter($domain) ); return $data->templatize(); } /** * Get total number of strings extracted from all domains, excluding additional metadata * @return int */ public function getTotal(){ return $this->extracted->count(); } /** * Get list of files skipped, or null if none were skipped * @return Loco_fs_FileList | null */ public function getSkipped(){ return $this->skipped; } /** * Get size in bytes of largest file encountered, even if skipped. * This is the value required of the max_php_size plugin setting to extract all files * @return int */ public function getMaxPhpSize(){ return $this->maxbytes; } } SearchPaths.php 0000666 00000005710 15214170700 0007466 0 ustar 00 <?php /** * A file finder built from search path references in a PO/POT file */ class Loco_gettext_SearchPaths extends Loco_fs_FileFinder { /** * Look up a relative file reference against search paths * @param string relative file path reference * @return Loco_fs_File */ public function match( $ref ){ $excluded = new Loco_fs_Locations( $this->getExcluded() ); /* @var Loco_fs_Directory */ foreach( $this->getRootDirectories() as $base ){ $file = new Loco_fs_File($ref); $path = $file->normalize( (string) $base ); if( $file->exists() && ! $excluded->check($path) ){ return $file; } } } /** * Build search paths from a given PO/POT file that references other files * @return Loco_gettext_SearchPaths */ public function init( Loco_fs_File $pofile, LocoHeaders $head = null ){ if( is_null($head) ){ loco_require_lib('compiled/gettext.php'); $head = LocoPoHeaders::fromSource( $pofile->getContents() ); } $ninc = 0; foreach( array('Poedit') as $vendor ){ $key = 'X-'.$vendor.'-Basepath'; if( ! $head->has($key) ){ continue; } $dir = new Loco_fs_Directory( $head[$key] ); $base = $dir->normalize( $pofile->dirname() ); // base should be absolute, with the following search paths relative to it $i = 0; while( true ){ $key = sprintf('X-%s-SearchPath-%u', $vendor, $i++); if( ! $head->has($key) ){ break; } // map search path to given base $include = new Loco_fs_File( $head[$key] ); $include->normalize( $base ); if( $include->exists() ){ if( $include->isDirectory() ){ $this->addRoot( (string) $include ); $ninc++; } /*else { TODO force specific file in Loco_fs_FileFinder }*/ } } // exclude from search paths $i = 0; while( true ){ $key = sprintf('X-%s-SearchPathExcluded-%u', $vendor, $i++); if( ! $head->has($key) ){ break; } // map excluded path to given base $exclude = new Loco_fs_File( $head[$key] ); $exclude->normalize($base); if( $exclude->exists() ){ $this->exclude( (string) $exclude ); } // TODO implement wildcard exclusion } } // Add po file location if no proprietary headers used if( ! $ninc ){ $this->addRoot( $pofile->dirname() ); } return $this; } } Metadata.php 0000666 00000015307 15214170700 0007004 0 ustar 00 <?php loco_require_lib('compiled/gettext.php'); /** * Holds metadata about a PO file, cached as Transient */ class Loco_gettext_Metadata extends Loco_data_Transient { /** * Generate abbreviated stats from parsed array data * @param array in form returned from parser, including header message * @return array in form ['t' => total, 'p' => progress, 'f' => fuzzy ]; */ public static function stats( array $po ){ $t = $p = $f = 0; /* @var $r array */ foreach( $po as $i => $r ){ // skip header if( 0 === $i && empty($r['source']) && empty($r['context']) ){ continue; } // plural form // TODO how should plural forms affect stats? should all forms be complete before 100% can be achieved? should offsets add to total?? if( isset($r['parent']) && is_int($r['parent']) ){ continue; } // singular form $t++; if( '' !== $r['target'] ){ $p++; if( isset($r['flag']) /*&& LOCO_FLAG_FUZZY === $r['flag']*/ ){ $f++; } } } return compact('t','p','f'); } /** * {@inheritdoc} */ public function getKey(){ return 'po_'.md5( $this['rpath'] ); } /** * Load metadata from file, using cache if enabled. * Note that this does not throw exception, check "valid" key * @param Loco_fs_File * @param bool * @return Loco_gettext_Metadata */ public static function load( Loco_fs_File $po, $nocache = false ){ $bytes = $po->size(); $mtime = $po->modified(); // quick construct of new meta object. enough to query and validate cache $meta = new Loco_gettext_Metadata( array( 'rpath' => $po->getRelativePath( loco_constant('WP_CONTENT_DIR') ), ) ); // pull from cache if exists and has not been modified if( $nocache || ! $meta->fetch() || $bytes !== $meta['bytes'] || $mtime !== $meta['mtime'] ){ // not available from cache, or cache is invalidated $meta['bytes'] = $bytes; $meta['mtime'] = $mtime; // parse what is hopefully a PO file to get stats try { $data = Loco_gettext_Data::load($po)->getArrayCopy(); $meta['valid'] = true; $meta['stats'] = self::stats($data); } catch( Exception $e ){ $meta['valid'] = false; $meta['error'] = $e->getMessage(); } } // show cached debug notice as if file was being parsed else if( $meta->offsetExists('error') ){ Loco_error_AdminNotices::debug($meta['error'].': '.$meta['rpath']); } // persist on shutdown with a useful TTL and keepalive // Maximum lifespan: 10 days. Refreshed if accessed a day after being cached. $meta->setLifespan(864000)->keepAlive(86400)->persistLazily(); return $meta; } /** * Construct metadata from previously parsed PO data * @param Loco_fs_File * @param Loco_gettext_Data * @return Loco_gettext_Metadata */ public static function create( Loco_fs_File $file, Loco_gettext_Data $data ){ return new Loco_gettext_Metadata( array ( 'valid' => true, 'bytes' => $file->size(), 'mtime' => $file->modified(), 'stats' => self::stats( $data->getArrayCopy() ), ) ); } /** * Get progress stats as simple array with keys, t=total, p=progress, f:flagged. * Note that untranslated strings are never flagged, hence "f" includes all in "p" * @return array in form ['t' => total, 'p' => progress, 'f' => fuzzy ]; */ public function getStats(){ if( isset($this['stats']) ){ return $this['stats']; } // fallback to empty stats return array( 't' => 0, 'p' => 0, 'f' => 0 ); } /** * Get total number of messages, not including header and excluding plural forms * @return int */ public function getTotal(){ $stats = $this->getStats(); return $stats['t']; } /** * Get number of fuzzy messages, not including header * @return int */ public function countFuzzy(){ $stats = $this->getStats(); return $stats['f']; } /** * Get progress as a string percentage (minus % symbol) * @return string */ public function getPercent(){ $stats = $this->getStats(); $n = max( 0, $stats['p'] - $stats['f'] ); $t = max( $n, $stats['t'] ); return loco_string_percent( $n, $t ); } /** * Get number of strings either untranslated or fuzzy. * @return int */ public function countIncomplete(){ $stats = $this->getStats(); return max( 0, $stats['t'] - ( $stats['p'] - $stats['f'] ) ); } /** * Get number of strings completely untranslated (excludes fuzzy). * @return int */ public function countUntranslated(){ $stats = $this->getStats(); return max( 0, $stats['t'] - $stats['p'] ); } /** * Echo progress bar using compiled function * @return void */ public function printProgress(){ $stats = $this->getStats(); $flagged = $stats['f']; $translated = $stats['p']; $untranslated = $stats['t'] - $translated; loco_print_progress( $translated, $untranslated, $flagged ); } /** * Get wordy summary of total strings */ public function getTotalSummary(){ $total = $this->getTotal(); return sprintf( _n('1 string','%s strings',$total,'loco-translate'), number_format($total) ); } /** * Get wordy summary including translation stats */ public function getProgressSummary(){ $extra = array(); $stext = sprintf( __('%s%% translated','loco-translate'), $this->getPercent() ).', '.$this->getTotalSummary(); if( $num = $this->countFuzzy() ){ $extra[] = sprintf( __('%s fuzzy','loco-translate'), number_format($num) ); } if( $num = $this->countUntranslated() ){ $extra[] = sprintf( __('%s untranslated','loco-translate'), number_format($num) ); } if( $extra ){ $stext .= ' ('.implode(', ', $extra).')'; } return $stext; } public function getPath( $absolute ){ $path = $this['rpath']; if( $absolute && ! Loco_fs_File::abs($path) ){ $path = trailingslashit( loco_constant('WP_CONTENT_DIR') ).$path; } return $path; } }
dvadf
dvadf
| ver. 1.4 |
Github
|
.
| PHP 7.0.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings