feat:3.0.0版初次提交,新版将完全推倒重写
5
vendor/loco-translate/CONTRIBUTING.md
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# This is a mirror
|
||||
|
||||
Please don't submit pull requests.
|
||||
|
||||
If you find any issues with this plugin, we'll greatly appreciate feedback posted in the [support forum](https://wordpress.org/support/plugin/loco-translate).
|
37
vendor/loco-translate/README.md
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Loco WordPress Plugin
|
||||
|
||||
### Translate plugins and themes directly in your browser
|
||||
|
||||
Git mirror of the official Loco WordPress plugin:
|
||||
[http://wordpress.org/plugins/loco-translate/](http://wordpress.org/plugins/loco-translate/)
|
||||
|
||||
**Please don't submit pull requests** this is just a mirror of the SVN repository at:
|
||||
[https://plugins.svn.wordpress.org/loco-translate/trunk/](https://plugins.svn.wordpress.org/loco-translate/trunk/)
|
||||
|
||||
Please report issues in the WordPress plugin directory support forum:
|
||||
[http://wordpress.org/support/plugin/loco-translate](http://wordpress.org/support/plugin/loco-translate)
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Note that the actual name of the plugin is "loco-translate" not "wp-loco". It's renamed on Github to differentiate it as a WordPress plugin.
|
||||
|
||||
Add the plugin to your WordPress project via Git as follows:
|
||||
|
||||
$ git submodule add git@github.com:loco/wp-loco.git wp-content/plugins/loco-translate
|
||||
|
||||
If you want to use a stable release listed in the WordPress plugin directory, you can checkout by tag, e.g:
|
||||
|
||||
$ cd wp-content/plugins/loco-translate
|
||||
$ git fetch origin --tags
|
||||
$ git checkout tags/x.y.z
|
||||
|
||||
Be sure to check out the latest version, replacing `x.y.z` in above example with the release number shown below.
|
||||
|
||||
[](https://github.com/loco/wp-loco/releases)
|
||||
|
||||
## Contributing
|
||||
|
||||
There is no issue tracker here. Please submit bugs or feature requests in the [WordPress support forum](http://wordpress.org/support/plugin/loco-translate).
|
||||
|
||||
The Github repository is for people who want the latest development version of the plugin and prefer Git to [SVN](http://plugins.svn.wordpress.org/loco-translate/trunk/). This is not a collaborative project and there are no resources available for examining pull requests.
|
2044
vendor/loco-translate/languages/loco-translate.pot
vendored
Normal file
5
vendor/loco-translate/lib/compiled/README.md
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Compiled libraries
|
||||
|
||||
These files are built from the Loco core. Do not edit!
|
||||
|
||||
They've been converted down for PHP 5.2 compatibility in WordPress.
|
46
vendor/loco-translate/lib/compiled/gettext.php
vendored
Normal file
5
vendor/loco-translate/lib/compiled/locales.php
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
/**
|
||||
* Downgraded for PHP 5.2 compatibility. Do not edit.
|
||||
*/
|
||||
function loco_parse_wp_locale( $tag ){ if( ! preg_match( '/^([a-z]{2,3})(?:[-_]([a-z]{2}))?(?:[-_]([a-z0-9]{3,8}))?$/i', $tag, $tags ) ){ throw new InvalidArgumentException('Invalid WordPress locale: '.json_encode($tag) ); } $data = array( 'lang' => strtolower( $tags[1] ), ); if( isset($tags[2]) && ( $subtag = $tags[2] ) ){ $data['region'] = strtoupper($tags[2]); } if( isset($tags[3]) && ( $subtag = $tags[3] ) ){ $data['variant'] = strtolower($tags[3]); } return $data; }
|
6
vendor/loco-translate/lib/compiled/phpunit.php
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Downgraded for PHP 5.2 compatibility. Do not edit.
|
||||
*/
|
||||
class LocoDomQuery extends ArrayIterator { public static function parse( $source ){ $dom = new DOMDocument('1.0', 'UTF-8' ); $dom->preserveWhitespace = true; $dom->formatOutput = false; $source = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body>'.$source.'</body></html>'; $used_errors = libxml_use_internal_errors(true); $opts = LIBXML_HTML_NODEFDTD; $parsed = $dom->loadHTML( $source, $opts ); $errors = libxml_get_errors(); $used_errors || libxml_use_internal_errors(false); libxml_clear_errors(); if( $errors || ! $parsed ){ $e = new Loco_error_ParseException('Unknown parse error'); foreach( $errors as $error ){ $e = new Loco_error_ParseException( trim($error->message) ); $e->setContext( $error->line, $error->column, $source ); if( LIBXML_ERR_FATAL === $error->level ){ throw $e; } } if( ! $parsed ){ throw $e; } } return $dom; } public function __construct( $value ){ if( $value instanceof DOMDocument ){ $value = array( $value->documentElement ); } else if( $value instanceof DOMNode ){ $value = array( $value ); } if( is_iterable($value) ){ $nodes = array(); foreach( $value as $node ){ $nodes[] = $node; } } else if( is_string($value) || method_exists($value,'__toString') ){ $value = self::parse( $value ); $nodes = array( $value->documentElement ); } else { $type = is_object($value) ? get_class($value) : gettype($value); throw new InvalidArgumentException('Cannot construct DOM from '.$type ); } parent::__construct( $nodes ); } public function eq( $index ){ $q = new LocoDomQuery(array()); if( $el = $this[$index] ){ $q[] = $el; } return $q; } public function find( $value ){ $q = new LocoDomQuery( array() ); $f = new _LocoDomQueryFilter($value); foreach( $this as $el ){ foreach( $f->filter($el) as $match ){ $q[] = $match; } } return $q; } public function children(){ $q = new LocoDomQuery(array()); foreach( $this as $el ){ if( $el instanceof DOMNode ){ foreach( $el->childNodes as $child ) { $q[] = $child; } } } return $q; } public function text(){ $s = ''; foreach( $this as $el ){ $s .= $el->textContent; } return $s; } public function html(){ $s = ''; foreach( $this as $outer ){ foreach( $outer->childNodes as $inner ){ $s .= $inner->ownerDocument->saveXML($inner); } break; } return $s; } public function attr( $name ){ foreach( $this as $el ){ return $el->getAttribute($name); } return null; } public function serialize(){ $pairs = array(); foreach( array('input','select','textarea','button') as $type ){ foreach( $this->find($type) as $field ){ $name = $field->getAttribute('name'); if( ! $name ){ continue; } if( $field->hasAttribute('type') ){ $type = $field->getAttribute('type'); } if( 'select' === $type ){ $value = null; $f = new _LocoDomQueryFilter('option'); foreach( $f->filter($field) as $option ){ if( $option->hasAttribute('value') ){ $_value = $option->getAttribute('value'); } else { $_value = $option->nodeValue; } if( $option->hasAttribute('selected') ){ $value = $_value; break; } else if( is_null($value) ){ $value = $_value; } } if( is_null($value) ){ $value = ''; } } else if( 'checkbox' === $type || 'radio' === $type ){ if( $field->hasAttribute('checked') ){ $value = $field->getAttribute('value'); } else { continue; } } else if( 'file' === $type ){ $value = ''; } else if( $field->hasAttribute('value') ){ $value = $field->getAttribute('value'); } else { $value = $field->textContent; } $pairs[] = sprintf('%s=%s', rawurlencode($name), rawurlencode($value) ); } } return implode('&',$pairs); } }
|
||||
class _LocoDomQueryFilter { private $tag; private $attr = array(); public function __construct( $value ){ $id = '[-_a-z][-_a-z0-9]*'; if( ! preg_match('/^([a-z1-6]*)(#'.$id.')?(\.'.$id.')?(\[(\w+)="(.+)"\])?$/i', $value, $r ) ){ throw new InvalidArgumentException('Bad filter, '.$value ); } if( $r[1] ){ $this->tag = $r[1]; } if( ! empty($r[2]) ){ $this->attr['id'] = substr($r[2],1); } if( ! empty($r[3]) ){ $this->attr['class'] = substr($r[3],1); } if( ! empty($r[4]) ){ $this->attr[ $r[5] ] = $r[6]; } } public function filter( DOMElement $el ){ if( $this->tag ){ $list = $el->getElementsByTagName($this->tag); $recursive = false; } else { $list = $el->childNodes; $recursive = true; } if( $this->attr ){ $list = $this->reduce( $list, new ArrayIterator, $recursive )->getArrayCopy(); } return $list; } public function reduce( DOMNodeList $list, ArrayIterator $reduced, $recursive ){ foreach( $list as $node ){ if( $node instanceof DOMElement ){ $matched = false; foreach( $this->attr as $name => $value ){ if( ! $node->hasAttribute($name) ){ $matched = false; break; } $values = array_flip( explode(' ', $node->getAttribute($name) ) ); if( ! isset($values[$value]) ){ $matched = false; break; } $matched = true; } if( $matched ){ $reduced[] = $node; } if( $recursive && $node->hasChildNodes() ){ $this->reduce( $node->childNodes, $reduced, true ); } } } return $reduced; } }
|
5
vendor/loco-translate/lib/data/languages.php
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
/**
|
||||
* Compiled data. Do not edit.
|
||||
*/
|
||||
return array('aa'=>'Afar','ab'=>'Abkhazian','ae'=>'Avestan','af'=>'Afrikaans','ak'=>'Akan','am'=>'Amharic','an'=>'Aragonese','ar'=>'Arabic','arq'=>'Algerian Arabic','ary'=>'Moroccan Arabic','as'=>'Assamese','ast'=>'Asturian','av'=>'Avaric','ay'=>'Aymara','az'=>'Azerbaijani','azb'=>'South Azerbaijani','ba'=>'Bashkir','bal'=>'Baluchi','bcc'=>'Southern Balochi','be'=>'Belarusian','bg'=>'Bulgarian','bi'=>'Bislama','bm'=>'Bambara','bn'=>'Bengali','bo'=>'Tibetan','br'=>'Breton','bs'=>'Bosnian','ca'=>'Catalan','ce'=>'Chechen','ceb'=>'Cebuano','ch'=>'Chamorro','ckb'=>'Central Kurdish','co'=>'Corsican','cr'=>'Cree','cs'=>'Czech','cu'=>'Church Slavic','cv'=>'Chuvash','cy'=>'Welsh','da'=>'Danish','de'=>'German','dv'=>'Dhivehi','dz'=>'Dzongkha','ee'=>'Ewe','el'=>'Greek','en'=>'English','eo'=>'Esperanto','es'=>'Spanish','et'=>'Estonian','eu'=>'Basque','fa'=>'Persian','ff'=>'Fulah','fi'=>'Finnish','fj'=>'Fijian','fo'=>'Faroese','fr'=>'French','frp'=>'Arpitan','fuc'=>'Pulaar','fur'=>'Friulian','fy'=>'Western Frisian','ga'=>'Irish','gd'=>'Scottish Gaelic','gl'=>'Galician','gn'=>'Guarani','gsw'=>'Swiss German','gu'=>'Gujarati','gv'=>'Manx','ha'=>'Hausa','haw'=>'Hawaiian','haz'=>'Hazaragi','he'=>'Hebrew','hi'=>'Hindi','ho'=>'Hiri Motu','hr'=>'Croatian','ht'=>'Haitian','hu'=>'Hungarian','hy'=>'Armenian','hz'=>'Herero','ia'=>'Interlingua','id'=>'Indonesian','ie'=>'Interlingue','ig'=>'Igbo','ii'=>'Sichuan Yi','ik'=>'Inupiaq','io'=>'Ido','is'=>'Icelandic','it'=>'Italian','iu'=>'Inuktitut','ja'=>'Japanese','jv'=>'Javanese','ka'=>'Georgian','kab'=>'Kabyle','kg'=>'Kongo','ki'=>'Kikuyu','kj'=>'Kuanyama','kk'=>'Kazakh','kl'=>'Kalaallisut','km'=>'Central Khmer','kn'=>'Kannada','ko'=>'Korean','kr'=>'Kanuri','ks'=>'Kashmiri','ku'=>'Kurdish','kv'=>'Komi','kw'=>'Cornish','ky'=>'Kirghiz','la'=>'Latin','lb'=>'Luxembourgish','lg'=>'Ganda','li'=>'Limburgan','ln'=>'Lingala','lo'=>'Lao','lt'=>'Lithuanian','lu'=>'Luba-Katanga','lv'=>'Latvian','mg'=>'Malagasy','mh'=>'Marshallese','mi'=>'Maori','mk'=>'Macedonian','ml'=>'Malayalam','mn'=>'Mongolian','mr'=>'Marathi','ms'=>'Malay','mt'=>'Maltese','my'=>'Burmese','na'=>'Nauru','nb'=>'Norwegian Bokmål','nd'=>'North Ndebele','ne'=>'Nepali','ng'=>'Ndonga','nl'=>'Dutch','nn'=>'Norwegian Nynorsk','no'=>'Norwegian','nr'=>'South Ndebele','nv'=>'Navajo','ny'=>'Nyanja','oc'=>'Occitan (post 1500)','oj'=>'Ojibwa','om'=>'Oromo','or'=>'Oriya','ory'=>'Oriya (individual language)','os'=>'Ossetian','pa'=>'Panjabi','pi'=>'Pali','pl'=>'Polish','ps'=>'Pushto','pt'=>'Portuguese','qu'=>'Quechua','rhg'=>'Rohingya','rm'=>'Romansh','rn'=>'Rundi','ro'=>'Romanian','ru'=>'Russian','rue'=>'Rusyn','rup'=>'Macedo-Romanian','rw'=>'Kinyarwanda','sa'=>'Sanskrit','sah'=>'Yakut','sc'=>'Sardinian','sd'=>'Sindhi','se'=>'Northern Sami','sg'=>'Sango','sh'=>'Serbo-Croatian','si'=>'Sinhala','sk'=>'Slovak','sl'=>'Slovenian','sm'=>'Samoan','sn'=>'Shona','so'=>'Somali','sq'=>'Albanian','sr'=>'Serbian','ss'=>'Swati','st'=>'Southern Sotho','su'=>'Sundanese','sv'=>'Swedish','sw'=>'Swahili','szl'=>'Silesian','ta'=>'Tamil','te'=>'Telugu','tg'=>'Tajik','th'=>'Thai','ti'=>'Tigrinya','tk'=>'Turkmen','tl'=>'Tagalog','tn'=>'Tswana','to'=>'Tonga (Tonga Islands)','tr'=>'Turkish','ts'=>'Tsonga','tt'=>'Tatar','tw'=>'Twi','twd'=>'Twents','ty'=>'Tahitian','tzm'=>'Central Atlas Tamazight','ug'=>'Uighur','uk'=>'Ukrainian','ur'=>'Urdu','uz'=>'Uzbek','ve'=>'Venda','vi'=>'Vietnamese','vo'=>'Volapük','wa'=>'Walloon','wo'=>'Wolof','xh'=>'Xhosa','xmf'=>'Mingrelian','yi'=>'Yiddish','yo'=>'Yoruba','za'=>'Zhuang','zh'=>'Chinese','zu'=>'Zulu','tlh'=>'Klingon');
|
5
vendor/loco-translate/lib/data/locales.php
vendored
Normal file
5
vendor/loco-translate/lib/data/plurals.php
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
/**
|
||||
* Compiled data. Do not edit.
|
||||
*/
|
||||
return array('ak'=>1,'am'=>1,'ar'=>2,'ary'=>2,'be'=>3,'bm'=>4,'bo'=>4,'br'=>1,'bs'=>3,'cs'=>5,'cy'=>6,'dz'=>4,'ff'=>1,'fr'=>1,'ga'=>7,'gd'=>8,'gv'=>9,'hr'=>10,'id'=>4,'ii'=>4,'iu'=>11,'ja'=>4,'ka'=>4,'kk'=>4,'km'=>4,'kn'=>4,'ko'=>4,'kw'=>11,'ky'=>4,'ln'=>1,'lo'=>4,'lt'=>12,'lv'=>13,'mg'=>1,'mi'=>1,'mk'=>14,'ms'=>4,'mt'=>15,'my'=>4,'nr'=>4,'oc'=>1,'pl'=>16,'ro'=>17,'ru'=>3,'sa'=>11,'sg'=>4,'sk'=>5,'sl'=>18,'sm'=>4,'sr'=>3,'su'=>4,'th'=>4,'ti'=>1,'tl'=>1,'to'=>4,'tt'=>4,'ug'=>4,'uk'=>3,'vi'=>4,'wa'=>1,'wo'=>4,'yo'=>4,'zh'=>4,''=>array(0=>array(0=>'n != 1',1=>array(0=>'one',1=>'other')),1=>array(0=>'n > 1',1=>array(0=>'one',1=>'other')),2=>array(0=>'n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100 >= 3 && n%100<=10 ? 3 : n%100 >= 11 && n%100<=99 ? 4 : 5',1=>array(0=>'zero',1=>'one',2=>'two',3=>'few',4=>'many',5=>'other')),3=>array(0=>'(n%10==1 && n%100!=11 ? 0 : n%10 >= 2 && n%10<=4 &&(n%100<10||n%100 >= 20)? 1 : 2)',1=>array(0=>'one',1=>'few',2=>'other')),4=>array(0=>'0',1=>array(0=>'other')),5=>array(0=>'( n == 1 ) ? 0 : ( n >= 2 && n <= 4 ) ? 1 : 2',1=>array(0=>'one',1=>'few',2=>'other')),6=>array(0=>'n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n==3 ? 3 : n==6 ? 4 : 5',1=>array(0=>'zero',1=>'one',2=>'two',3=>'few',4=>'many',5=>'other')),7=>array(0=>'n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4',1=>array(0=>'one',1=>'two',2=>'few',3=>'many',4=>'other')),8=>array(0=>'n==1||n==11 ? 0 : n==2||n==12 ? 1 :(n >= 3 && n<=10)||(n >= 13 && n<=19)? 2 : 3',1=>array(0=>'one',1=>'two',2=>'few',3=>'other')),9=>array(0=>'n%10==1 ? 0 : n%10==2 ? 1 : n%20==0 ? 2 : 3',1=>array(0=>'one',1=>'two',2=>'few',3=>'other')),10=>array(0=>'n%10==1 && n%100!=11 ? 0 : n%10 >= 2 && n%10<=4 &&(n%100<10||n%100 >= 20)? 1 : 2',1=>array(0=>'one',1=>'few',2=>'other')),11=>array(0=>'n == 1 ? 0 : n == 2 ? 1 : 2',1=>array(0=>'one',1=>'two',2=>'other')),12=>array(0=>'(n%10==1 && n%100!=11 ? 0 : n%10 >= 2 &&(n%100<10||n%100 >= 20)? 1 : 2)',1=>array(0=>'one',1=>'few',2=>'other')),13=>array(0=>'n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2',1=>array(0=>'one',1=>'other',2=>'zero')),14=>array(0=>'( n % 10 == 1 && n % 100 != 11 ) ? 0 : 1',1=>array(0=>'one',1=>'other')),15=>array(0=>'(n==1 ? 0 : n==0||( n%100>1 && n%100<11)? 1 :(n%100>10 && n%100<20)? 2 : 3)',1=>array(0=>'one',1=>'few',2=>'many',3=>'other')),16=>array(0=>'(n==1 ? 0 : n%10 >= 2 && n%10<=4 &&(n%100<10||n%100 >= 20)? 1 : 2)',1=>array(0=>'one',1=>'few',2=>'other')),17=>array(0=>'(n==1 ? 0 :(((n%100>19)||(( n%100==0)&&(n!=0)))? 2 : 1))',1=>array(0=>'one',1=>'few',2=>'other')),18=>array(0=>'n%100==1 ? 0 : n%100==2 ? 1 : n%100==3||n%100==4 ? 2 : 3',1=>array(0=>'one',1=>'two',2=>'few',3=>'other'))));
|
5
vendor/loco-translate/lib/data/regions.php
vendored
Normal file
177
vendor/loco-translate/loco.php
vendored
Normal file
|
@ -0,0 +1,177 @@
|
|||
<?php
|
||||
/*
|
||||
Plugin Name: Loco Translate
|
||||
Plugin URI: https://wordpress.org/plugins/loco-translate/
|
||||
Description: Translate themes and plugins directly in WordPress
|
||||
Author: Tim Whitlock
|
||||
Version: 2.4.0
|
||||
Author URI: https://localise.biz/wordpress/plugin
|
||||
Text Domain: loco-translate
|
||||
Domain Path: /languages/
|
||||
*/
|
||||
|
||||
// disallow execution out of context
|
||||
if( ! function_exists('is_admin') ){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get absolute path to Loco primary plugin file
|
||||
* @return string
|
||||
*/
|
||||
function loco_plugin_file(){
|
||||
return __FILE__;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get version of this plugin
|
||||
* @return string
|
||||
*/
|
||||
function loco_plugin_version(){
|
||||
return '2.4.0';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Loco plugin handle, used by WordPress to identify plugin as a relative path
|
||||
* @return string probably "loco-translate/loco.php"
|
||||
*/
|
||||
function loco_plugin_self(){
|
||||
static $handle;
|
||||
isset($handle) or $handle = plugin_basename(__FILE__);
|
||||
return $handle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get absolute path to plugin root directory
|
||||
* @return string __DIR__
|
||||
*/
|
||||
function loco_plugin_root(){
|
||||
static $root;
|
||||
isset($root) or $root = dirname(__FILE__);
|
||||
return $root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether currently running in debug mode
|
||||
* @return bool
|
||||
*/
|
||||
function loco_debugging(){
|
||||
return apply_filters('loco_debug', WP_DEBUG );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Whether currently processing an Ajax request
|
||||
* @return bool
|
||||
*/
|
||||
function loco_doing_ajax(){
|
||||
return defined('DOING_AJAX') && DOING_AJAX;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate a constant by name
|
||||
* @param string
|
||||
* @return mixed
|
||||
*/
|
||||
function loco_constant( $name ){
|
||||
$value = defined($name) ? constant($name) : null;
|
||||
// constant values will only be modified in tests
|
||||
if( defined('LOCO_TEST') && LOCO_TEST ){
|
||||
$value = apply_filters('loco_constant', $value, $name );
|
||||
$value = apply_filters('loco_constant_'.$name, $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runtime inclusion of any file under plugin root
|
||||
* @param string PHP file path relative to __DIR__
|
||||
* @return mixed return value from included file
|
||||
*/
|
||||
function loco_include( $relpath ){
|
||||
$path = loco_plugin_root().'/'.$relpath;
|
||||
if( ! file_exists($path) ){
|
||||
throw new Loco_error_Exception('File not found: '.$path);
|
||||
}
|
||||
return include $path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Require dependant library once only
|
||||
* @param string PHP file path relative to ./lib
|
||||
* @return void
|
||||
*/
|
||||
function loco_require_lib( $path ){
|
||||
require_once loco_plugin_root().'/lib/'.$path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check PHP extension required by Loco and load polyfill if needed
|
||||
* @param string
|
||||
* @return bool
|
||||
*/
|
||||
function loco_check_extension( $name ) {
|
||||
static $cache = array();
|
||||
if ( ! isset( $cache[$name] ) ) {
|
||||
if ( extension_loaded($name) ) {
|
||||
$cache[ $name ] = true;
|
||||
}
|
||||
else {
|
||||
Loco_error_AdminNotices::warn( sprintf( __('Loco requires the "%s" PHP extension. Ask your hosting provider to install it','loco-translate'), $name ) );
|
||||
$class = 'Loco_compat_'.ucfirst($name).'Extension.php';
|
||||
$cache[$name] = class_exists($class);
|
||||
}
|
||||
}
|
||||
return $cache[ $name ];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class autoloader for Loco classes under src directory.
|
||||
* e.g. class "Loco_foo_FooBar" wil be found in "src/foo/FooBar.php"
|
||||
* Also does autoload for polyfills under "src/compat" if $name < 20 chars
|
||||
*
|
||||
* @internal
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
function loco_autoload( $name ){
|
||||
if( 'Loco_' === substr($name,0,5) ){
|
||||
loco_include( 'src/'.strtr( substr($name,5), '_', '/' ).'.php' );
|
||||
}
|
||||
else if( strlen($name) < 20 ){
|
||||
$path = loco_plugin_root().'/src/compat/'.$name.'.php';
|
||||
if( file_exists($path) ){
|
||||
require $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spl_autoload_register( 'loco_autoload', false );
|
||||
|
||||
|
||||
// provide safe directory for custom translations that won't be deleted during auto-updates
|
||||
if( ! defined('LOCO_LANG_DIR') ){
|
||||
define( 'LOCO_LANG_DIR', trailingslashit(loco_constant('WP_LANG_DIR')).'loco' );
|
||||
}
|
||||
|
||||
|
||||
// text domain loading helper for custom file locations. disable by setting constant empty
|
||||
if( LOCO_LANG_DIR ){
|
||||
new Loco_hooks_LoadHelper;
|
||||
}
|
||||
|
||||
|
||||
// initialize hooks for admin screens
|
||||
if( is_admin() ){
|
||||
new Loco_hooks_AdminHooks;
|
||||
}
|
24
vendor/loco-translate/loco.xml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bundle name="Loco Translate" min-version="2.0.14">
|
||||
<domain name="loco-translate">
|
||||
<project name="Loco Translate" slug="loco-translate">
|
||||
<source>
|
||||
<directory>src</directory>
|
||||
<directory>tpl</directory>
|
||||
<file>loco.php</file>
|
||||
</source>
|
||||
<target>
|
||||
<directory>languages</directory>
|
||||
</target>
|
||||
<template>
|
||||
<file>languages/loco-translate.pot</file>
|
||||
</template>
|
||||
</project>
|
||||
</domain>
|
||||
<exclude>
|
||||
<directory>tmp</directory>
|
||||
<directory>lib</directory>
|
||||
<directory>pub</directory>
|
||||
<directory>test</directory>
|
||||
</exclude>
|
||||
</bundle>
|
1
vendor/loco-translate/pub/css/admin.css
vendored
Normal file
1
vendor/loco-translate/pub/css/bundle.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
form.loco-filter{float:right}@media only screen and (max-width: 1024px){table.wp-list-table a.row-title{max-width:100px}}
|
1
vendor/loco-translate/pub/css/config.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
form#loco-conf>div{overflow:visible;border-bottom:solid 1px #ccc;padding-top:2em}form#loco-conf>div h2{margin-top:0}form#loco-conf td.twin>div{float:left;clear:none;width:50%}form#loco-conf td .description:first-child{margin-top:0;margin-bottom:4px}form#loco-conf a.icon-del{display:block;float:right;z-index:99;color:#aaa;outline:none}form#loco-conf a.icon-del:hover{color:#c00}form#loco-conf>div:first-child a.icon-del{display:none}form#loco-conf p.description{color:#aaa;font-size:12px;text-indent:.25em}form#loco-conf tr:hover p.description{color:#666}form#loco-reset{position:absolute;bottom:0;right:0}
|
1
vendor/loco-translate/pub/css/editor.css
vendored
Normal file
1
vendor/loco-translate/pub/css/fileinfo.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
#loco.wrap .notice-info dl{margin-top:0;display:inline-block}#loco.wrap .notice-info dl dt,#loco.wrap .notice-info dl dd{line-height:1.4em}#loco.wrap .notice-info dl dt{font-weight:bold;color:#555}#loco.wrap .notice-info dl dd{margin-left:0;margin-bottom:.8em}#loco.wrap .notice-info dl div.progress .l{display:none}
|
1
vendor/loco-translate/pub/css/locale.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
#loco.wrap td.loco-not-active{color:#aaa}#loco.wrap div.loco-projects>h3{float:left}#loco.wrap div.loco-projects form.loco-filter{float:right;margin:1em 0}
|
1
vendor/loco-translate/pub/css/podiff.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
#loco.wrap .revisions-diff{padding:10px;min-height:20px}#loco.wrap table.diff{border-collapse:collapse}#loco.wrap table.diff td{white-space:nowrap;overflow:hidden;font:normal 12px/17px "Monaco","Menlo","Ubuntu Mono","Consolas","source-code-pro",monospace;padding:2px}#loco.wrap table.diff td>span{color:#aaa}#loco.wrap table.diff td>span:after{content:". "}#loco.wrap table.diff tbody{border-top:1px dashed #ccc}#loco.wrap table.diff tbody:first-child{border-top:none}#loco.wrap .revisions.loading .diff-meta{color:#eee}#loco.wrap .revisions.loading .loading-indicator span.spinner{visibility:visible;background:#fff url(../img/spin-modal.gif?v=2.4.0) center center no-repeat}#loco.wrap .revisions-meta{clear:both;padding:10px 12px;margin:0;position:relative;top:10px}#loco.wrap .revisions-meta .diff-meta{clear:none;float:left;width:50%;padding:0;min-height:auto}#loco.wrap .revisions-meta .diff-meta button{margin-top:5px}#loco.wrap .revisions-meta .diff-meta-current{float:right;text-align:right}#loco.wrap .revisions-meta time{color:#72777c}#loco.wrap .revisions-control-frame{margin:10px 0}#loco.wrap .revisions-diff-frame{margin-top:20px}
|
1
vendor/loco-translate/pub/css/poinit.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
form#loco-poinit .loco-locales fieldset{float:left;margin-right:2em}form#loco-poinit .loco-locales fieldset.disabled span.lang{visibility:hidden !important}form#loco-poinit .loco-locales fieldset span.nolang{background:#999}form#loco-poinit .loco-locales fieldset>label span{width:20px;text-align:center;display:inline-block;margin-right:4px}form#loco-poinit a.icon-help{color:#999;font-style:normal;text-decoration:none}form#loco-poinit a.icon-help:hover{color:#666}form#loco-poinit .form-table th{padding:15px 10px}form#loco-poinit .form-table tr:first-child td,form#loco-poinit .form-table tr:first-child th{padding-top:25px}form#loco-poinit label.for-disabled input{visibility:hidden}form#loco-poinit label.for-disabled .icon-lock{top:0;left:0;display:block;position:absolute;width:1em;font-size:14px;text-align:center;color:gray}
|
1
vendor/loco-translate/pub/css/poview.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.js #loco.wrap .loco-loading{min-height:100px;background:#fff url(../img/spin-modal.gif?v=2.4.0) center center no-repeat}.js #loco.wrap .loco-loading ol.msgcat{display:none}#loco.wrap #loco-po{padding-right:0;overflow:auto}#loco.wrap ol.msgcat{margin-left:3em;padding-top:1em;border-top:1px dashed #ccc}#loco.wrap ol.msgcat:first-child{padding-top:0;border-top:none}#loco.wrap ol.msgcat li{color:#aaa;margin:0;padding:0 0 0 1em;font:normal 12px/17px "Monaco","Menlo","Ubuntu Mono","Consolas","source-code-pro",monospace;border-left:1px solid #eee}#loco.wrap ol.msgcat li>*{color:#333;white-space:pre}#loco.wrap ol.msgcat li>.po-comment{color:#3cc200}#loco.wrap ol.msgcat li>.po-refs{color:#0073aa}#loco.wrap ol.msgcat li>.po-refs a{color:inherit;text-decoration:none}#loco.wrap ol.msgcat li>.po-refs a:hover{text-decoration:underline}#loco.wrap ol.msgcat li>.po-flags{color:#77904a}#loco.wrap ol.msgcat li>.po-flags em{font-style:normal}#loco.wrap ol.msgcat li>.po-word{color:#000}#loco.wrap ol.msgcat li>.po-junk{font-style:italic;color:#ccc}#loco.wrap ol.msgcat li>.po-string>span{color:#c931c7}#loco.wrap form.loco-filter{top:0;right:0;position:absolute}#loco.wrap .loco-invalid form.loco-filter input[type=text]:focus{border-color:#c00;-webkit-box-shadow:0 0 2px rgba(153,0,0,.5);-moz-box-shadow:0 0 2px rgba(153,0,0,.5);box-shadow:0 0 2px rgba(153,0,0,.5)}#loco.wrap .loco-invalid ol.msgcat{list-style-type:none}#loco.wrap .loco-invalid ol.msgcat li{color:#000}
|
1
vendor/loco-translate/pub/css/skins/blue.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(9,100,132,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#096484}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/blue/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
1
vendor/loco-translate/pub/css/skins/coffee.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(199,165,137,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#c7a589}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/coffee/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
1
vendor/loco-translate/pub/css/skins/ectoplasm.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(163,183,69,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#a3b745}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/ectoplasm/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
1
vendor/loco-translate/pub/css/skins/light.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(136,136,136,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#888}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/light/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
1
vendor/loco-translate/pub/css/skins/midnight.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(225,77,67,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#e14d43}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/midnight/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
1
vendor/loco-translate/pub/css/skins/ocean.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(158,186,160,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#9ebaa0}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/ocean/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
1
vendor/loco-translate/pub/css/skins/sunrise.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.wrap #loco-editor .is-table .wg-tr:nth-child(even){background-color:rgba(221,130,59,.05)}.wrap #loco-editor .wg-split-x>nav.wg-tabs>a.active,.wrap #loco-editor .is-table .wg-cols>div>div.selected{background-color:#dd823b}.wrap #loco-editor .is-editable>.wg-content>textarea:focus,.wrap #loco-editor .is-editable>.wg-content.has-focus .ace_scroller,.wrap #loco-editor .is-editable>.wg-content.has-focus .mce-content-body{border-color:#5b9dd9;-webkit-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);-moz-box-shadow:inset 0 0 .6em rgba(30,140,190,.8);box-shadow:inset 0 0 .6em rgba(30,140,190,.8)}form button.loco-loading.button-primary[disabled]:before{background:transparent url(../../img/skins/sunrise/spin-primary-button.gif?v=2.4.0) 0 0 no-repeat !important}
|
BIN
vendor/loco-translate/pub/font/loco.eot
vendored
Normal file
111
vendor/loco-translate/pub/font/loco.svg
vendored
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
vendor/loco-translate/pub/font/loco.ttf
vendored
Normal file
BIN
vendor/loco-translate/pub/font/loco.woff
vendored
Normal file
BIN
vendor/loco-translate/pub/img/api/google.png
vendored
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
vendor/loco-translate/pub/img/api/microsoft.png
vendored
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
vendor/loco-translate/pub/img/flags.png
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
vendor/loco-translate/pub/img/logo-foot.gif
vendored
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
vendor/loco-translate/pub/img/skins/blue/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/coffee/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/ectoplasm/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/fresh/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/light/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/midnight/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/ocean/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/skins/sunrise/spin-primary-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/spin-editor-button.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/spin-modal.gif
vendored
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
vendor/loco-translate/pub/img/wg/splitx.png
vendored
Normal file
After Width: | Height: | Size: 87 B |
BIN
vendor/loco-translate/pub/img/wg/splity.png
vendored
Normal file
After Width: | Height: | Size: 90 B |
196
vendor/loco-translate/pub/js/min/admin.js
vendored
Normal file
|
@ -0,0 +1,196 @@
|
|||
(function(r,s,k,R){var n=function(){function f(d){throw Error("Failed to require "+d);}var d={};return{register:function(f,m){d[f]=m},require:function(k,m){return d[k]||f(m)},include:function(k,m,g){return d[k]||(g?f(m):null)}}}();n.register("$1",function(f,d,k){function m(g){var c=typeof g;if("string"===c)if(/[^ <>!=()%^&|?:n0-9]/.test(g))console.error("Invalid plural: "+g);else return new Function("n","return "+g);"function"!==c&&(g=function(b){return 1!=b});return g}f.init=function(g){function c(a,
|
||||
l,c){return(a=b[a])&&a[c]?a[c]:l||""}g=m(g);var b={};return{_:function(a){return c(a,a,0)},_x:function(a,b){return c(b+"\u0004"+a,a,0)},_n:function(a,b,e){e=Number(g(e));isNaN(e)&&(e=0);return c(a,e?b:a,e)},load:function(a){b=a||{};return this},pluraleq:function(a){g=m(a);return this}}};return f}({},r,s));n.register("$2",function(f,d,n){f.ie=function(){var d=k&&k.browser||{},g=d.msie&&11>Number(d.version),d=null;return function(){return g}}();f.init=function(){return f};return f}({},r,s));n.register("$3",
|
||||
function(f,d,k){Number.prototype.format=function(d){d=Math.pow(10,d||0);var g=Math.round(d*this)/d;d=[];var g=String(g),c=g.split("."),g=c[0],c=c[1],b=g.length;do d.unshift(g.substring(b-3,b));while(0<(b-=3));g=d.join(",");if(d=c){d=c;for(var a,c=d.length;"0"===d.charAt(--c);)a=c;a&&(d=d.substring(0,a));d=c=d}d&&(g+="."+c);return g};Number.prototype.percent=function(d){var g=0,c=this&&d?100*(this/d):0;if(0===c)return"0";if(100===c)return"100";if(99<c)c=Math.min(c,99.9),d=c.format(++g);else if(0.5>
|
||||
c){c=Math.max(c,1E-4);do d=c.format(++g);while("0"===d&&4>g);d=d.substr(1)}else d=c.format(0);return d};return f}({},r,s));n.register("$4",function(f,d,k){Array.prototype.indexOf||(Array.prototype.indexOf=function(d){if(null==this)throw new TypeError;var g,c=Object(this),b=c.length>>>0;if(0===b)return-1;g=0;1<arguments.length&&(g=Number(arguments[1]),g!=g?g=0:0!=g&&Infinity!=g&&-Infinity!=g&&(g=(0<g||-1)*Math.floor(Math.abs(g))));if(g>=b)return-1;for(g=0<=g?g:Math.max(b-Math.abs(g),0);g<b;g++)if(g in
|
||||
c&&c[g]===d)return g;return-1});return f}({},r,s));n.register("$5",function(f,d,k){f.trim=function(d,g){for(g||(g=" \n");d&&-1!==g.indexOf(d.substr(0,1));)d=d.substr(1);for(;d&&-1!==g.indexOf(d.substr(-1));)d=d.substr(0,d.length-1);return d};f.sprintf=function(d){var g=0,c,b=[].slice.call(arguments,1);return d.replace(/%([sud%])/g,function(a,l){if("%"===l)return"%";c=b[g++];return String(c)||""})};return f}({},r,s));n.register("$20",function(f,d,k){function m(g){return function(c,b){for(var a=c[g]||
|
||||
0;(c=c.offsetParent)&&c!==(b||k.body);)a+=c[g]||0;return a}}f.top=m("offsetTop");f.left=m("offsetLeft");f.el=function(g,c){var b=k.createElement(g||"div");c&&(b.className=c);return b};f.txt=function(g){return k.createTextNode(g||"")};return f}({},r,s));n.register("$6",function(f,d,E){function m(a,b,c){function l(){e();w=setTimeout(b,c)}function e(){w&&clearTimeout(w);w=null}var w;l();k(a).mouseenter(e).mouseleave(l);return{die:function(){e();k(a).off("mouseenter mouseleave")}}}function g(a,b){a.fadeTo(b,
|
||||
0,function(){a.slideUp(b,function(){a.remove();k(d).triggerHandler("resize")})});return a}function c(a,b){function c(b){p[w]=null;g(k(a),250);e&&e.die();var l;if(l=b)b.stopPropagation(),b.preventDefault(),l=!1;return l}function l(b){e&&e.die();return e=m(a,c,b)}var e,w,v,B=k(a),q=B.find("button");0===q.length&&(B.addClass("is-dismissible"),q=k('<button type="button" class="notice-dismiss"> </a>').appendTo(B));q.off("click").click(c);k(d).triggerHandler("resize");h();w=p.length;p.push(c);b&&(e=l(b));
|
||||
return{link:function(b,l){var c=l||b,e=k(a).find("nav"),c=k("<nav></nav>").append(k("<a></a>").attr("href",b).text(c));v?(v.push(c.html()),e.html(v.join("<span> | </span>"))):(v=[c.html()],k(a).addClass("has-nav").append(c));return this},stick:function(){e&&e.die();e=null;p[w]=null;return this},slow:function(a){l(a||1E4);return this}}}function b(a,b,c){var l=n.require("$20","dom.js").el;a=k('<div class="notice notice-'+a+' loco-notice inline"></div>').prependTo(k("#loco-notices"));var e=k(l("p"));
|
||||
c=k(l("span")).text(c);b=k(l("strong","has-icon")).text(b+": ");e.append(b).append(c).appendTo(a);return a}function a(a,l,e,w){a=b(e,l,a).css("opacity","0").fadeTo(500,1);k(d).triggerHandler("resize");return c(a,w)}function l(b){return a(b,D,"warning")}function e(){k("#loco-notices").find("div.notice").each(function(a,b){if(-1===b.className.indexOf("jshide")){var l=-1===b.className.indexOf("notice-success")?null:5E3;c(b,l)}})}var p=[],h=Date.now||function(){return(new Date).getTime()},v,D,q,w;f.error=
|
||||
function(b){return a(b,v,"error")};f.warn=l;f.info=function(b){return a(b,q,"info")};f.success=function(b){return a(b,w,"success",5E3)};f.warning=l;f.log=function(){d.console&&console.log&&console.log.apply(console,arguments)};f.debug=function(a,b){d.console&&console.error&&(console.error("Loco Error: "+a),b&&console.debug&&console.debug(b))};f.clear=function(){for(var a=-1,b,l=p,c=l.length;++a<c;)(b=l[a])&&b.call&&b();p=[];return f};f.create=b;f.raise=function(a){(f[a.type]||f.error).call(f,a.message)};
|
||||
f.convert=c;f.init=function(a){v=a._("Error");D=a._("Warning");q=a._("Notice");w=a._("OK");setTimeout(e,1E3);return f};return f}({},r,s));n.register("$7",function(f,d,E){function m(a){var b=k("<pre>"+a+"</pre>").text();b&&(b=b.replace(/[\r\n]+/g,"\n").replace(/(^|\n)\s+/g,"$1").replace(/\s+$/,""));b||(b=a)||(b="Blank response from server");return b}function g(a){return(a=a.split(/[\r\n]/)[0])?(a=a.replace(/ +in +\S+ on line \d+/,""),a=a.replace(/^[()! ]+Fatal error:\s*/,"")):t._("Server returned invalid data")}
|
||||
function c(a,b,l){a[b]=l}function b(a,b,l){a.push({name:b,value:l})}function a(a,b,l){a.append(b,l)}function l(a,b,l,c){function e(b,c,v){if("abort"!==c){var d=p||{_:function(a){return a}},B=b.status,u=b.responseText,A=m(u),q=b.getResponseHeader("Content-Type")||"text/html",f=b.getResponseHeader("Content-Length")||u.length;"success"===c&&v?z.error(v):(z.error(g(A)+".\n"+d._("Check console output for debugging information")),z.debug("Ajax failure for "+a,{status:B,error:c,message:v,output:u}),"parsererror"===
|
||||
c&&(v="Response not JSON"),z.log([d._("Provide the following text when reporting a problem")+":","----","Status "+B+' "'+(v||d._("Unknown error"))+'" ('+q+" "+f+" bytes)",A,"===="].join("\n")));l&&l.call&&l(b,c,v);h=b}}c.url=v;c.dataType="json";var z=n.require("$6","notices.js").clear();h=null;return k.ajax(c).fail(e).done(function(a,l,c){var w=a&&a.data,h=a&&a.notices,v=h&&h.length;for(!w||a.error?e(c,l,a&&a.error&&a.error.message):b&&b(w,l,c);v--;)z.raise(h[v])})}var e={},p,h,v=d.ajaxurl||"/wp-admin/admin-ajax.php";
|
||||
f.init=function(a){e=a.nonces||e;return f};f.localise=function(a){p=a;return f};f.xhr=function(){return h};f.strip=m;f.parse=g;f.submit=function(a,b,c){function e(a,b){b.disabled?b.setAttribute("data-was-disabled","true"):b.disabled=!0}function h(a,b){b.getAttribute("data-was-disabled")||(b.disabled=!1)}function v(a){a.find(".button-primary").removeClass("loading");a.find("button").each(h);a.find("input").each(h);a.find("select").each(h);a.find("textarea").each(h);a.removeClass("disabled loading")}
|
||||
var g=k(a),p=g.serialize();(function(a){a.find(".button-primary").addClass("loading");a.find("button").each(e);a.find("input").each(e);a.find("select").each(e);a.find("textarea").each(e);a.addClass("disabled loading")})(g);return l(a.route.value,function(a,l,c){v(g);b&&b(a,l,c)},function(a,b,l){v(g);c&&c(a,b,l)},{type:a.method,data:p})};f.post=function(h,v,w,g){var p,z=!0;v=v||{};(p=e[h])||(d.console&&console.error&&console.error('No nonce for "'+h+'"'),p="");var H=p;d.FormData&&v instanceof FormData?
|
||||
(z=!1,p=a):p=Array.isArray(v)?b:c;p(v,"action","loco_json");p(v,"route",h);p(v,"loco-nonce",H);return l(h,w,g,{type:"post",data:v,processData:z,contentType:z?"application/x-www-form-urlencoded; charset=UTF-8":!1})};f.setNonce=function(a,b){e[a]=b;return f};return f}({},r,s));n.register("$21",{arab:1,aran:1,hebr:1,nkoo:1,syrc:1,syrn:1,syrj:1,syre:1,samr:1,mand:1,mend:1,thaa:1,adlm:1,cprt:1,phnx:1,armi:1,prti:1,phli:1,phlp:1,phlv:1,avst:1,mani:1,khar:1,orkh:1,ital:1,lydi:1,ar:1,ary:1,ckb:1,dv:1,fa:1,
|
||||
he:1,nqo:1,ps:1,ur:1,yi:1});n.register("$8",function(f,d,k){function m(){}var g,c=n.require("$21","rtl.json");f.init=function(){return new m};f.cast=function(b){return b instanceof m?b:"string"===typeof b?f.parse(b):f.clone(b)};f.clone=function(b){var a,l=new m;for(a in b)l[a]=b[a];return l};f.parse=function(b){if(!(g||(g=/^([a-z]{2,3})(?:[-_]([a-z]{2}))?(?:[-_]([a-z0-9]{3,8}))?$/i)).exec(b))return null;var a=new m;a.lang=RegExp.$1.toLowerCase();if(b=RegExp.$2)a.region=b.toUpperCase();if(b=RegExp.$3)a.variant=
|
||||
b.toLowerCase();return a};d=m.prototype;d.isValid=function(){return!!this.lang};d.isKnown=function(){var b=this.lang;return!(!b||"zxx"===b)};d.toString=function(b){b=b||"-";var a,l=this.lang||"zxx";if(a=this.region)l+=b+a;if(a=this.variant)l+=b+a;return l};d.getIcon=function(){for(var b=3,a,l,c=["variant","region","lang"],p=[];0!==b--;)if(a=c[b],l=this[a])p.push(a),p.push(a+"-"+l.toLowerCase());return p.join(" ")};d.isRTL=function(){return!!c[String(this.lang).toLowerCase()]};d=null;return f}({},
|
||||
r,s));n.register("$22",{"\u00e1":"a","\u00e0":"a","\u0103":"a","\u1eaf":"a","\u1eb1":"a","\u1eb5":"a","\u1eb3":"a","\u00e2":"a","\u1ea5":"a","\u1ea7":"a","\u1eab":"a","\u1ea9":"a","\u01ce":"a","\u00e5":"a","\u01fb":"a","\u00e4":"a","\u01df":"a","\u00e3":"a","\u0227":"a","\u01e1":"a","\u0105":"a","\u0101":"a","\u1ea3":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1eb7":"a","\u1ead":"a","\u1e01":"a","\u01fd":"\u00e6","\u01e3":"\u00e6","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0107":"c","\u0109":"c",
|
||||
"\u010d":"c","\u010b":"c","\u00e7":"c","\u1e09":"c","\u010f":"d","\u1e0b":"d","\u1e11":"d","\u0111":"d","\u1e0d":"d","\u1e13":"d","\u1e0f":"d","\u00f0":"d","\ua77a":"d","\u01c6":"\u01f3","\u00e9":"e","\u00e8":"e","\u0115":"e","\u00ea":"e","\u1ebf":"e","\u1ec1":"e","\u1ec5":"e","\u1ec3":"e","\u011b":"e","\u00eb":"e","\u1ebd":"e","\u0117":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u0113":"e","\u1e17":"e","\u1e15":"e","\u1ebb":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u1e19":"e","\u1e1b":"e",
|
||||
"\u1e1f":"f","\ua77c":"f","\u01f5":"g","\u011f":"g","\u011d":"g","\u01e7":"g","\u0121":"g","\u0123":"g","\u1e21":"g","\ua7a1":"g","\u1d79":"g","\u0125":"h","\u021f":"h","\u1e27":"h","\u1e23":"h","\u1e29":"h","\u0127":"h","\u210f":"h","\u1e25":"h","\u1e2b":"h","\u1e96":"h","\u00ed":"i","\u00ec":"i","\u012d":"i","\u00ee":"i","\u01d0":"i","\u00ef":"i","\u1e2f":"i","\u0129":"i","\u012f":"i","\u012b":"i","\u1ec9":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u1e2d":"i","\u0135":"j","\u01f0":"j","\u1e31":"k",
|
||||
"\u01e9":"k","\u0137":"k","\ua7a3":"k","\u1e33":"k","\u1e35":"k","\u013a":"l","\u013e":"l","\u013c":"l","\u0142":"l","\u1e37":"l","\u1e39":"l","\u1e3d":"l","\u1e3b":"l","\u0140":"l","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0144":"n","\u01f9":"n","\u0148":"n","\u00f1":"n","\u1e45":"n","\u0146":"n","\ua7a5":"n","\u1e47":"n","\u1e4b":"n","\u1e49":"n","\u00f3":"o","\u00f2":"o","\u014f":"o","\u00f4":"o","\u1ed1":"o","\u1ed3":"o","\u1ed7":"o","\u1ed5":"o","\u01d2":"o","\u00f6":"o","\u022b":"o","\u0151":"o",
|
||||
"\u00f5":"o","\u1e4d":"o","\u1e4f":"o","\u022d":"o","\u022f":"o","\u0231":"o","\u00f8":"o","\u01ff":"o","\u01eb":"o","\u01ed":"o","\u014d":"o","\u1e53":"o","\u1e51":"o","\u1ecf":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edb":"o","\u1edd":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u1e55":"p","\u1e57":"p","\u0155":"r","\u0159":"r","\u1e59":"r","\u0157":"r","\ua7a7":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u1e5f":"r","\ua783":"r","\u015b":"s","\u1e65":"s",
|
||||
"\u015d":"s","\u0161":"s","\u1e67":"s","\u1e61":"s","\u015f":"s","\ua7a9":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u017f":"s","\ua785":"s","\u1e9b":"s","\u0165":"t","\u1e97":"t","\u1e6b":"t","\u0163":"t","\u1e6d":"t","\u021b":"t","\u1e71":"t","\u1e6f":"t","\ua787":"t","\u00fa":"u","\u00f9":"u","\u016d":"u","\u00fb":"u","\u01d4":"u","\u016f":"u","\u00fc":"u","\u01d8":"u","\u01dc":"u","\u01da":"u","\u01d6":"u","\u0171":"u","\u0169":"u","\u1e79":"u","\u0173":"u","\u016b":"u","\u1e7b":"u","\u1ee7":"u",
|
||||
"\u0215":"u","\u0217":"u","\u01b0":"u","\u1ee9":"u","\u1eeb":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u1e77":"u","\u1e75":"u","\u1e7d":"v","\u1e7f":"v","\u1e83":"w","\u1e81":"w","\u0175":"w","\u1e98":"w","\u1e85":"w","\u1e87":"w","\u1e89":"w","\u1e8d":"x","\u1e8b":"x","\u00fd":"y","\u1ef3":"y","\u0177":"y","\u1e99":"y","\u00ff":"y","\u1ef9":"y","\u1e8f":"y","\u0233":"y","\u1ef7":"y","\u1ef5":"y","\u017a":"z","\u1e91":"z","\u017e":"z","\u017c":"z","\u1e93":"z","\u1e95":"z",
|
||||
"\u01ef":"\u0292","\u1f00":"\u03b1","\u1f04":"\u03b1","\u1f84":"\u03b1","\u1f02":"\u03b1","\u1f82":"\u03b1","\u1f06":"\u03b1","\u1f86":"\u03b1","\u1f80":"\u03b1","\u1f01":"\u03b1","\u1f05":"\u03b1","\u1f85":"\u03b1","\u1f03":"\u03b1","\u1f83":"\u03b1","\u1f07":"\u03b1","\u1f87":"\u03b1","\u1f81":"\u03b1","\u03ac":"\u03b1","\u1f71":"\u03b1","\u1fb4":"\u03b1","\u1f70":"\u03b1","\u1fb2":"\u03b1","\u1fb0":"\u03b1","\u1fb6":"\u03b1","\u1fb7":"\u03b1","\u1fb1":"\u03b1","\u1fb3":"\u03b1","\u1f10":"\u03b5",
|
||||
"\u1f14":"\u03b5","\u1f12":"\u03b5","\u1f11":"\u03b5","\u1f15":"\u03b5","\u1f13":"\u03b5","\u03ad":"\u03b5","\u1f73":"\u03b5","\u1f72":"\u03b5","\u1f20":"\u03b7","\u1f24":"\u03b7","\u1f94":"\u03b7","\u1f22":"\u03b7","\u1f92":"\u03b7","\u1f26":"\u03b7","\u1f96":"\u03b7","\u1f90":"\u03b7","\u1f21":"\u03b7","\u1f25":"\u03b7","\u1f95":"\u03b7","\u1f23":"\u03b7","\u1f93":"\u03b7","\u1f27":"\u03b7","\u1f97":"\u03b7","\u1f91":"\u03b7","\u03ae":"\u03b7","\u1f75":"\u03b7","\u1fc4":"\u03b7","\u1f74":"\u03b7",
|
||||
"\u1fc2":"\u03b7","\u1fc6":"\u03b7","\u1fc7":"\u03b7","\u1fc3":"\u03b7","\u1f30":"\u03b9","\u1f34":"\u03b9","\u1f32":"\u03b9","\u1f36":"\u03b9","\u1f31":"\u03b9","\u1f35":"\u03b9","\u1f33":"\u03b9","\u1f37":"\u03b9","\u03af":"\u03b9","\u1f77":"\u03b9","\u1f76":"\u03b9","\u1fd0":"\u03b9","\u1fd6":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u1fd3":"\u03b9","\u1fd2":"\u03b9","\u1fd7":"\u03b9","\u1fd1":"\u03b9","\u1f40":"\u03bf","\u1f44":"\u03bf","\u1f42":"\u03bf","\u1f41":"\u03bf","\u1f45":"\u03bf",
|
||||
"\u1f43":"\u03bf","\u03cc":"\u03bf","\u1f79":"\u03bf","\u1f78":"\u03bf","\u1fe4":"\u03c1","\u1fe5":"\u03c1","\u1f50":"\u03c5","\u1f54":"\u03c5","\u1f52":"\u03c5","\u1f56":"\u03c5","\u1f51":"\u03c5","\u1f55":"\u03c5","\u1f53":"\u03c5","\u1f57":"\u03c5","\u03cd":"\u03c5","\u1f7b":"\u03c5","\u1f7a":"\u03c5","\u1fe0":"\u03c5","\u1fe6":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u1fe3":"\u03c5","\u1fe2":"\u03c5","\u1fe7":"\u03c5","\u1fe1":"\u03c5","\u1f60":"\u03c9","\u1f64":"\u03c9","\u1fa4":"\u03c9",
|
||||
"\u1f62":"\u03c9","\u1fa2":"\u03c9","\u1f66":"\u03c9","\u1fa6":"\u03c9","\u1fa0":"\u03c9","\u1f61":"\u03c9","\u1f65":"\u03c9","\u1fa5":"\u03c9","\u1f63":"\u03c9","\u1fa3":"\u03c9","\u1f67":"\u03c9","\u1fa7":"\u03c9","\u1fa1":"\u03c9","\u03ce":"\u03c9","\u1f7d":"\u03c9","\u1ff4":"\u03c9","\u1f7c":"\u03c9","\u1ff2":"\u03c9","\u1ff6":"\u03c9","\u1ff7":"\u03c9","\u1ff3":"\u03c9","\u0491":"\u0433","\u0450":"\u0435","\u0451":"\u0435","\u04c2":"\u0436","\u045d":"\u0438","\u04e3":"\u0438","\u04ef":"\u0443"});
|
||||
n.register("$9",function(f,d,k){f.init=function(){function d(a){return h[a]||a}function g(a,b,l,c){b=a.split(b);for(var e=b.length;0!==e--;)(a=b[e])&&null==c[a]&&(l.push(a),c[a]=!0);return l}function c(a){return g(String(a||"").toLowerCase().replace(e,d),p,[],{})}function b(a,b){for(var c=[],h={},A,u=b.length,z=p;0!==u--;)(A=b[u])&&g(String(A||"").toLowerCase().replace(e,d),z,c,h);l[a]=c}function a(a,b){var c=[],e=-1,h=l,p=h.length,g,d,C,f,k,B,I=a.length,L=b?!0:!1;a:for(;++e<p;)if(C=h[e],null!=C&&
|
||||
(f=C.length)){k=0;b:for(;k<I;k++){B=a[k];for(g=0;g<f;g++)if(d=C[g],0===d.indexOf(B))continue b;continue a}c.push(L?b[e]:e)}return c}var l=[],e=/[^a-z0-9]/g,p=/[\-_\s.?!;:,*^+=~`"(){}<>\[\]\/\\\u00a0\u1680\u180e\u2000-\u206f\u2e00-\u2e7f\u3000-\u303f]+/,h=n.require("$22","flatten.json");return{split:c,pull:function(b,c){return a(b,c)},find:function(b,l){return a(c(b),l)},add:function(a,b){l[a]=c(b)},push:function(a){b(l.length,a)},index:function(a,c){b(a,c)},size:function(){return l.length},clear:function(){l=
|
||||
[]},remove:function(a){l[a]=null}}};return f}({},r,s));n.register("$10",function(f,d,n){f.listen=function(f,g){function c(){q[e?"show":"hide"]()}function b(a){D&&f.setAttribute("size",2+a.length);e=a;c();return a}function a(){p=null;g(e)}function l(){var c=f.value;v&&c===v&&(c="");c!==e&&(p&&clearTimeout(p),b(c),h?p=setTimeout(a,h):a())}f instanceof jQuery&&(f=f[0]);var e,p,h=150,v=d.attachEvent&&f.getAttribute("placeholder"),D=1===Number(f.size),q=k('<a href="#clear" tabindex="-1" class="icon clear"><span>clear</span></a>').click(function(){f.value=
|
||||
"";l();return!1});b(f.value);k(f).on("input blur focus",function(){l();return!0}).after(q);c();return{delay:function(a){h=a},ping:function(c){c?(p&&clearTimeout(p),c=f.value,v&&c===v&&(c=""),b(c),a(),c=void 0):c=l();return c},val:function(a){if(null==a)return e;p&&clearTimeout(p);f.value=b(a);c()},el:function(){return f},blur:function(a){return k(f).on("blur",a)}}};return f}({},r,s));n.register("$11",function(f,d,n){function m(b,a){this.$element=k(b);this.options=a;this.enabled=!0;this.fixTitle()}
|
||||
f.init=function(b,a){var l={fade:!0,offset:5,delayIn:g,delayOut:c,anchor:b.attr("data-anchor"),gravity:b.attr("data-gravity")||"s"};a&&(l=k.extend({},l,a));b.tipsy(l)};f.delays=function(b,a){g=b||150;c=a||100};f.kill=function(){k("div.tipsy").remove()};f.text=function(b,a){a.data("tipsy").setTitle(b)};var g,c;f.delays();k(n.body).on("overlayOpened overlayClosing",function(b){f.kill();return!0});m.prototype={show:function(){var b=this.getTitle();if(b&&this.enabled){var a=this.tip();a.find(".tipsy-inner")[this.options.html?
|
||||
"html":"text"](b);a[0].className="tipsy";a.remove().css({top:0,left:0}).prependTo(n.body);var b=(b=this.options.anchor)?this.$element.find(b):this.$element,b=k.extend({},b.offset(),{width:b[0].offsetWidth,height:b[0].offsetHeight}),c=a[0].offsetWidth,e=a[0].offsetHeight,p="function"==typeof this.options.gravity?this.options.gravity.call(this.$element[0]):this.options.gravity,h;switch(p.charAt(0)){case "n":h={top:b.top+b.height+this.options.offset,left:b.left+b.width/2-c/2};break;case "s":h={top:b.top-
|
||||
e-this.options.offset,left:b.left+b.width/2-c/2};break;case "e":h={top:b.top+b.height/2-e/2,left:b.left-c-this.options.offset};break;case "w":h={top:b.top+b.height/2-e/2,left:b.left+b.width+this.options.offset}}2==p.length&&("w"==p.charAt(1)?h.left=b.left+b.width/2-15:h.left=b.left+b.width/2-c+15);a.css(h).addClass("tipsy-"+p);a.find(".tipsy-arrow")[0].className="tipsy-arrow tipsy-arrow-"+p.charAt(0);this.options.className&&a.addClass("function"==typeof this.options.className?this.options.className.call(this.$element[0]):
|
||||
this.options.className);a.addClass("in")}},hide:function(){this.tip().remove()},fixTitle:function(){var b=this.$element,a=b.attr("title")||"";(a||"string"!==typeof b.attr("original-title"))&&b.attr("original-title",a).removeAttr("title")},getTitle:function(){var b,a=this.$element,c=this.options;this.fixTitle();"string"==typeof c.title?b=a.attr("title"==c.title?"original-title":c.title):"function"==typeof c.title&&(b=c.title.call(a[0]));return(b=(""+b).replace(/(^\s*|\s*$)/,""))||c.fallback},setTitle:function(b){var a=
|
||||
this.$element;a.attr("default-title")||a.attr("default-title",this.getTitle());null==b&&(b=a.attr("default-title")||this.getTitle());a.attr("original-title",b);if(this.$tip)this.$tip.find(".tipsy-inner")[this.options.html?"html":"text"](b)},tip:function(){this.$tip||(this.$tip=k('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>'),this.$tip.data("tipsy-pointee",this.$element[0]));return this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),
|
||||
this.options=this.$element=null)},enable:function(){this.enabled=!0},disable:function(){this.hide();this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled}};k.fn.tipsy=function(b){function a(a){var c=k.data(a,"tipsy");c||(c=new m(a,k.fn.tipsy.elementOptions(a,b)),k.data(a,"tipsy",c));return c}function c(){var l=a(this),e=b.delayIn;l.hoverState="in";0==e?l.show():(l.fixTitle(),setTimeout(function(){"in"==l.hoverState&&l.show()},e))}function e(){var c=a(this),l=b.delayOut;c.hoverState=
|
||||
"out";0==l?c.hide():(c.tip().removeClass("in"),setTimeout(function(){"out"==c.hoverState&&c.hide()},l))}b=k.extend({},k.fn.tipsy.defaults,b);b.live||this.each(function(){a(this)});if("manual"!=b.trigger){var p=b.live?"live":"bind",h="hover"==b.trigger?"mouseleave":"blur";this[p]("hover"==b.trigger?"mouseenter":"focus",c)[p](h,e)}return this};k.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:0.8,title:"title",trigger:"hover",anchor:null};
|
||||
k.fn.tipsy.elementOptions=function(b,a){return k.metadata?k.extend({},a,k(b).metadata()):a};k.fn.tipsy.autoNS=function(){return k(this).offset().top>k(n).scrollTop()+k(d).height()/2?"s":"n"};k.fn.tipsy.autoWE=function(){return k(this).offset().left>k(n).scrollLeft()+k(d).width()/2?"e":"w"};k.fn.tipsy.autoBounds=function(b,a){return function(){var c=a[0],e=1<a.length?a[1]:!1,p=k(n).scrollTop()+b,h=k(n).scrollLeft()+b,g=k(this);g.offset().top<p&&(c="n");g.offset().left<h&&(e="w");k(d).width()+k(n).scrollLeft()-
|
||||
g.offset().left<b&&(e="e");k(d).height()+k(n).scrollTop()-g.offset().top<b&&(c="s");return c+(e?e:"")}};return f}({},r,s));n.register("$35",function(f,d,k){"".localeCompare||(String.prototype.localeCompare=function(){return 0});"".trim||(String.prototype.trim=function(){return n.require("$5","string.js").trim(this," \n\r\t")});f.html=function(){function d(){b=/[<>&]/g;a=/(\r\n|\n|\r)/g;l=/(?:https?):\/\/(\S+)/ig;e=location.hostname;d=null}function g(a){return"&#"+a.charCodeAt(0)+";"}function c(a,
|
||||
b){return'<a href="'+a+'" target="'+(b.indexOf(e)?"_blank":"_top")+'">'+b+"</a>"}var b,a,l,e;return function(e,h){d&&d();var v=e.replace(b,g);h&&(v=v.replace(l,c).replace(a,"<br />"));return v}}();return f}({},r,s));n.register("$36",function(f,d,k){function m(){}var g,c,b=n.require("$21","rtl.json");f.init=function(){return new m};f.cast=function(a){return a instanceof m?a:"string"===typeof a?f.parse(a):f.clone(a)};f.clone=function(a){var b,c=new m;for(b in a)c[b]=a[b];return c};f.parse=function(a){g||
|
||||
(c=/[-_+]/,g=/^([a-z]{2,3})(?:-([a-z]{4}))?(?:-([a-z]{2}|[0-9]{3}))?(?:-([0-9][a-z0-9]{3,8}|[a-z0-9]{5,8}))?(?:-([a-z]-[-a-z]+))?$/i);a=String(a).split(c).join("-");if(!g.exec(a))return null;var b=new m;b.lang=RegExp.$1.toLowerCase();if(a=RegExp.$2)b.script=a.charAt(0).toUpperCase()+a.substr(1).toLowerCase();if(a=RegExp.$3)b.region=a.toUpperCase();if(a=RegExp.$4)b.variant=a.toLowerCase();if(a=RegExp.$5)b.extension=a;return b};d=m.prototype;d.isValid=function(){return!!this.lang};d.isKnown=function(){var a=
|
||||
this.lang;return!(!a||"zxx"===a)};d.toString=function(a){a=a||"-";var b,c=this.lang||"zxx";if(b=this.script)c+=a+b;if(b=this.region)c+=a+b;if(b=this.variant)c+=a+b;if(b=this.extension)c+=a+b;return c};d.getIcon=function(){for(var a=4,b,c,g=["variant","region","script","lang"],h=[];0!==a--;)if(b=g[a],c=this[b])c.join&&(c=c.join("-")),1===a&&3===c.length?h.push("region-m49"):h=h.concat([b,b+"-"+c.toLowerCase()]);return h.join(" ")};d.isRTL=function(){return!!b[String(this.script||this.lang).toLowerCase()]};
|
||||
d=null;return f}({},r,s));n.register("$37",function(f,d,k){function m(a){d.console&&console.error&&console.error(a)}function g(){m("Method not implemented")}function c(){}function b(a){}c.prototype.toString=function(){return"[Undefined]"};b.prototype._validate=function(a){var b,e,p=!0;for(b in this)e=this[b],e===g?(m(a+"."+b+"() must be implemented"),p=!1):e instanceof c&&(m(a+"."+b+" must be defined"),p=!1);return p};f.init=function(a,l){var e,p=new b;if(a)for(e=a.length;0!==e--;)p[a[e]]=g;if(l)for(e=
|
||||
l.length;0!==e--;)p[l[e]]=new c;return p};f.validate=function(a){var b=/function (\w+)\(/.exec(a.toString())?RegExp.$1:"";a.prototype._validate(b||"Object")};return f}({},r,s));n.register("$46",function(f,d,k){var m=d.requestAnimationFrame,g=d.cancelAnimationFrame,c=0;if(!m||!g)for(var b in{ms:1,moz:1,webkit:1,o:1})if(m=d[b+"RequestAnimationFrame"])if(g=d[b+"CancelAnimationFrame"]||d[b+"CancelRequestAnimationFrame"])break;m&&g||(m=function(b){var e=a();timeToCall=Math.max(0,16-(e-c));nextTime=e+timeToCall;
|
||||
timerId=d.setTimeout(function(){b(nextTime)},timeToCall);c=nextTime;return timerId},g=function(a){clearTimeout(a)});var a=Date.now||function(){return(new Date).getTime()};f.loop=function(a,b){function c(){d=m(c,b);a(h++)}var h=0,d;c();return{stop:function(){d&&g(d);d=null}}};return f}({},r,s));n.register("$43",function(f,d,k){function m(a,c,e,l){if(b){var h=e;e=function(a){if((a.MSPOINTER_TYPE_TOUCH||"touch")===a.pointerType)return h(a)}}a.addEventListener(c,e,l);return{unbind:function(){a.removeEventListener(c,
|
||||
e,l)}}}function g(a){a.preventDefault();a.stopPropagation();return!1}var c,b=!!d.navigator.msPointerEnabled,a=b?"MSPointerDown":"touchstart",l=b?"MSPointerMove":"touchmove",e=b?"MSPointerUp":"touchend";f.ok=function(a){null==c&&(c="function"===typeof k.body.addEventListener);c&&a&&a(f);return c};f.ms=function(){return b};f.dragger=function(b,c){function h(a){b.addEventListener(a,d[a],!1)}function w(a){b.removeEventListener(a,d[a],!1)}var d={};d[a]=function(b){p(b,function(e,h){h.type=a;c(b,h,u)});
|
||||
h(l);h(e);return!0};d[e]=function(a){w(l);w(e);p(a,function(b,h){h.type=e;c(a,h,u)});return!0};d[l]=function(a){p(a,function(b,e){e.type=l;c(a,e,u)});return g(a)};h(a);var u={kill:function(){w(a);w(l);w(e);b=u=c=null}};return u};f.swiper=function(c,d,f){function w(a){c.addEventListener(a,k[a],!1)}function A(a){c.removeEventListener(a,k[a],!1)}function u(){z&&z.stop();z=null}var z,H,C,k={},m=[],B=[],I=[];k[a]=function(a){H=!1;u();var b=h();p(a,function(a,c){m[a]=b;B[a]=c.clientX;I[a]=c.clientY});C=
|
||||
c.scrollLeft;return!0};k[e]=function(a){p(a,function(a,b){var c=h()-m[a],e=B[a]-b.clientX,c=Math.abs(e)/c;d(c,e?0>e?-1:1:0)});C=null;return!0};k[l]=function(a){var b,e;null==C||p(a,function(a,c){b=B[a]-c.clientX;e=I[a]-c.clientY});if(e&&Math.abs(e)>Math.abs(b))return H=!0;b&&(H=!0,c.scrollLeft=Math.max(0,C+b));return g(a)};if(!b||f)w(a),w(l),w(e),b&&(c.className+=" mstouch");return{kill:function(){A(a);A(l);A(e);u()},swiped:function(){return H},ms:function(){return b},snap:function(a){b&&!f&&(c.style["-ms-scroll-snap-points-x"]=
|
||||
"snapInterval(0px,"+a+"px)",c.style["-ms-scroll-snap-type"]="mandatory",c.style["-ms-scroll-chaining"]="none")},scroll:function(a,b,e){u();var h=c.scrollLeft,l=a>h?1:-1,B=Math[1===l?"min":"max"],g=Math.round(16*b*l);return z=n.require("$46","fps.js").loop(function(b){b&&(h=Math.max(0,B(a,h+g)),c.scrollLeft=h,a===h&&(u(),e&&e(h)))},c)}}};f.start=function(b,c){return m(b,a,c,!1)};f.move=function(a,b){return m(a,l,b,!1)};f.end=function(a,b){return m(a,e,b,!1)};var p=f.each=function(a,c){if(b)(a.MSPOINTER_TYPE_TOUCH||
|
||||
"touch")===a.pointerType&&c(0,a);else for(var e=-1,h=(a.originalEvent||a).changedTouches||[];++e<h.length;)c(e,h[e])},h=Date.now||function(){return(new Date).getTime()};return f}({},r,s));n.register("$47",function(f,d,n){f.init=function(d){function g(){l.style.top=String(-d.scrollTop)+"px";return!0}function c(){var a=l;a.textContent=d.value;a.innerHTML=a.innerHTML.replace(/[ \t]/g,b).split(/(?:\n|\r\n?)/).join('<span class="eol crlf"></span>\r\n')+'<span class="eol eof"></span>';return!0}function b(a){return'<span class="x'+
|
||||
a.charCodeAt(0).toString(16)+'">'+a+"</span>"}var a=d.parentNode,l=a.insertBefore(n.createElement("div"),d);k(d).on("input",c).on("scroll",g);k(a).addClass("has-mirror");l.className="ta-mirror";var e=d.offsetWidth-d.clientWidth;2<e&&(l.style.marginRight=String(e-2)+"px");c();g();return{kill:function(){k(d).off("input",c).off("scroll",g);a.removeChild(l);l=null;k(a).removeClass("has-mirror")}}};return f}({},r,s));n.register("$29",function(f,d,k){function m(b,a){for(var c=0,e=-1,p=a&&d[a],h=g[b]||[],
|
||||
v=h.length;++e<v;)callback=h[e],"function"===typeof callback&&(callback(p),c++);return c}var g={},c;f.load=function(b,a,c){function e(){v&&(clearTimeout(v),v=null);f&&(f.onreadystatechange=null,f=f=f.onload=null);b&&(delete g[b],b=null)}function p(a,h){var g=f&&f.readyState;if(h||!g||"loaded"===g||"complete"===g)h||m(b,c),e()}function h(){if(0===m(b))throw Error('Failed to load "'+(c||b)+'"');e()}if(c&&d[c])"function"===typeof a&&a(d[c]);else if(null!=g[b])g[b].push(a);else{g[b]=[a];var v=setTimeout(h,
|
||||
4E3),f=k.createElement("script");f.setAttribute("src",b);f.setAttribute("async","true");f.onreadystatechange=p;f.onload=p;f.onerror=h;f.onabort=e;k.getElementsByTagName("head")[0].appendChild(f)}};f.stat=function(b){var a;if(!(a=c)){for(var l,e,g=k.getElementsByTagName("script"),h=-1,d=g.length;++h<d;)if(a=g[h].getAttribute("src"))if(l=a.indexOf("/lib/vendor"),-1!==l){e=a.substr(0,l);break}a=c=e||"/static"}return a+b};return f}({},r,s));n.register("$15",function(f,d,E){function m(a,b){a.setReadOnly(!1);
|
||||
a.on("change",function(a,c){return b.val(c.getValue())});a.on("focus",function(){return b.focus()});a.on("blur",function(){return b.blur()})}function g(a){a.off("change");a.off("focus");a.off("blur")}function c(a){g(a);a.setReadOnly(!0);a.setHighlightGutterLine(!1);a.setHighlightActiveLine(!1)}function b(b,c){function e(){this.HighlightRules=l}var l=a(c),g=b.require,d=g("ace/lib/oop");d.inherits(l,g("ace/mode/text_highlight_rules").TextHighlightRules);d.inherits(e,g("ace/mode/text").Mode);return new e}
|
||||
function a(a){return function(){var b={start:[{token:"empty_line",regex:/^$/},{token:"constant.language",regex:"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"},{token:"constant.language",regex:/<!\[CDATA\[/},{token:"constant.language",regex:/\]\]>/},{token:"locked",regex:/<(?:xliff:)?(?:g|ph)[^>]*>[^<]*<\/(?:xliff:)?(?:g|ph)>/},{token:"locked",regex:/<(?:xliff:)?(bx|ex|x)[^\/>]*\/>/},{token:"constant.language",regex:/<\/?[:a-z]+[^>]*>/}]},c=l(a);"icu"===a?b={start:b.start.concat([{token:"icu-quoted",
|
||||
regex:/'([{}][^']*)?'/},{token:"printf",regex:"{[^!-/:-@\\[-^{-~\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a9\u00ab\u00ac\u00ae\u00b0\u00b1\u00b6\u00bb\u00bf\u00d7\u00f7\\u2010-\\u2027\\u2030-\\u203E\\u2041-\\u2053\\u2055-\\u205E\\u2190-\\u245F\\u2500-\\u2775\\u2794-\\u2BFF\\u2E00-\\u2E7F\\u3001-\\u3003\\u3008-\\u3020\\u3030\\uFD3E\\uFD3F\\uFE45\\uFE46]+(,[\\s\\u0085\\u200E\\u200F\\u2028\\u2029]*(?:number|date|time|spellout|ordinal|duration)[\\s\\u0085\\u200E\\u200F\\u2028\\u2029]*(,[\\s\\u0085\\u200E\\u200F\\u2028\\u2029]*[^{}]+)?)?}"},
|
||||
{token:"icu",regex:/{/,next:"icuName"},{token:"icu",regex:/}/,next:"icuType"}]),icuName:[{token:"icu",regex:"[\\s\\u0085\\u200E\\u200F\\u2028\\u2029]+"},{token:"icu.name",regex:"[^\\s\\u0085\\u200E\\u200F\\u2028\\u2029!-/:-@\\[-^{-~\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7\u00a9\u00ab\u00ac\u00ae\u00b0\u00b1\u00b6\u00bb\u00bf\u00d7\u00f7\\u2010-\\u2027\\u2030-\\u203E\\u2041-\\u2053\\u2055-\\u205E\\u2190-\\u245F\\u2500-\\u2775\\u2794-\\u2BFF\\u2E00-\\u2E7F\\u3001-\\u3003\\u3008-\\u3020\\u3030\\uFD3E\\uFD3F\\uFE45\\uFE46]+",
|
||||
next:"icuType"},{defaultToken:"icu",next:"icuType"}],icuType:[{token:"icu",regex:/[{}]/,next:"start"},{defaultToken:"icu"}]}:c&&b.start.push({token:"printf",regex:c});this.$rules=b}}function l(a){switch(a){case "objc":return/%(?:\d+\$)?[-+'0# ]*\d*(?:\.\d+|\.\*(?:\d+\$)?)?(?:hh?|ll?|[qjzTL])?[sScCdDioOuUxXfFeEgGaAp%@]/;case "java":return/%(?:\d+\$)?[-+,(0# ]*\d*(?:\.\d+)?(?:[bBhHsScCdoxXeEfgGaA%n]|[tT][HIklMSLNpzZsQBbhAaCYyjmdeRTrDFc])/;case "php":return/%(?:\d+\$)?(?:'.|[-+0 ])*\d*(?:\.\d+)?[suxXbcdeEfFgGo%]/;
|
||||
case "python":return/%(?:\([a-z]+\))?[-+0# ]*(?:\d+|\*)?(?:\.\d+|\.\*)?(?:[hlL])?[sdiouxXeEfFgGcra%]/;case "javascript":return/%(?:[1-9]\d*\$)?\+?(?:0|'[^$])?-?\d*(?:\.\d+)?[b-gijostTuvxX%]/;case "auto":return/%(?:\d+\$|\([a-z]+\))?(?:[-+0]?\d*(\.\d+)?[duxoefgaDUXOEFGA]|[@scSC%])/;case p:return e||"%%"}}var e,p="auto";f.init=function(a,e,l){var f,w=!1,A=l||p,u=a.parentNode,z=u.appendChild(E.createElement("div"));k(u).addClass("has-proxy has-ace");n.require("$29","remote.js").load("https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.1/ace.js",
|
||||
function(l){if(z){if(!l)throw Error("Failed to load code editor");f=l.edit(z);var g=f.session,d=f.renderer;f.$blockScrolling=Infinity;f.setShowInvisibles(w);f.setWrapBehavioursEnabled(!1);f.setBehavioursEnabled(!1);f.setHighlightActiveLine(!1);g.setUseSoftTabs(!1);d.setShowGutter(!0);d.setPadding(10);d.setScrollMargin(8);g.setMode(b(l,A));f.setValue(a.value,-1);g.setUseWrapMode(!0);e?m(f,e):c(f)}},"ace");return{kill:function(){f&&(g(f),f.destroy(),f=null);z&&(u.removeChild(z),k(u).removeClass("has-proxy has-ace"),
|
||||
z=null);return this},disable:function(){f&&c(f);e=null;return this},enable:function(a){e=a;f&&m(f,a);return this},resize:function(){f&&f.resize();return this},val:function(a){f&&a!==f.getValue()&&f.setValue(a,-1);return this},invs:function(a){a=a||!1;w!==a&&(w=a,f&&f.setShowInvisibles(a));return this},strf:function(a){a=a||p;a!==A&&(A=a,f&&f.session.setMode(b(d.ace,a)));return this},focus:function(){return this}}};f.strf=function(a,b){p=a;e=b;return f};return f}({},r,s));n.register("$48",function(f,
|
||||
d,E){function m(a,b){function c(){return b.val(a.getContent())}a.on("input",c);a.on("change",c);a.on("focus",function(){return b.focus()});a.on("blur",function(){return b.blur()});a.setMode("design")}function g(a){a.off("input");a.off("change");a.off("focus");a.off("blur")}function c(a){g(a);a.setMode("readonly")}var b=0;f.load=function(a){var b=n.require("$29","remote.js");b.load(b.stat("/lib/tinymce.min.js"),a,"tinymce");return f};f.init=function(a,l){function e(a){D=a;q="<p>"===a.substr(0,3)&&
|
||||
"</p>"===a.substr(-4);return a.replace(/(<\/?)script/ig,"$1loco:script")}function d(a){h=a;a._getContent=a.getContent;a.getContent=function(a){a=this._getContent(a);a=a.replace(/(<\/?)loco:script/ig,"$1script");if(!q&&"<p>"===a.substr(0,3)&&"</p>"===a.substr(-4)){var b=a.substr(3,a.length-7);if(b===D||-1===b.indexOf("</p>"))a=b}return a};a._setContent=a.setContent;a.setContent=function(a,b){return this._setContent(e(a),b)};l?(m(a,l),l.reset()):c(a);k(u).removeClass("loading")}var h,v=!1,D="",q=!1,
|
||||
w=a.parentNode,A=w.parentNode,u=w.appendChild(E.createElement("div")),z=A.insertBefore(E.createElement("nav"),w);z.id="_tb"+String(++b);k(w).addClass("has-proxy has-mce");k(u).addClass("mce-content-body loading").html(e(a.value));f.load(function(a){if(!a)throw Error("Failed to load HTML editor");u&&a.init({inline:!0,target:u,hidden_input:!1,theme:"modern",skin:!1,plugins:"link lists",browser_spellcheck:!0,menubar:!1,fixed_toolbar_container:"#"+z.id,toolbar:"formatselect | bold italic link unlink | bullist numlist outdent indent",
|
||||
block_formats:"Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h4;Heading 4=h4;Heading 5=h5;Heading 6=h6;",forced_root_block:"p",relative_urls:!1,convert_urls:!1,remove_script_host:!1,document_base_url:"",allow_script_urls:!1,formats:{alignleft:{classes:"alignleft"},alignright:{selector:"p,h1,h2,h3,h4,span,strong,em,a",classes:"alignright"},aligncenter:{selector:"p,h1,h2,h3,h4,span,strong,em,a",classes:"aligncenter"},strikethrough:{inline:"del"}},fix_list_elements:!0,extended_valid_elements:"span,b,i,u,loco:script",
|
||||
entities:"38,amp,60,lt,62,gt,160,nbsp",entity_encoding:"named",keep_styles:!1,init_instance_callback:d})});return{val:function(b){b=e(b);null==h?(a.value=b,k(u).html(b)):h.getContent()!==b&&h.setContent(b);l&&l.val(b);return this},kill:function(){h&&(l&&l.val(h.getContent()),g(h),h.destroy(),h=null);u&&(w.removeChild(u),k(w).removeClass("has-proxy has-mce"),u=null);z&&(A.removeChild(z),z=null);return this},enable:function(a){l=a;h&&m(h,a);return this},disable:function(){h&&c(h);l=null;return this},
|
||||
focus:function(){h&&l&&h.focus();return this},invs:function(a){a=a||!1;v!==a&&(v=a,k(w)[a?"addClass":"removeClass"]("show-invs"));return this}}};return f}({},r,s));n.register("$44",function(f,d,E){function m(b){function a(){d&&(f.off("input",l),d=!1)}function l(){var a=b.value;a!==w&&(f.trigger("changing",[a,w]),w=a)}function e(){l();d&&A!==w&&f.trigger("changed",[w])}function g(){c=b;A=w;d||(f.on("input",l),d=!0);f.trigger("editFocus");q.addClass("has-focus");return!0}function h(){c===b&&(c=null);
|
||||
f.trigger("editBlur");q.removeClass("has-focus");d&&(e(),a());return!0}var d=!1,f=k(b),q=k(b.parentNode),w=b.value,A;f.blur(h).focus(g);return{val:function(a){w!==a&&(b.value=a,f.triggerHandler("input"),w=a);return!0},kill:function(){a();f.off("blur",h).off("focus",g)},fire:function(){w=null;l()},ping:e,blur:h,focus:g,reset:function(){A=w=b.value}}}function g(b){this.e=b}var c;f._new=function(b){return new g(b)};f.init=function(b){var a=new g(b);b.disabled?(b.removeAttribute("disabled"),a.disable()):
|
||||
b.readOnly?a.disable():a.enable();return a};TextAreaPrototype=g.prototype;TextAreaPrototype.destroy=function(){this.unlisten();var b=this.p;b&&(b.kill(),this.p=null);this.e=null};TextAreaPrototype.reload=function(b,a){var c=this.l;c&&!a&&(this.disable(),c=null);this.val(b||"");a&&!c&&this.enable();return this};TextAreaPrototype.val=function(b){var a=this.e;if(null==b)return a.value;var c=this.l,e=this.p;e&&e.val(b);c&&c.val(b);c||a.value===b||(a.value=b,k(a).triggerHandler("input"));return this};
|
||||
TextAreaPrototype.fire=function(){this.l&&this.l.fire();return this};TextAreaPrototype.ping=function(){this.l&&this.l.ping();return this};TextAreaPrototype.focus=function(){var b=this.p;b?b.focus():k(this.e).focus()};TextAreaPrototype.focused=function(){return c&&c===this.el};TextAreaPrototype.parent=function(){return this.e.parentNode};TextAreaPrototype.attr=function(b,a){var c=this.e;if(1===arguments.length)return c.getAttribute(b);null==a?c.removeAttribute(b):c.setAttribute(b,a);return this};TextAreaPrototype.editable=
|
||||
function(){return!!this.l};TextAreaPrototype.enable=function(){var b=this.p;this.e.removeAttribute("readonly");this.listen();b&&b.enable&&b.enable(this.l);return this};TextAreaPrototype.disable=function(){var b=this.p;this.e.setAttribute("readonly",!0);this.unlisten();b&&b.disable&&b.disable();return this};TextAreaPrototype.listen=function(){var b=this.l;b&&b.kill();this.l=m(this.e);return this};TextAreaPrototype.unlisten=function(){var b=this.l;b&&(b.kill(),this.l=null);return this};TextAreaPrototype.setInvs=
|
||||
function(b,a){var c=this.i||!1;if(a||c!==b)this._i&&(this._i.kill(),delete this._i),(c=this.p)?c.invs&&c.invs(b):b&&(this._i=n.require("$47","mirror.js").init(this.e)),this.i=b;return this};TextAreaPrototype.getInvs=function(){return this.i||!1};TextAreaPrototype.setMode=function(b){var a=this.p,g=this.i||!1;b!==(this.m||"")&&(this.m=b,a&&a.kill(),this.p=a="code"===b?n.require("$15","ace.js").init(this.e,this.l,this["%"]):"html"===b?n.require("$48","mce.js").init(this.e,this.l):null,this.setInvs(g,
|
||||
!0),c&&this.focus());return this};TextAreaPrototype.setStrf=function(b){this["%"]=b;"code"===this.m&&this.p.strf(b);return this};TextAreaPrototype.name=function(b){this.e.setAttribute("name",b);return this};TextAreaPrototype.placeholder=function(b){this.e.setAttribute("placeholder",b);return this};TextAreaPrototype.redraw=function(){var b=this.p;b&&b.resize&&b.resize()};TextAreaPrototype=null;return f}({},r,s));n.register("$45",function(f,d,n){function m(a){var b=d.console;b&&b.error&&b.error(a)}
|
||||
function g(a){var b=n.createElement("div");a&&b.setAttribute("class",a);return b}function c(a){return function(){a.resize();return this}}function b(a){return function(b){for(var c=b.target,e=c.$index;null==e&&"DIV"!==c.nodeName&&(c=c.parentElement);)e=c.$index;null!=e&&(b.stopImmediatePropagation(),a.select(e));return!0}}function a(a){return function(){a.redrawDirty()&&a.redraw();return!0}}function l(a){return function(b){var c;c=b.keyCode;if(40===c)c=1;else if(38===c)c=-1;else return!0;if(b.shiftKey||
|
||||
b.ctrlKey||b.metaKey||b.altKey)return!0;a.selectNext(c);b.stopPropagation();b.preventDefault();return!1}}function e(a,b,c){function e(a){m("row["+a+"] disappeared");return{cellVal:function(){return""}}}return function(h){var g=b||0,d=c?-1:1,l=a.rows||[];h.sort(function(a,b){return d*(l[a]||e(a)).cellVal(g).localeCompare((l[b]||e(b)).cellVal(g))})}}function p(a){this.w=a}function h(a){this.t=a;this.length=0}function v(a,b,c){var e=n.createElement("div");e.className=c||"";this._=e;this.d=b||[];this.i=
|
||||
a||0;this.length=b.length}function D(a){this.live=a;this.rows=[]}f.create=function(a){return new p(a)};var q=p.prototype;q.init=function(e){var h=this.w,d=h.id,p=h.splity(d+"-thead",d+"-tbody"),f=p[0],p=p[1],C=[],q=[],m=[],B=[];if(e)this.ds=e,this.idxs=q,this._idxs=null;else if(!(e=this.ds))throw Error("No datasource");f.css.push("wg-thead");p.css.push("wg-tbody");e.eachCol(function(a,b,c){m[a]=d+"-col-"+b;B[a]=c||b});for(var I=g(),L=-1,D=m.length,n=g("wg-cols"),J=f.splitx.apply(f,m);++L<D;)J[L].header(B[L]),
|
||||
n.appendChild(I.cloneNode(!1)).setAttribute("for",m[L]);e.eachRow(function(a,b,c){C[a]=new v(a,b,c);q[a]=a});this.rows=C;this.cols=n;this.ww=null;this.root=I=p.body;this.head=f;f.redraw=c(this);f=p.fixed=J[0].bodyY()||20;h.lock().resize(f,p);h.css.push("is-table");h.restyle();this.sc?this._re_sort(D):e.sort&&e.sort(q);this.redrawDirty();this.render();k(I).attr("tabindex","-1").on("keydown",l(this)).on("mousedown",b(this)).on("scroll",a(this));return this};q.clear=function(){for(var a=this.pages||
|
||||
[],b=a.length;0!==b--;)a[b].destroy();this.pages=[];this.sy=this.mx=this.mn=this.vh=null;void 0;return this};q.render=function(){for(var a,b,c=[],e=this.rows||[],h=-1,g,d=this.idxs,l=d.length,B=this.idxr={},p=this.r,f=this._r,v=this.root,k=this.cols;++h<l;){0===h%100&&(a=k.cloneNode(!0),b=new D(a),b.h=2200,b.insert(v),c.push(b));g=d[h];B[g]=h;a=e[g];if(null==a)throw Error("Render error, no data at ["+g+"]");a.page=b;b.rows.push(a)}b&&100!==b.size()&&b.sleepH(22);this.pages=c;this.mx=this.mn=null;
|
||||
this.redrawDirty();this.redraw();null==p?null!=f&&(a=e[f])&&a.page&&(delete this._r,this.select(f,!0)):(a=e[p])&&a.page?this.select(p,!0):(this.deselect(),this._r=p);return this};q.resize=function(){var a=-1,b=this.ww||(this.ww=[]),c=this.w,e=c.cells[0],h=e.body.childNodes,g=h.length,d=this.pages||[],l=d.length;for(c.redraw.call(e);++a<g;)b[a]=h[a].style.width;if(l){c=this.mx;for(a=this.mn;a<=c;a++)d[a].widths(b);this.redrawDirty()&&this.redraw()}};q.redrawDirty=function(){var a=!1,b=this.root,c=
|
||||
b.scrollTop,b=b.clientHeight;this.sy!==c&&(a=!0,this.sy=c);this.vh!==b&&(a=!0,this.vh=b);return a};q.redraw=function(){for(var a=0,b=-1,c=null,e=null,h=this.ww,g=this.sy,d=this.vh,l=this.mn,B=this.mx,p=Math.max(0,g-100),g=d+g+100,f=this.pages||[],v=f.length;++b<v&&!(a>g);)d=f[b],a+=d.height(),a<p||(null===c&&(c=b),e=b,d.rendered||d.render(h));if(l!==c){if(null!==l&&c>l)for(b=l;b<c;b++){d=f[b];if(!d)throw Error("Shit!");d.rendered&&d.sleep()}this.mn=c}if(B!==e){if(null!==B&&e<B)for(b=B;b>e;b--)d=f[b],
|
||||
d.rendered&&d.sleep();this.mx=e}};q.selected=function(){return this.r};q.thead=function(){return this.w.cells[0]};q.tbody=function(){return this.w.cells[1]};q.tr=function(a){return(a=this.row(a))?a.cells():[]};q.row=function(a){return this.rows[a]};q.td=function(a,b){return this.tr(a)[b]};q.next=function(a,b,c){null==c&&(c=this.r||0);var e=this.idxs,h=e.length,d=(this.idxr||{})[c];for(c=d;c!==(d+=a)&&!(0<=d&&h>d);)if(b&&h)d=1===a?-1:h,b=!1;else return null;c=e[d];return null==c||null==this.rows[c]?
|
||||
(m("Bad next: ["+d+"] does not map to data row"),null):c};q.selectNext=function(a,b,c){a=this.next(a,b);null!=a&&this.r!==a&&this.select(a,c);return this};q.deselect=function(a){var b=this.r;null!=b&&(this.r=null,k(this.tr(b)).removeClass("selected"),this.w.fire("wgRowDeselect",[b,a]));return this};q.selectRow=function(a,b){return this.select(this.idxs[a])};q.select=function(a,b){var c=this.rows[a],e=c&&c.page;if(!e)return this.deselect(!1),m("Row is filtered out"),this;this.deselect(!0);var d,h=
|
||||
this.w.cells[1];e.rendered||(d=e.top(),h.scrollY(d),this.redrawDirty()&&this.redraw());if(!c.rendered)return e.rendered||m("Failed to render page"),m("Row ["+c.i+"] not rendered"),this;e=c.cells();k(e).addClass("selected");this.r=a;b||(d=h.scrollY(),k(this.root).focus(),d!==h.scrollY()&&h.scrollY(d));h.scrollTo(e[0],!0);this.w.fire("wgRowSelect",[a,c.data()]);return this};q.unfilter=function(){this._idxs&&(this.idxs=this._sort(this._idxs),this._idxs=null,this.clear().render());return this};q.filter=
|
||||
function(a){this._idxs||(this._idxs=this.idxs);this.idxs=this._sort(a);return this.clear().render()};q.each=function(a){for(var b,c=-1,e=this.rows||[],d=this.idxs||[],h=d.length;++c<h;)b=d[c],a(e[b],c,b);return this};q.sortable=function(a){var b=this.sc||(this.sc=new h(this));b.has(a)||b.add(a);return this};q._re_sort=function(a){var b=-1,c=this.sc,e=c.active;for(this.sc=c=new h(this);++b<a;)c.add(b);e&&(b=this.head.indexOf(e.id),-1===b&&(b=Math.min(e.idx,a-1)),this.sort(b,e.desc));return this};q._sort=
|
||||
function(a,b){b?(this.s=b,b(a)):(b=this.s)&&b(a);return a};q.sort=function(a,b){this._sort(this.idxs,e(this,a,b));this.sc.activate(a,b);return this};q=null;q=h.prototype;q.has=function(a){return null!=this[a]};q.add=function(a){var b=this,c=b.t.head.cells[a];b[a]={desc:null,idx:a,id:c.id};b.length++;c.addClass("wg-sortable").on("click",function(c){if("header"===c.target.nodeName.toLowerCase())return c.stopImmediatePropagation(),b.toggle(a),!1});return b};q.toggle=function(a){this.t.sort(a,!this[a].desc).clear().render();
|
||||
return this};q.activate=function(a,b){var c,e;c=this.active;var d=this[a],h=this.t.head.cells;c&&(e=h[c.idx])&&(e.removeClass(c.css),c!==d&&e.restyle());(e=h[a])?(d.desc=b,this.active=d,c="wg-"+(b?"desc":"asc"),e.addClass(c).restyle(),d.css=c):this.active=null;return this};q=null;q=v.prototype;q.render=function(a){var b,c=[],e=this._,d=this.length;if(e){for(this.c=c;0!==d--;)b=e.cloneNode(!1),c[d]=this.update(d,b),b.$index=this.i,a[d].appendChild(b);this._=null}else for(c=this.c;0!==d--;)a[d].appendChild(c[d]);
|
||||
this.rendered=!0;return this};q.update=function(a,b){var c=b||this.c[a]||{},e=(this.d[a]||function(){})()||"\u00a0";null==e.innerHTML?c.textContent=e:c.innerHTML=e.innerHTML;return c};q.cells=function(){return this.c||[this._]};q.data=function(){for(var a=-1,b=[],c=this.length;++a<c;)b[a]=this.cellVal(a);return b};q.destroy=function(){this.page=null;this.rendered=!1};q.cellVal=function(a){a=this.d[a]()||"";return String(a.textContent||a)};q=null;q=D.prototype;q.size=function(){return this.rows.length};
|
||||
q.insert=function(a){var b=this.h,c=g("wg-dead");c.style.height=String(b)+"px";a.appendChild(c);return this.dead=c};q.top=function(){return(this.rendered?this.live:this.dead).offsetTop};q.height=function(){var a=this.h;null==a&&(this.h=a=this.rendered?this.live.firstChild.offsetHeight:this.dead.offsetHight);a||m("row has zero height");return a};q.render=function(a){for(var b,c=-1,e=this.rows,d=e.length,h=this.dead,g=this.live,l=g.childNodes;++c<d;)b=e[c],b.rendered||b.render(l);d=a.length;for(c=0;c<
|
||||
d;c++)l[c].style.width=a[c];h.parentNode.replaceChild(g,h);this.rendered=!0;this.h=null;return this};q.sleep=function(){var a=this.height(),b=this.live,c=this.dead;c.style.height=String(a)+"px";b.parentNode.replaceChild(c,b);this.rendered=!1;this.h=a;return this};q.sleepH=function(a){a*=this.rows.length;var b=this.dead;b&&(b.style.height=String(a)+"px");this.rendered||(this.h=a);return this};q.widths=function(a){for(var b=this.live.childNodes,c=a.length;0!==c--;)b[c].style.width=a[c];return this};
|
||||
q.destroy=function(){var a=this.rendered?this.live:this.dead,b=this.rows,c=b.length;for(a.parentNode.removeChild(a);0!==c--;)b[c].destroy()};q=null;return f}({},r,s));n.register("$38",function(f,d,s){function m(a,b){var c=a.id,e=c&&w[c],d=e&&e.parent();if(!e||!d)return null;var h=d.dir===q,c=h?"X":"Y",g="page"+c,h=h?D:v,l=h(d.el),c=b["offset"+c],p=d.el,f=p.className;null==c&&(c=b[g]-h(a));c&&(l+=c);p.className=f+" is-resizing";return{done:function(){p.className=f},move:function(a){d.resize(a[g]-l,
|
||||
e);return!0}}}function g(a,c){function e(){k(s).off("mousemove",d);u&&(u.done(),u=null);return!0}function d(a){u?u.move(a):e();return!0}if(u)return!0;u=m(a.target,a);if(!u)return!0;k(s).one("mouseup",e).on("mousemove",d);return b(a)}function c(a,b){var c=b.type;"touchmove"===c?u&&u.move(b):"touchstart"===c?u=m(a.target,b):"touchend"===c&&u&&(u.done(),u=null)}function b(a){a.stopPropagation();a.preventDefault();return!1}function a(a){var b=A;b&&b.redraw();a&&a.redraw();return A=a}function l(b,c){var e=
|
||||
k(c).on("editFocus",function(){e.trigger("wgFocus",[a(b)])}).on("editBlur",function(){e.trigger("wgBlur",[a(null)])})}function e(a){var b=a.id,c=a.className;this.id=b;this.el=a;this.pos=this.index=0;this.css=[c||"wg-root","wg-cell"];this._cn=c;w[b]=this;this.clear()}var p=n.include("$42","html.js")||n.include("$2","html.js",!0),h=n.require("$20","dom.js"),v=h.top,D=h.left,q=1,w={},A,u=!1;f.init=function(a){var b=new e(a);b.redraw();n.require("$43","touch.js").ok(function(b){b.dragger(a,c)});k(a).mousedown(g);
|
||||
return b};d=e.prototype;d.fire=function(a,b){var c=k.Event(a);c.cell=this;k(this.el).trigger(c,b);return this};d.each=function(a){for(var b=-1,c=this.cells,e=c.length;++b<e;)a(c[b],b);return this};d.indexOf=function(a){return(a=w[a.id||String(a)])&&a.pid===this.id?a.index:-1};d.on=function(){return this.$("on",arguments)};d.off=function(){return this.$("off",arguments)};d.find=function(a){return k(this.el).find(a)};d.$=function(a,b){k.fn[a].apply(k(this.el),b);return this};d.addClass=function(a){this.css.push(a);
|
||||
return this};d.removeClass=function(a){a=this.css.indexOf(a);-1!==a&&this.css.splice(a,1);return this};d.parent=function(){return this.pid&&w[this.pid]};d.splitx=function(){return this._split(q,arguments)};d.splity=function(){return this._split(2,arguments)};d._split=function(a,b){(this.length||this.field)&&this.clear();for(var c=-1,d,g=b.length,l=1/g,p=0;++c<g;){d=h.el();this.body.appendChild(d);for(var f=d,v=b[c],k=v,q=1;w[v];)v=k+"-"+ ++q;f.id=v;d=new e(d);d.index=c;d.pid=this.id;d._locale(this.lang,
|
||||
this.rtl);d.pos=p;p+=l;this.cells.push(d);this.length++}this.dir=a;this.redraw();return this.cells};d.destroy=function(){this.clear();delete w[this.id];var a=this.el;a.innerHTML="";this.body=null;a.className=this._cn||"";k(a).off();return this};d.exists=function(){return this===w[this.id]};d.clear=function(){for(var a=this.el,b=this.cells,c=this.field,e=this.body,d=this.nav,g=this.length||0;0!==g--;)delete w[b[g].destroy().id];this.cells=[];this.length=0;d&&(a.removeChild(d),this.nav=null);e&&(c&&
|
||||
(p.ie()&&k(e).triggerHandler("blur"),c.destroy(),this.field=null),this.table&&(this.table=null),a===e.parentNode&&a.removeChild(e));this.body=a.appendChild(h.el("","wg-body"));this._h=null;return this};d.resize=function(a,b){if(!b&&(b=this.cells[1],!b))return;var c=b.index,e=this.cells,d=k(this.el)[this.dir===q?"width":"height"](),h=e[c+1],c=e[c-1];pad=(b.body||b.el.firstChild).offsetTop||0;max=(h?h.pos*d:d)-pad;min=c?c.pos*d:0;b.pos=Math.min(max,Math.max(min,a))/d;this.redraw();return this};d.distribute=
|
||||
function(a){for(var b=-1,c=0,e,d=this.cells,h=a.length;++b<h&&(e=d[++c]);)e.pos=Math.max(0,Math.min(1,a[b]));this.redraw();return this};d.distribution=function(){for(var a=[],b=0,c=this.cells,e=c.length-1;b<e;)a[b]=c[++b].pos;return a};d.restyle=function(){var a=this.css.concat();0===this.index?a.push("first"):a.push("not-first");this.dir&&(a.push("wg-split"),2===this.dir?a.push("wg-split-y"):a.push("wg-split-x"));this.t&&a.push("has-title");this.nav&&a.push("has-nav");this.field&&(a.push("is-field"),
|
||||
this.field.editable()?a.push("is-editable"):a.push("is-readonly"));a=a.join(" ");a!==this._css&&(this._css=a,this.el.className=a);return this};d.redraw=function(a){this.restyle();var b=this.el,c=this.body,e=this.field;if(c){var d,h=b.clientWidth||0,g=b.clientHeight||0,l=c.offsetTop||0,g=l>g?0:g-l;this._h!==g&&(this._h=g,c.style.height=String(g)+"px",d=e);this._w!==h&&(this._w=h,d=e);d&&d.redraw()}c=this.length;h=1;g=this.nav;for(l=2===this.dir?"height":"width";0!==c--;)e=this.cells[c],g?d=1:(e.fixed&&
|
||||
(e.pos=e.fixed/k(b)[l]()),d=h-e.pos,h=e.pos),e.el.style[l]=String(100*d)+"%",e.redraw(a);return this};d.contents=function(a,b){var c=this.el,e=this.body;if(null==a)return e.innerHTML;this.length?this.clear():e&&(c.removeChild(e),e=null);e||(this.body=e=c.appendChild(h.el("",b||"wg-content")),this._h=null,(c=this.lang)&&this._locale(c,this.rtl,!0));"string"===typeof a?k(e)._html(a):a&&this.append(a);this.redraw();return this};d.textarea=function(a,b){var c=this.field;if(c){var e=c.editable();c.reload(a,
|
||||
b);e!==b&&this.restyle()}else this.length&&this.clear(),e=h.el("textarea"),e.setAttribute("wrap","virtual"),e.value=a,this.contents(e),c=n.require("$44","field.js")._new(e)[b?"enable":"disable"](),l(this,e),this.field=c,this.restyle();this.lang||this.locale("en");return c};d.locale=function(a){a=n.require("$36","locale.js").cast(a);return this._locale(String(a),a.isRTL())};d._locale=function(a,b,c){var e=this.body;if(c||a!==this.lang)this.lang=a,e&&e.setAttribute("lang",a);if(c||b!==this.rtl)this.rtl=
|
||||
b,e&&e.setAttribute("dir",b?"RTL":"LTR");return this};d.editable=function(){var a=this.field;if(a)return a.editable()?a:null;var b=this.cells,c=b.length,e=this.navigated();if(null!=e)return b[e].editable();for(;++e<c;){for(e=0;e<c;c++);if(a=b[e].editable())return a}};d.eachTextarea=function(a){var b=this.field;b?a(b):this.each(function(b){b.eachTextarea(a)});return this};d.append=function(a){a&&(a.nodeType?p.init(this.body.appendChild(a)):p.init(k(a).appendTo(this.body)));return this};d.prepend=function(a){var b=
|
||||
this.body;if(a.nodeType){var c=b.firstChild;p.init(c?b.insertBefore(a,c):b.appendChild(a))}else p.init(k(a).prependTo(b));return this};d.before=function(a){var b=this.body;a.nodeType?p.init(this.el.insertBefore(a,b)):p.init(k(a).insertBefore(b));return this};d.header=function(a,b){if(null==a&&null==b)return this.el.getElementsByTagName("header")[0];this.t=h.txt(a||"");this.el.insertBefore(h.el("header",b),this.body).appendChild(this.t);this.redraw();return this};d.title=function(a){var b=this.t;if(b)return b.nodeValue=
|
||||
a||"",b;this.header(a);return this.t};d.titled=function(){var a=this.t;return a&&a.nodeValue};d.bodyY=function(){return v(this.body,this.el)};d.scrollY=function(a){if(R===a)return this.body.scrollTop;this.body.scrollTop=a};d.tabulate=function(a){var b=this.table;b?b.clear():b=n.require("$45","wgtable.js").create(this);b.init(a);return this.table=b};d.lock=function(){this.body.className+=" locked";return this};d.scrollTo=function(a,b){var c,e=this.body;c=e.scrollTop;var d=v(a,e);if(c>d)c=d;else{var h=
|
||||
e.clientHeight,d=d+k(a).outerHeight();if(h+c<d)c=d-h;else return}b?e.scrollTop=c:k(e).stop(!0).animate({scrollTop:c},250)};d.navigize=function(a,c){function e(a){var b=g[a],c=f[a],d=k(b.el).show();c.addClass("active");p=a;v.data("idx",a);b.fire("wgTabSelect",[a]);return d}var d=this,g=d.cells,l=d.nav,p,f=[];l&&d.el.removeChild(l);var l=d.nav=d.el.insertBefore(h.el("nav","wg-tabs"),d.body),v=k(l).on("click",function(a){var c=k(a.target).data("idx");if(null==c)return!0;if(null!=p){var h=f[p];k(g[p].el).hide();
|
||||
h.removeClass("active")}e(c);d.redraw();return b(a)});null==c&&(c=v.data("idx")||0);d.each(function(b,c){f[c]=k('<a href="#'+b.id+'"></a>').data("idx",c).text(a[c]).appendTo(v);b.pos=0;k(b.el).hide()});e(g[c]?c:0);d.lock();d.redraw();return d};d.navigated=function(){var a=this.nav;if(a)return k(a).data("idx")};d=null;return f}({},r,s));n.register("$23",function(f,d,s){function m(a){var b=[];a&&(a.saved()||b.push("po-unsaved"),a.fuzzy()?b.push("po-fuzzy"):a.flagged()&&b.push("po-flagged"),a.translation()||
|
||||
b.push("po-empty"),a.comment()&&b.push("po-comment"));return b.join(" ")}function g(a,b,c){b=k(a.title(b).parentNode);var e=b.find("span.lang");c?(c=n.require("$36","locale.js").cast(c),e.length||(e=k("<span></span>").prependTo(b)),e.attr("lang",c.lang).attr("class",c.getIcon()||"lang region region-"+(c.region||"zz").toLowerCase())):(e.remove(),c="en");a.locale(c);return b}function c(a,b,c){b.click(function(b){var e=a.fire(c,[b.target]);e||b.preventDefault();return e})}function b(){this.dirty=0}n.require("$3",
|
||||
"number.js");var a="poUpdate",l="changing",e="changed",p=0,h=1,v=2,D=3,q=4,w=5,A=/^\s+/,u,z,r=n.require("$35","string.js").html,C=n.require("$5","string.js").sprintf;f.extend=function(a){return a.prototype=new b};f.localise=function(a){z=a;return f};var F=function(){var a=s.createElement("p");return function(b){a.innerHTML=b.replace("src=","x=");return a.textContent}}(),x=b.prototype=n.require("$37","abstract.js").init(["getListColumns","getListHeadings","getListEntry"],["editable","t"]);x.init=function(){this.localise();
|
||||
this.editable={source:!0,target:!0};this.mode="";this.html=!1;return this};x.localise=function(a){a||(a=z||n.require("$1","t.js").init());var b=[];b[p]=a._x("Source text","Editor")+":";b[D]=a._x("%s translation","Editor")+":";b[q]=a._x("Context","Editor")+":";b[w]=a._x("Comments","Editor")+":";b[h]=a._x("Single","Editor")+":";b[v]=a._x("Plural","Editor")+":";b[6]=a._x("Untranslated","Editor");b[7]=a._x("Translated","Editor");b[8]=a._x("Toggle Fuzzy","Editor");b[9]=a._x("Suggest translation","Editor");
|
||||
this.labels=b;this.t=a;return this};x.setRootCell=function(a){function b(a){c.redraw(!0,a);return!0}var c=n.require("$38","wingrid.js").init(a);k(d).on("resize",b);this.redraw=b;k(a).on("wgFocus wgBlur",function(a,b){a.stopPropagation();u=b});this.destroy=function(){c.destroy();k(d).off("resize",b)};this.rootDiv=a;return c};x.$=function(){return k(this.rootDiv)};x.setListCell=function(a){var b=this;b.listCell=a;a.on("wgRowSelect",function(a,c){b.loadMessage(b.po.row(c));return!0}).on("wgRowDeselect",
|
||||
function(a,c,e){e||b.loadNothing();return!0})};x.setSourceCell=function(a){this.sourceCell=a};x.setTargetCell=function(a){this.targetCell=a};x.next=function(a,b,c){for(var e=this.listTable,d=e.selected(),h=d,g,l=this.po;null!=(d=e.next(a,c,d));){if(h===d){d=null;break}if(b&&(g=l.row(d),g.translated(0)))continue;break}null!=d&&e.select(d,!0);return d};x.current=function(a){var b=this.active;if(null==a)return b;a?a.is(b)?this.reloadMessage(a):this.loadMessage(a):this.unloadActive();return this};x.getTargetOffset=
|
||||
function(){if(this.active)return this.targetCell&&this.targetCell.navigated()||0};x.getTargetEditable=function(){return this.editable.target&&this.targetCell&&this.targetCell.editable()};x.getSourceEditable=function(){return this.editable.source&&this.sourceCell&&this.sourceCell.editable()};x.getContextEditable=function(){return this.editable.context&&this.contextCell&&this.contextCell.editable()};x.getFirstEditable=function(){return this.getTargetEditable()||this.getSourceEditable()||this.getContextEditable()};
|
||||
x.searchable=function(a){a&&(this.dict=a,this.po&&this.rebuildSearch());return this.dict&&!0};x.rebuildSearch=function(){var a=-1,b=this.po.rows,c=b.length,e=this.dict;for(e.clear();++a<c;)e.add(a,b[a].toText())};x.filtered=function(){return this.lastSearch||""};x.filter=function(a,b){var c,e=this.listTable,d=this.lastFound,h=this.lastSearch;if(a){if(h===a)return d||0;if(h&&!d&&0===a.indexOf(h))return 0;c=this.dict.find(a)}this.lastSearch=h=a;this.lastFound=d=c?c.length:this.po.length;c?e.filter(c):
|
||||
e.unfilter();b||this.fire("poFilter",[h,d]);return d};x.countFiltered=function(){return this.lastSearch?this.lastFound:this.po.length};x.unsave=function(a,b){var c=!1;if(a){if(c=a.saved(b))this.dirty++,a.unsave(b),this.fire("poUnsaved",[a,b]);this.markUnsaved(a)}return c};x.markUnsaved=function(a){var b=this.po.indexOf(a);if((b=this.listTable.tr(b))&&b.length){var c=b[0].className;a=c.replace(/(?:^| +)po-[a-z]+/g,"")+" "+m(a);a!==c&&k(b).attr("class",a)}};x.save=function(a){var b=this.po;if(this.dirty||
|
||||
a)b.each(function(a,b){b.save()}),this.listCell.find("div.po-unsaved").removeClass("po-unsaved"),this.dirty=0,this.fire("poSave");return b};x.fire=function(a,b){var c=this.handle;if(c&&c[a]&&(c=c[a].apply(this,b||[]),!1===c))return!1;c=k.Event(a);this.$().trigger(c,b);return!c.isDefaultPrevented()};x.on=function(a,b){this.$().on(a,b);return this};x.getSorter=function(){return null};x.reload=function(){var a=this,b,c=a.listCell,e=a.listTable,d=a.po,h=d&&d.locale(),g=h&&h.isRTL(),l=d&&d.length||0;if(!d||
|
||||
!d.row)return c&&c.clear().header("Error").contents("Invalid messages list"),!1;a.targetLocale=h;a.lastSearch&&(a.lastSearch="",a.lastFound=l,a.fire("poFilter",["",l]));e&&(b=e.thead().distribution());a.listTable=e=c.tabulate({eachCol:function(b){var c,e,d=a.getListColumns(),h=a.getListHeadings();for(e in d)c=d[e],b(c,e,h[c])},eachRow:function(b){d.each(function(c,e){b(e.idx,a.getListEntry(e),m(e))})},sort:a.getSorter()});var p,c=a.getListColumns();for(p in c)e.sortable(c[p]);b&&e.thead().distribute(b);
|
||||
e.tbody().$(g?"addClass":"removeClass",["is-rtl"]);a.fire("poLoad");return!!l};x.load=function(a,b){this.po=a;this.dict&&this.rebuildSearch();this.reload()&&(-1!==b?this.listTable.selectRow(b||0):this.active&&this.unloadActive())};x.pasteMessage=function(a){var b,c=0;this.active===a&&((b=this.sourceCell)&&b.eachTextarea(function(b){b.val(a.source(null,c++))}),(b=this.contextCell)&&b.eachTextarea(function(b){b.val(a.context())}),b=this.targetCell)&&(c=0,b.eachTextarea(function(b){b.val(a.translation(c++))}));
|
||||
this.updateListCell(a,"source");this.updateListCell(a,"target");return this};x.reloadMessage=function(a){var b=this.sourceCell,c=this.targetCell,e;this.pasteMessage(a);b&&this.setSrcMeta(a,b)&&b.redraw();c&&(e=c.navigated()||0,e=this.setTrgMeta(a,e,c),!b&&this.setSrcMeta(a,c)&&(e=!0),e&&c.redraw());return this};x.setStatus=function(){return null};x.setSrcMeta=function(a,b){var e=[],d,h=!1,g=this.$smeta,l=this.labels,p=[],f=a.tags(),v=f&&f.length;if(d=a.context())p.push("<span>"+r(l[q])+"</span>"),
|
||||
p.push("<mark>"+r(d)+"</mark>");if(v&&this.getTag)for(p.push("<span>Tagged:</span>");0<=--v;)(d=this.getTag(f[v]))&&p.push('<mark class="tag">'+r(d.mod_name)+"</mark>");p.length&&e.push(p.join(" "));if(this.getMono()&&(d=a.refs())&&(f=d.split(/\s/),v=f.length)){for(p=[];0<=--v;)d=f[v],p.push("<code>"+r(d)+"</code>");e.push('<p class="has-icon icon-file">'+p.join(" ")+"</p>")}(d=a.notes())&&e.push('<p class="has-icon icon-info">'+r(d,!0)+"</p>");e.length?(g||(g=b.find("div.meta"),g.length||(g=k('<div class="meta"></div>').insertAfter(b.header())),
|
||||
c(this,g,"poMeta"),this.$smeta=g),g.html(e.join("\n")).show(),h=!0):g&&g.text()&&(g.text("").hide(),h=!0);return h};x.setTrgMeta=function(a,b,c){var e=[],d=!1,h=this.$tmeta;b=(a=a.errors(b))&&a.length;var g;if(b)for(g=0;g<b;g++)e.push('<p class="has-icon icon-warn">'+r(a[g],!0)+".</p>");e.length?(h||(h=c.find("div.meta"),h.length||(h=k('<div class="meta"></div>').insertAfter(c.header())),this.$tmeta=h),h.html(e.join("\n")).show(),d=!0):h&&h.text()&&(h.text("").hide(),d=!0);return d};x.loadMessage=
|
||||
function(b){function c(a,b){var e=b?a.split(" "):a.split(" ",1);a=e[0];"="===a.charAt(0)&&(a=a.substr(1),a=["zero","one","two"][Number(a)]||a);e[0]=a.charAt(0).toUpperCase()+a.substr(1).toLowerCase();return e.join(" ")}function d(a,e){var l=R,k=N[p];a.off();a.titled()!==k&&g(a,k,e||"en");k=!1;y.setSrcMeta(b,a)&&(k=!0);if(b.plural()){var k=-1,q=[],m=[],n=a.id+"-",D=b.sourceForms()||e&&e.plurals||["One","Other"],w=D.length;if(2!==w||"="===D[0].charAt(0)&&"=1"!==D[0])for(;++k<w;)q[k]=n+String(k),m[k]=
|
||||
c(D[k])+":";else q=[n+"-0",n+"-1"],m=[N[h],N[v]];a.splity.apply(a,q);a.each(function(a,c){a.header(m[c]).textarea(b.source(null,c),l).setStrf(E).setMode(A).setInvs(z)});a.lock();l&&a.each(function(a,b){f(a,b)})}else k&&a.redraw(),a.textarea(b.source(),l).setStrf(E).setMode(A).setInvs(z),l&&f(a,0)}function f(c,d){c.on(l,function(a,c){b.source(c,d);0===d&&y.updateListCell(b,"source");y.unsave(b,d)}).on(e,function(){0===d&&y.po.reIndex(b);y.dict&&y.rebuildSearch();y.fire(a,[b])})}function k(a,e,d){O&&
|
||||
a.eachTextarea(function(a){a.ping()});a.off();var h=e.isKnown()&&e.label||"Target",h=C(N[D],h);a.titled()!==h&&g(a,h,e);h=!1;!this.sourceCell&&y.setSrcMeta(b,a)&&(h=!0);y.setTrgMeta(b,d,a)&&(h=!0);y.setStatus(b,d);if(b.pluralized()){var l=[],p=[],f=a.id+"-",v=b.targetForms()||e.plurals||["One","Other"],h=v.length,q=function(a){var b=v[a];p.push(b?c(b,!0):"Form "+a);l.push(f+String(a))};for(b.each(q);(e=l.length)<h;)q(e);a.splitx.apply(a,l);a.each(function(a,c){var e=O&&!b.disabled(c);a.textarea(b.translation(c),
|
||||
e).setStrf(E).setMode(A).setInvs(z);O&&m(a,c)});a.navigize(p,d||null).on("wgTabSelect",function(c,e){var d=O&&c.cell.editable();d&&d.focus();y.setTrgMeta(b,e,a);y.setStatus(b,e);y.fire("poTab",[e])})}else h&&a.redraw(),a.textarea(b.translation(),O&&!b.disabled(0)).setStrf(E).setMode(A).setInvs(z),O&&m(a,0)}function m(c,d){c.on(l,function(a,c,e){b.translate(c,d);0===d&&y.updateListCell(b,"target");b.fuzzy(d)?y.fuzzy(!1,b,d):y.unsave(b,d);""===c?(y.fire("poEmpty",[!0,b,d]),y.setStatus(b,d)):""===e&&
|
||||
(y.fire("poEmpty",[!1,b,d]),y.setStatus(b,d))}).on(e,function(){y.dict&&y.rebuildSearch();y.fire(a,[b])})}function n(c){c.off();var d=N[q];c.titled()!==d&&(g(c,d),y.setStatus(null));c.textarea(b.context(),!0).setMode(A).setInvs(z);V&&c.on(l,function(a,c){b.context(c);y.updateListCell(b,"source");y.unsave(b,F)}).on(e,function(){y.po.reIndex(b);y.dict&&y.rebuildSearch();y.fire(a,[b])})}function x(a){var c=N[w];a.titled()!==c&&g(a,c);a.off().on(l,function(a,c){b.comment(c);y.fire("poComment",[b,c]);
|
||||
y.unsave(b,F)}).textarea(b.comment(),!0)}var y=this,A=y.mode,s=b.isHTML(),z=y.inv||!1,r=this.fmt||null,E=b.format()||null,H=b.is(y.active),F=0,G=y.sourceCell,S=y.targetCell,K=y.contextCell,T=y.commentCell,O=y.editable.target,R=y.editable.source,V=y.editable.context,P=u,W=y.sourceLocale,U=y.targetLocale,N=y.labels;y.html!==s&&(y.html=s,"code"!==y.mode&&(A=s?"html":"",y.setMode(A)));y.active=b;G&&d(G,W);K&&n(K);S&&U&&(F=S.navigated()||0,k(S,U,F));T&&x(T);P&&(P.exists()||(P=P.parent()),(s=P.editable())&&
|
||||
s.focus());r!==E&&(this.fmt=E);H||y.fire("poSelected",[b,F])};x.unloadActive=function(){function a(b){b&&b.text("").hide()}function b(a){a&&a.off().clear()}a(this.$smeta);a(this.$tmeta);b(this.sourceCell);b(this.contextCell);b(this.targetCell);this.commentCell&&this.commentCell.off();this.active&&(this.fire("poDeselected",[this.active]),this.active=null);return this};x.loadNothing=function(){var a,b=this.t,c=this.mode||"",e=this.inv||!1,d=this.fmt;this.unloadActive();this.setStatus(null);(a=this.commentCell)&&
|
||||
a.textarea("",!1);if(a=this.sourceCell)a.textarea("",!1).setStrf(d).setMode(c).setInvs(e),a.title(b._x("Source text not loaded","Editor")+":");if(a=this.contextCell)a.textarea("",!1).setMode(c).setInvs(e),a.title(b._x("Context not loaded","Editor")+":");if(a=this.targetCell)a.textarea("",!1).setStrf(d).setMode(c).setInvs(e),a.title(b._x("Translation not loaded","Editor")+":");this.fire("poSelected",[null])};x.updateListCell=function(a,b){var c=this.getListColumns()[b],e=this.po.indexOf(a);(e=this.listTable.row(e))&&
|
||||
e.rendered&&e.update(c)};x.cellText=function(a){if(-1!==a.indexOf("<")||-1!==a.indexOf("&"))a=F(a);return a.replace(A,"")||"\u00a0"};x.fuzzy=function(a,b,c){b=b||this.active;var e=b.fuzzy(c);!0!==a||e?!1===a&&e&&this.flag(0,b,c)&&this.fire("poFuzzy",[b,!1,c]):this.flag(4,b,c)&&this.fire("poFuzzy",[b,!0,c]);return e};x.flag=function(b,c,e){if(!c){c=this.active;e=this.getTargetOffset();if(null==e)return null;e&&c.targetForms()&&(e=0)}var d=c.flagged(e);if(null==b)return d;if(d===b||b&&!c.translated(e)||
|
||||
!this.fire("poFlag",[b,d,c,e]))return!1;c.flag(b,e);this.fire(a,[c])&&this.unsave(c,e);this.setStatus(c,e);return!0};x.add=function(b,c){var e,d=this.po.get(b,c);d?e=this.po.indexOf(d):(e=this.po.length,d=this.po.add(b,c),this.load(this.po,-1),this.fire("poAdd",[d]),this.fire(a,[d]));this.lastSearch&&this.filter("");this.listTable.select(e);return d};x.del=function(b){if(b=b||this.active){var c=this.lastSearch,e=this.po.del(b);null!=e&&(this.unsave(b),this.fire("poDel",[b]),this.fire(a,[b]),this.reload(),
|
||||
this.dict&&this.rebuildSearch(),this.active&&this.active.equals(b)&&this.unloadActive(),this.po.length&&(c&&this.filter(c),this.active||(e=Math.min(e,this.po.length-1),this.listTable.select(e))))}};x.setMono=function(a){return this.setMode(a?"code":this.html?"html":"")};x.setMode=function(a){if(this.mode!==a){this.mode=a;this.callTextareas(function(b){b.setMode(a)});var b=this.active,c=this.sourceCell;b&&b.refs()&&c&&this.setSrcMeta(b,c)&&c.redraw()}return this};x.getMono=function(){return"code"===
|
||||
this.mode};x.setInvs=function(a){(this.inv||!1)!==a&&(this.inv=a,this.callTextareas(function(b){b.setInvs(a)}),this.fire("poInvs",[a]));return this};x.getInvs=function(){return this.inv||!1};x.callTextareas=function(a){var b=this.targetCell;b&&b.eachTextarea(a);(b=this.contextCell)&&b.eachTextarea(a);(b=this.sourceCell)&&b.eachTextarea(a);return this};x.focus=function(){var a=this.getTargetEditable();a&&a.focus();return this};x=null;return f}({},r,s));n.register("$12",function(f,d,s){function m(){this.init()._validate();
|
||||
this.sourceLocale={lang:"en",label:"English",plurals:["One","Other"]}}function g(a){a=k('<button type="button" class="button button-small icon icon-'+a+' hastip"></button>');n.require("$11","tooltip.js").init(a);return a}function c(a){return g("cloud").attr("title",a.labels[8]+" (Ctrl-U)").click(function(b){b.preventDefault();a.focus().fuzzy(!a.fuzzy())})}function b(a){return g("robot").attr("title",a.labels[9]+" (Ctrl-J)").click(function(b){b.preventDefault();a.fire("poHint")})}d=n.require("$23",
|
||||
"base.js");f.init=function(a){var b=new m;a=b.setRootCell(a);var c=a.splity("po-list","po-edit"),d=c[0],h=c[1],c=h.splitx("po-trans","po-comment"),g=c[0],f=c[1].header("Loading.."),c=g.splity("po-source","po-target"),g=c[0].header("Loading.."),c=c[1].header("Loading..");a.distribute([0.34]);h.distribute([0.8]);b.setListCell(d);b.setSourceCell(g);b.setTargetCell(c);b.commentCell=f;b.editable.source=!1;return b};d=m.prototype=d.extend(m);d.getListHeadings=function(){var a=this.t||{_x:function(a){return a}},
|
||||
b=[a._x("Source text","Editor")];this.targetLocale&&(b[1]=a._x("Translation","Editor"));return b};d.getListColumns=function(){var a={source:0};this.targetLocale&&(a.target=1);return a};d.getListEntry=function(a){var b=this.cellText,c=[function(){var c,e=b(a.source()||""),d=a.context();return d?(c=s.createElement("p"),c.appendChild(s.createElement("mark")).innerText=d,c.appendChild(s.createTextNode("\u00a0"+e)),c):e}];this.targetLocale&&(c[1]=function(){return b(a.translation()||"")});return c};d.stats=
|
||||
function(){var a=this.po,b=a.length,c=0,d=0,h=0;a.each(function(a,b){b.fuzzy()?h++:b.translated()?c++:d++});return{t:b,p:c.percent(b)+"%",f:h,u:d}};d.unlock=function(){var a=this.targetLocale;this._unlocked||(this.editable={source:!0,context:!0,target:!1},this.po&&this.po.unlock(),this.contextCell=this.targetCell,delete this.targetCell,a&&(this._unlocked=a,delete this.targetLocale,this.reload(),this.fire("poLock",[!1])),this.active&&this.loadMessage(this.active))};d.lock=function(){var a=this._unlocked;
|
||||
a&&(this.targetLocale=a,delete this._unlocked,this.po&&this.po.lock(a),this.editable={source:!1,context:!1,target:!0},this.targetCell=this.contextCell,delete this.contextCell,this.reload(),this.fire("poLock",[!0,a]),this.active&&this.loadMessage(this.active))};d.locked=function(){return!this._unlocked};d.setStatus=function(a){var d=this.$tnav;if(null==a)d&&(d.remove(),this.$tnav=null);else{d||(this.$tnav=d=k("<nav></nav>").append(c(this)).append(b(this)).appendTo(this.targetCell.header()));var e=
|
||||
[];a.translated()?a.fuzzy()&&e.push("po-fuzzy"):e.push("po-empty");d.attr("class",e.join(" "))}};d.getSorter=function(){function a(a,c){var e=a.weight(),d=c.weight();return e===d?b(a,c):e>d?-1:1}function b(a,c){return a.hash().localeCompare(c.hash())}var c=this;return function(d){var h=c.po,g=c.locked()?a:b;d.sort(function(a,b){return g(h.row(a),h.row(b))})}};return f}({},r,s));n.register("$13",function(f,d,n){var m={copy:66,clear:75,save:83,fuzzy:85,next:40,prev:38,enter:13,invis:73,hint:74},g={38:!0,
|
||||
40:!0,73:!0},c={66:function(b,a){var c=a.current();c&&(c.normalize(),a.focus().pasteMessage(c))},75:function(b,a){var c=a.current();c&&(c.untranslate(),a.focus().pasteMessage(c))},85:function(b,a){a.focus().fuzzy(!a.fuzzy())},13:function(b,a){a.getFirstEditable()&&a.next(1,!0,!0)},40:function(b,a){var c=b.shiftKey;a.next(1,c,c)},38:function(b,a){var c=b.shiftKey;a.next(-1,c,c)},73:function(b,a){if(!b.shiftKey)return!1;a.setInvs(!a.getInvs())}};f.init=function(b,a){function l(a){if(a.isDefaultPrevented()||
|
||||
!a.metaKey&&!a.ctrlKey)return!0;var d=a.which;if(!e[d])return!0;var l=c[d];if(!l)throw Error("command undefined #"+d);if(a.altKey||a.shiftKey&&!g[d]||!1===l(a,b))return!0;a.stopPropagation();a.preventDefault();return!1}var e={};k(a||d).on("keydown",l);return{add:function(a,b){c[m[a]]=b;return this},enable:function(){var a,b;for(b in arguments)a=m[arguments[b]],e[a]=!0;return this},disable:function(){k(a||d).off("keydown",l);b=a=e=null}}};return f}({},r,s));n.register("$24",function(f,d,k){function m(){this.reIndex([])}
|
||||
f.init=function(){return new m};d=m.prototype;d.reIndex=function(d){for(var c={},b=-1,a=d.length;++b<a;)c[d[b]]=b;this.keys=d;this.length=b;this.ords=c};d.key=function(d,c){if(null==c)return this.keys[d];var b=this.keys[d],a=this.ords[c];if(c!==b){if(null!=a)throw Error("Clash with item at ["+a+"]");this.keys[d]=c;delete this.ords[b];this.ords[c]=d}return d};d.indexOf=function(d){d=this.ords[d];return null==d?-1:d};d.add=function(d,c){var b=this.ords[d];null==b&&(this.keys[this.length]=d,b=this.ords[d]=
|
||||
this.length++);this[b]=c;return b};d.get=function(d){return this[this.ords[d]]};d.has=function(d){return null!=this.ords[d]};d.del=function(d){this.cut(this.ords[d],1)};d.cut=function(d,c){c=c||1;var b=[].splice.call(this,d,c);this.keys.splice(d,c);this.reIndex(this.keys);return b};d.each=function(d){for(var c=-1,b=this.keys,a=this.length;++c<a;)d(b[c],this[c],c);return this};d.sort=function(d){for(var c=-1,b=this.length,a,l=this.keys,e=this.ords,f=[];++c<b;)f[c]=[this[c],l[c]];f.sort(function(a,
|
||||
b){return d(a[0],b[0])});for(c=0;c<b;c++)a=f[c],this[c]=a[0],a=a[1],l[c]=a,e[a]=c;return this};d.join=function(d){return[].join.call(this,d)};d=null;return f}({},r,s));n.register("$25",function(f,d,k){function m(d,c){var b=RegExp("^.{0,"+(d-1)+"}["+c+"]"),a=RegExp("^[^"+c+"]+");return function(c,e){for(var f=c.length,h;f>d;){h=b.exec(c)||a.exec(c);if(null==h)break;h=h[0];e.push(h);h=h.length;f-=h;c=c.substr(h)}0!==f&&e.push(c);return e}}f.create=function(d){function c(a){return h[a]||"\\"+a}var b,
|
||||
a,l=/(?:\r\n|[\r\n\v\f\u2028\u2029])/g,e=/[ \r\n]+/g,f=/[\t\v\f\x07\x08\\\"]/g,h={"\t":"\\t","\v":"\\v","\f":"\\f","\u0007":"\\a","\b":"\\b"};if(null==d||isNaN(d=Number(d)))d=79;0<d&&(b=m(d-3," "),a=m(d-2,"-\u2013 \\.,:;\\?!\\)\\]\\}\\>"));return{pair:function(b,e){if(!e)return b+' ""';e=e.replace(f,c);var h=0;e=e.replace(l,function(){h++;return"\\n\n"});if(!(h||d&&d<e.length+b.length+3))return b+' "'+e+'"';var k=[b+' "'],m=e.split("\n");if(a)for(var n=-1,s=m.length;++n<s;)a(m[n],k);else k=k.concat(m);
|
||||
return k.join('"\n"')+'"'},prefix:function(a,b){var c=a.split(l);return b+c.join("\n"+b)},refs:function(a){a=a.replace(e," ",a);b&&(a=b(a,[]).join("\n#: "));return"#: "+a}}};return f}({},r,s));n.register("$39",function(f,d,k){function m(){this.length=0}f.init=function(){return new m};d=m.prototype;d.push=function(d){this[this.length++]=d;return this};d.sort=function(d){[].sort.call(this,d);return this};d.each=function(d){for(var c=-1,b=this.length;++c<b;)d(c,this[c]);return this};return f}({},r,s));
|
||||
n.register("$26",function(f,d,k){function m(){}f.extend=function(d){return d.prototype=new m};d=m.prototype=n.require("$37","abstract.js").init(["add","load"]);d.row=function(d){return this.rows[d]};d.lock=function(d){return this.locale(d||{lang:"zxx",label:"Unknown",nplurals:1,pluraleq:"n!=1"})};d.unlock=function(){var d=this.loc;this.loc=null;return d};d.locale=function(d){null==d?d=this.loc:this.loc=d=n.require("$36","locale.js").cast(d);return d};d.each=function(d){this.rows.each(d);return this};
|
||||
d.indexOf=function(d){"object"!==typeof d&&(d=this.get(d));if(!d)return-1;null==d.idx&&(d.idx=this.rows.indexOf(d.hash()));return d.idx};d.get=function(d){return this.rows&&this.rows.get(d)};d.has=function(d){return this.rows&&this.rows.has(d)};d.del=function(d){d=this.indexOf(d);if(-1!==d){var c=this.rows.cut(d,1);if(c&&c.length)return this.length=this.rows.length,this.rows.each(function(b,a,c){a.idx=c}),d}};d.reIndex=function(d,c){var b=this.indexOf(d),a=d.hash(),f=this.rows.indexOf(a);return f===
|
||||
b?b:-1!==f?(c=(c||0)+1,d.source("Error, duplicate "+String(c)+": "+d.source()),this.reIndex(d,c)):this.rows.key(b,a)};d.sort=function(d){this.rows.sort(d);return this};d["export"]=function(){for(var d=-1,c=this.rows,b=c.length,a=n.require("$39","list.js").init();++d<b;)a.push(c[d]);return a};d=null;return f}({},r,s));n.register("$27",function(f,d,n){function m(){function d(a){return/<[a-z]+[^>]*>/i.test(a)||/&(#\d+|#x[0-9a-f]|[a-z]+);/i.test(a)?k("<p></p>").html(a).text():a}function c(a){return a.replace(/%(?:\d+\$)?(?:'.|[-+0 ])*\d*(?:\.\d+)?[suxXbcdeEfFgGo]/g,
|
||||
"%s")}function b(a){return a.replace(/[^\sa-z0-9]+/ig," ")}function a(a){return a.trim().replace(/\s+/g," ")}function f(e){return a(b(d(c(e).toLowerCase())))}var e={},p={};return{add:function(a){var b=f(a.source());(e[b]||(e[b]=[])).push(a);p[a.hash()]=a},match:function(h){var k=f(h.source()),k=e[k],m;if(m=k){m=k.length;var q=k[0];if(1!==m)for(var n=7,A,u=h.source(),s=h.context(),r;0<=--m;)if(h=0,A=k[m],!(A.context()!==s&&++h>=n)){r=A.source();if(u!==r){if(++h>=n)continue;u=u.toLowerCase();r=r.toLowerCase();
|
||||
if(u!==r){if(++h>=n)continue;u=c(u);r=c(r);if(u!==r){if(++h>=n)continue;u=d(u);r=d(r);if(u!==r){if(++h>=n)continue;u=b(u);r=b(r);if(u!==r){if(++h>=n)continue;u=a(u);r=a(r);if(u!==r&&++h>=n)continue}}}}}n=h;q=A;if(0===h)break}delete p[q.hash()];m=q.copy()}return m},unmatched:function(){var a,b,c=[];for(a in p)b=p[a],c.push(b);return c}}}f.merge=function(f,c){var b=f.rows,a=c.rows,l=[],e=[],p=[],h=m();b.each(function(b,c){a.has(b)||(c.translated()?h.add(c):p.push(c))});f.clear();a.each(function(a,c){try{var p=
|
||||
b.get(a),k;p?(k=p.flagged(0),p.merge(c),p.flagged(0)!==k&&e.push(p)):(p=h.match(c))?(p.merge(c),e.push(p)):(p=c.copy(),l.push(p));f.add(p,"")}catch(m){d.console&&console.error(String(m))}});f.header("POT-Creation-Date",c.header("POT-Creation-Date")||f.now());return{add:l,fuz:e,del:p.concat(h.unmatched())}};return f}({},r,s));n.register("$28",function(f,d,k){function m(c,b,a){if(null==a)return c[b]||"";c[b]=a||"";return c}function g(){this._id=this.id=""}f.extend=function(c){return c.prototype=new g};
|
||||
d=g.prototype;d.flag=function(c,b){var a=this.flg||(this.flg=[]);if(null!=b)a[b]=c;else for(var d=Math.max(a.length,this.src.length,this.msg.length);0!==d--;)a[d]=c;return this};d.flagged=function(c){var b=this.flg||[];if(null!=c)return b[c]||0;for(c=b.length;0!==c--;)if(b[c])return!0;return!1};d.flags=function(){for(var c,b={},a=[],d=this.flg||[],e=d.length;0!==e--;)c=d[e],b[c]||(b[c]=!0,a.push(c));return a};d.flaggedAs=function(c,b){var a=this.flg||[];if(null!=b)return c===a[b]||0;for(var d=a.length;0!==
|
||||
d--;)if(a[d]===c)return!0;return!1};d.fuzzy=function(c,b){var a=this.flaggedAs(4,c);null!=b&&this.flag(b?4:0,c);return a};d.source=function(c,b){if(null==c)return this.src[b||0]||"";this.src[b||0]=c;return this};d.plural=function(c,b){if(null==c)return this.src[b||1]||"";this.src[b||1]=c||"";return this};d.sourceForms=function(){return this.srcF};d.targetForms=function(){return this.msgF};d.each=function(c){for(var b=-1,a=this.src,d=this.msg,e=Math.max(a.length,d.length);++b<e;)c(b,a[b],d[b]);return this};
|
||||
d.count=function(){return Math.max(this.src.length,this.msg.length)};d.pluralized=function(){return 1<this.src.length||1<this.msg.length};d.translate=function(c,b){this.msg[b||0]=c||"";return this};d.untranslate=function(c){if(null!=c)this.msg[c]="";else{var b=this.msg,a=b.length;for(c=0;c<a;c++)b[c]=""}return this};d.translation=function(c){return this.msg[c||0]||""};d.errors=function(c){return this.err&&this.err[c||0]||[]};d.translated=function(c){if(null!=c)return!!this.msg[c];var b=this.msg,a=
|
||||
b.length;for(c=0;c<a;c++)if(!b[c])return!1;return!0};d.untranslated=function(c){if(null!=c)return!this.msg[c];var b=this.msg,a=b.length;for(c=0;c<a;c++)if(b[c])return!1;return!0};d.comment=function(c){return m(this,"cmt",c)};d.notes=function(c){return m(this,"xcmt",c)};d.refs=function(c){return m(this,"rf",c)};d.format=function(c){return m(this,"fmt",c)};d.context=function(c){return m(this,"ctx",c)};d.tags=function(){return this.tg};d.toString=d.toText=function(){return this.src.concat(this.msg,this.id,
|
||||
this.ctx).join(" ")};d.weight=function(){var c=0;this.translation()||(c+=2);this.fuzzy()&&(c+=1);return c};d.equals=function(c){return this===c||this.hash()===c.hash()};d.hash=function(){return this.id};d.normalize=function(){for(var c=this.msg.length;0!==c--;)this.msg[c]=this.src[c]||""};d.disabled=function(c){return!!(this.lck||[])[c||0]};d.disable=function(c){(this.lck||(this.lck=[]))[c||0]=!0;return this};d.saved=function(c){var b=this.drt;if(null==b)return!0;if(null!=c)return!b[c];for(c=b.length;0!==
|
||||
c--;)if(b[c])return!1;return!0};d.unsave=function(c){(this.drt||(this.drt=[]))[c||0]=!0;return this};d.save=function(c){null==c?this.drt=null:(this.drt||(this.drt=[]))[c]=!1;return this};d.is=function(c){return c&&(c===this||c.idx===this.idx)};d.isHTML=function(c){if(null==c)return this.htm||!1;this.htm=c};d=null;return f}({},r,s));n.register("$14",function(f,d,k){function m(a){return{"Project-Id-Version":"PACKAGE VERSION","Report-Msgid-Bugs-To":"","POT-Creation-Date":a||"","PO-Revision-Date":a||
|
||||
"","Last-Translator":"","Language-Team":"",Language:"","Plural-Forms":"","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit"}}function g(a,b){var c=a||"";b&&(c+="\x00"+b);return c}function c(a){var b=d.console;b&&b.error&&b.error(a.message||String(a))}function b(a){return n.require("$25","format.js").create(a)}function a(a){this.locale(a);this.clear();this.head=m(this.now())}function l(a,b){this.src=[a||""];this.msg=[b||""]}f.create=function(b){return new a(b)};
|
||||
k=n.require("$26","messages.js").extend(a);k.clear=function(){this.rows=n.require("$24","collection.js").init();this.length=0};k.now=function(){function a(b,c){for(var d=String(b);d.length<c;)d="0"+d;return d}var b=new Date,c=b.getUTCFullYear(),d=b.getUTCMonth()+1,f=b.getUTCDate(),l=b.getUTCHours(),b=b.getUTCMinutes();return a(c,4)+"-"+a(d,2)+"-"+a(f,2)+" "+a(l,2)+":"+a(b,2)+"+0000"};k.header=function(a,b){var c=this.head||(this.head={});if(null==b)return this.headers()[a]||"";c[a]=b||"";return this};
|
||||
k.headers=function(a){var b,c=this.now(),d=this.head||(this.head=m(c));if(null!=a){for(b in a)d[b]=a[b];return this}var f=this.locale();a={};for(b in d)a[b]=String(d[b]);f?(a.Language=String(f)||"zxx",a["Language-Team"]=f.label||a.Language,a["Plural-Forms"]="nplurals="+(f.nplurals||"2")+"; plural="+(f.pluraleq||"n!=1")+";",b="PO-Revision-Date"):(a.Language="",a["Plural-Forms"]="nplurals=INTEGER; plural=EXPRESSION;",a["PO-Revision-Date"]="YEAR-MO-DA HO:MI+ZONE",b="POT-Creation-Date");a[b]||(a[b]=c);
|
||||
a["X-Generator"]="Loco https://localise.biz/";return a};k.get=function(a,b){var c=g(a,b);return this.rows.get(c)};k.add=function(a,b){a instanceof l||(a=new l(a));b&&a.context(b);var d=a.hash();this.rows.get(d)?c("Duplicate message at index "+this.indexOf(a)):(a.idx=this.rows.add(d,a),this.length=this.rows.length);return a};k.load=function(a){for(var b=-1,d,f,g,k,m,n,u=(g=this.locale())&&g.nplurals||2,r=[];++b<a.length;)d=a[b],null==d.parent?(f=d.source||d.id,g=d.target||"",k=d.context,f||k?(m=new l(f,
|
||||
g),m._id=d._id,k&&m.context(k),d.flag&&m.flag(d.flag,0),d.comment&&m.comment(d.comment),d.notes&&m.notes(d.notes),d.refs&&m.refs(d.refs),m.format(d.format),d.message=m,this.add(m)):0===b&&"object"===typeof g&&(this.head=g,this.headcmt=d.comment)):r.push(d);for(b=-1;++b<r.length;)try{d=r[b];f=d.source||d.id;m=a[d.parent]&&a[d.parent].message;if(!m)throw Error("parent missing for plural "+f);n=d.plural;1===n&&m.plural(f);n>=u||(d.flag&&m.flag(d.flag,n),m.translate(d.target||"",n),d.format&&!m.format()&&
|
||||
m.format(d.format))}catch(s){c(s)}return this};k.merge=function(a){return n.require("$27","merge.js").merge(this,a)};k.wrap=function(a){this.fmtr=b(a);return this};k.toString=function(){var a,c=this.locale(),d=[],f=[],g=this.headers(),k=!c,m=c&&c.nplurals||2,n=this.fmtr||b();g[c?"PO-Revision-Date":"POT-Creation-Date"]=this.now();for(a in g)f.push(a+": "+g[a]);f=new l("",f.join("\n"));f.comment(this.headcmt||"");k&&f.fuzzy(0,!0);d.push(f.toString());d.push("");this.rows.each(function(a,b){a&&(d.push(b.cat(n,
|
||||
k,m)),d.push(""))});return d.join("\n")};k=n.require("$28","message.js").extend(l);k.hash=function(){return g(this.source(),this.context())};k.toString=function(){return this.cat(b())};k.cat=function(a,b,c){var d,f=[],l;(l=this.cmt)&&f.push(a.prefix(l,"# "));(l=this.xcmt)&&f.push(a.prefix(l,"#. "));d=this.rf;if(l=this._id)d+=(d?" ":"")+"loco:"+l;d&&/\S/.test(d)&&f.push(a.refs(d));!b&&this.fuzzy()&&f.push("#, fuzzy");(l=this.fmt)&&f.push("#, "+l+"-format");(l=this._ctx)&&f.push(a.prefix(a.pair("msgctxt",
|
||||
l),"#| "));if(l=this._src)l[0]&&f.push(a.prefix(a.pair("msgid",l[0]),"#| ")),l[1]&&f.push(a.prefix(a.pair("msgid_plural",l[1]),"#| "));(l=this.ctx)&&f.push(a.pair("msgctxt",l));f.push(a.pair("msgid",this.src[0]));if(null==this.src[1])f.push(a.pair("msgstr",b?"":this.msg[0]));else for(d=-1,f.push(a.pair("msgid_plural",this.src[1])),l=this.msg||["",""],c=c||l.length;++d<c;)f.push(a.pair("msgstr["+d+"]",b?"":l[d]||""));return f.join("\n")};k.compare=function(a,b){var c=this.weight(),d=a.weight();if(c>
|
||||
d)return 1;if(c<d)return-1;if(b){c=this.hash().toLowerCase();d=a.hash().toLowerCase();if(c<d)return 1;if(c>d)return-1}return 0};k.merge=function(a){var b=!1;this.rf=a.rf;this.fmt=a.fmt;this.cmt=a.cmt;this.xcmt=a.xcmt;a.src.join("\x00")!==this.src.join("\x00")&&(this._src=this.src,this.src=a.src.concat(),this.msg=(this.msg||["",""]).slice(0,this.src.length),b=!0);a.ctx!==this.ctx&&(this._ctx=this.ctx,this.ctx=a.ctx,b=!0);b&&this.translated()&&this.fuzzy(0,!0)};k.copy=function(){var a=new l,b,c;for(b in this)this.hasOwnProperty(b)&&
|
||||
((c=this[b])&&c.concat&&(c=c.concat()),a[b]=c);return a};k=k=null;return f}({},r,s));n.register("$16",function(f,d,n){f.init=function(d,f){function c(){return e||(e=k('<div id="loco-po-ref"></div>').dialog({dialogClass:"loco-modal loco-modal-wide",modal:!0,autoOpen:!1,closeOnEscape:!0,resizable:!1,height:500}))}function b(a,b,d){a=k("<p></p>").text(d);c().dialog("close").html("").dialog("option","title","Error").append(a).dialog("open")}function a(a){var b=a&&a.code;if(b){for(var d=-1,e=b.length,
|
||||
f=k("<ol></ol>").attr("class",a.type);++d<e;)k("<li></li>").html(b[d]).appendTo(f);f.find("li").eq(a.line-1).attr("class","highlighted");c().dialog("close").html("").dialog("option","title",a.path+":"+a.line).append(f).dialog("open")}}function l(a){a=a.target;var b=k(a).find("li.highlighted")[0],b=Math.max(0,(b&&b.offsetTop||0)-Math.floor(a.clientHeight/2));a.scrollTop=b}var e;return{load:function(e){c().html('<div class="loco-loading"></div>').dialog("option","title","Loading..").off("dialogopen").dialog("open").on("dialogopen",
|
||||
l);e=k.extend({ref:e,path:f.popath},f.project||{});d.ajax.post("fsReference",e,a,b)}}};return f}({},r,s));n.register("$30",function(f,d,k){function m(d){this.api=d;this.chars=0}f.create=function(d){return new m(d)};d=m.prototype;d.init=function(d,c){function b(a){var b={length:0,html:a.html,sources:[]};q.push(b);return w[a.html?1:0]=b}function a(a,d){var g=a.source(null,d);if(g&&(a.untranslated(d)||c)){var q=n[g];if(q)q.push(a);else{var q=g.length,r=f.isHtml(g),r=w[r?1:0],s=r.sources;if(r.length+
|
||||
q>m||s.length===h)r=b(r),s=r.sources;s.push(g);n[g]=[a];r.length+=q;e+=q;k+=1}}}var f=this.api,e=0,k=0,h=50,m=5E3,n={},q=[],w=[];b({html:!1});b({html:!0});d.each(function(b,c){a(c,0);a(c,1)});w=null;this.map=n;this.chars=e;this.length=k;this.batches=q;this.locale=d.locale()};d.abort=function(){this.state="abort";return this};d.dispatch=function(){function d(a,b){function e(c,d,l){b!==l&&(a===d||1<c&&f.source(null,1)===a)&&(f.translate(b,c),q++,z++);return q}if(!c())return!1;if(!b)return m.stderr("Empty translation returned for: "+
|
||||
a),!0;var f,l=n[a]||[],h=l.length,g=-1,q;for(s++;++g<h;)if(f=l[g])q=0,f.each(e),q&&k("each",[f]);return!0}function c(){return"abort"===h.state?(m&&(m.abort(),e()),!1):!0}function b(){var b=q.shift(),c;b?(c=b.sources)&&c.length?m.batch(c,r,b.html,d).fail(a).always(f):f():e()}function a(){h.abort();e()}function f(){u++;k("prog",[u,C]);c()&&b()}function e(){m=q=null;k("done")}function k(a,b){for(var c=F[a]||[],d=c.length;0<=--d;)c[d].apply(null,b)}var h=this,m=h.api,n=h.map,q=h.batches||[],r=h.locale,
|
||||
s=0,u=0,z=0,E=h.length,C=q.length,F={done:[],each:[],prog:[]};h.state="";b();return{done:function(a){F.done.push(a);return this},each:function(a){F.each.push(a);return this},prog:function(a){F.prog.push(a);return this},stat:function(){return{todo:function(){return Math.max(E-s,0)},did:function(){return s}}}}};return f}({},r,s));n.register("$31",function(f,d,k){function m(){}f.create=function(d){d=m.prototype=new d;d.toString=function(){return"Yandex.Translate"};d.getId=function(){return"yandex"};
|
||||
d.getUrl=function(){return"https://translate.yandex.com/"};d.parseError=function(c){return c&&c.code&&200!==c.code&&c.message?String(this)+" error "+c.code+": "+c.message:""};d.batch=function(c,b,a,d){function e(a){for(var e=c.length,f=-1;++f<e&&!1!==d(c[f],a[f]||"",b););}var f=this;return f._call({url:"https://translate.yandex.net/api/v1.5/tr.json/translate?format="+(a?"html":"plain")+"&lang="+b.lang,method:"POST",traditional:!0,data:{key:f.key(),text:c}}).done(function(a,b,c){a&&200===a.code?e(a.text||
|
||||
[]):(f.stderr(f.parseError(a)||f.odderr(c)),e([]))}).fail(function(){e([])})};return new m};return f}({},r,s));n.register("$40",{zh:["zh","zh-TW"],he:["iw"],jv:["jw"]});n.register("$32",function(f,d,k){function m(){}f.create=function(d){d=m.prototype=new d;d.toString=function(){return"Google Translate"};d.getId=function(){return"google"};d.getUrl=function(){return"https://translate.google.com/"};d.parseError=function(c){if(c.error){for(var b=[],a=c.error.errors||[],d=a.length,e=-1;++e<d;)b.push(a[e].message||
|
||||
"");return String(this)+" error "+c.error.code+": "+b.join(";")}return""};d.batch=function(c,b,a,d){function e(a){for(var e=c.length,f=-1,h;++f<e&&(h=a[f]||{},!1!==d(c[f],h.translatedText||"",b)););}var f=this;a=a?"html":"text";var h=f.mapLang(b,n.require("$40","google.json"));return f._call({url:"https://translation.googleapis.com/language/translate/v2?source=en&target="+h+"&format="+a,method:"POST",traditional:!0,data:{key:f.key(),q:c}}).done(function(a){a.data?e(a.data.translations||[]):(f.stderr(f.parseError(a)||
|
||||
f.odderr(xhr)),e([]))}).fail(function(){e([])})};return new m};return f}({},r,s));n.register("$41",{pt:["pt","pt-pt"],sr:["sr-Cyrl","sr-Latn"],sr_RS:["sr-Cyrl"],tlh:["tlh-Latn","tlh-Piqd"],zh:["zh-Hans","zh-Hant"],zh_CN:["zh-Hans"],zh_HK:["zh-Hans"],zh_SG:["zh-Hans"],zh_TW:["zh-Hant"]});n.register("$33",function(f,d,k){function m(){}f.create=function(d){d=m.prototype=new d;d.toString=function(){return"Microsoft Translator text API"};d.getId=function(){return"microsoft"};d.getUrl=function(){return"https://aka.ms/MicrosoftTranslatorAttribution"};
|
||||
d.parseError=function(c){return c&&c.error?c.error.message:""};d.batch=function(c,b,a,d){function e(a){for(var e=-1,f;++e<g&&(f=a[e]||{},f=f.translations||[],f=f[0]||{},!1!==d(c[e],f.text||"",b)););}var f=this,h=[],g=c.length,k=-1;a=a?"html":"plain";for(var m=f.mapLang(b,n.require("$41","ms.json"));++k<g;)h.push({text:c[k]});return f._call({url:"https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&from=en&to="+m+"&textType="+a,method:"POST",data:JSON.stringify(h),headers:{"Content-Type":"application/json; charset=UTF-8",
|
||||
"Ocp-Apim-Subscription-Key":this.key(),"Ocp-Apim-Subscription-Region":f.param("region")||"global"}}).done(function(a){a&&a.length?e(a):(f.stderr(f.parseError(a)||f.odderr(xhr)),e([]))}).fail(function(){e([])})};return new m};return f}({},r,s));n.register("$34",function(f,d,n){function m(){}f.create=function(f){(m.prototype=new f).batch=function(c,b,a,f){function e(a){for(var d=c.length,e=-1;++e<d&&!1!==f(c[e],a[e],b););}var g=d.locoScope.ajax;a={hook:this.getId(),type:a?"html":"text",locale:String(b),
|
||||
sources:c};var h=k.Deferred();this.abortable(g.post("apis",a,function(a){e(a&&a.targets||[]);h.resolve()},function(){e([]);h.reject()}));return h.promise()};return new m};return f}({},r,s));n.register("$17",function(f,d,r){function m(){this.inf={}}function g(){var a=r.createElement("p"),b=/&(#\d+|#x[0-9a-f]|[a-z]+);/i,c=/<[a-z]+\s/i,d,f;return{sniff:function(g){if(g===d)return f;d=g;if(b.test(g)||c.test(g))if(a.innerHTML=g,a.textContent!==g)return f=!0;return f=!1}}}var c=m.prototype;c.init=function(a){this.inf=
|
||||
a||{}};c.param=function(a){return this.inf[a]||""};c.key=function(){return this.param("key")};c.getId=function(){return this.param("id")||"none"};c.getUrl=function(){return this.param("url")||"#"};c.toString=function(){return this.param("name")||this.getId()};c.stderr=function(a){var b=(d.locoScope||{}).notices||d.console;b&&b.error&&b.error(String(a))};c.odderr=function(){return String(this)+": Unknown failure"};c.parseError=function(a){return""};c.mapLang=function(a,b){var c=String(a),d=a.lang,
|
||||
f=b[c]||b[d]||[],g=f.length;if(0===g)return d;if(1<g)for(var c=c.toLowerCase(),d=-1,k;++d<g;)if(k=f[d],k.toLowerCase().replace("-","_")===c)return k;return f[0]};c.translate=function(a,b,c){return this.batch([a],b,this.isHtml(a),c)};c.batch=function(){return{always:function(a){a()}}};c._call=function(a){var b=this;a.cache=!0;a.dataType="json";a.error=function(a,c,d){try{var f=a.responseText,g=f&&k.parseJSON(f);d=g&&b.parseError(g)||d}catch(m){}b.stderr(String(b)+": "+d)};return b.abortable(k.ajax(a))};
|
||||
c.abortable=function(a){var b=this;a.always(function(){b.$r===a&&(b.$r=null)});return b.$r=a};c.abort=function(){var a=this.$r;a&&a.abort()};c.isHtml=function(a){return(b||(b=g())).sniff(a)};c.createJob=function(){return n.require("$30","job.js").create(this)};f.create=function(a){var b;b=a.id;b="yandex"===b?n.require("$31","yandex.js").create(m):"google"===b?n.require("$32","google.js").create(m):"microsoft"===b?n.require("$33","ms.js").create(m):n.require("$34","custom.js").create(m);b.init(a);
|
||||
return b};f.suggest=function(a,b,c,d){var f,g,k=a.length;for(f=0;f<k;f++)g=a[f],g.translate(b,c,d)};var b;return f}({},r,s));n.register("$18",function(f,d,n){f.init=function(f){function g(){M||(L.click(h),M=k('<div id="loco-fs-creds"></div>').dialog({dialogClass:"request-filesystem-credentials-dialog loco-modal",minWidth:580,modal:!0,autoOpen:!1,closeOnEscape:!0}).on("change",'input[name="connection_type"]',function(){this.checked&&k("#ssh-keys").toggleClass("hidden","ssh"!==k(this).val())}));return M}
|
||||
function c(){G&&(b(k(u)),G=!1);if(C&&K){var a=K,c=k(Q);c.find("span.loco-msg").text(a);J||(c.removeClass("jshide").hide().fadeIn(500),J=!0)}else J&&(b(k(Q)),J=!1)}function b(a){a.slideUp(250).fadeOut(250,function(){k(this).addClass("jshide")})}function a(){if(C)return M&&M.dialog("close"),c(),k(f).find('button[type="submit"]').attr("disabled",!1),k(d).triggerHandler("resize"),A&&A(!0),!0;x&&M?(G||(k(u).removeClass("jshide").hide().fadeIn(500),G=!0),J&&(b(k(Q)),J=!1)):c();k(f).find('input[type="submit"]').attr("disabled",
|
||||
!0);A&&A(!1);return!1}function l(a){var b,c,d=w||{};for(b in d)d.hasOwnProperty(b)&&(c=d[b],a[b]?a[b].value=c:k('<input type="hidden" />').attr("name",b).appendTo(a).val(c))}function e(a){a.preventDefault();a=k(a.target).serializeArray();q(a);H=!0;return!1}function p(a){a.preventDefault();M.dialog("close");return!1}function h(a){a.preventDefault();M.dialog("open").find('input[name="connection_type"]').change();return!1}function r(b){C=b.authed;z=b.method;k(u).find("span.loco-msg").text(b.message||
|
||||
"Something went wrong.");K=b.warning||"";b.notice&&F.notices.info(b.notice);if(C)"direct"!==z&&(w=b.creds,l(f),H&&b.success&&F.notices.success(b.success)),a();else if(b.reason)F.notices.info(b.reason);else if(b=b.prompt){var c=g();c.html(b).find("form").submit(e);c.dialog("option","title",c.find("h2").remove().text());c.find("button.cancel-button").show().click(p);c.find('input[type="submit"]').addClass("button-primary");a();k(d).triggerHandler("resize")}else F.notices.error("Server didn't return credentials, nor a prompt for credentials")}
|
||||
function s(){a()}function q(a){H=!1;F.ajax.setNonce("fsConnect",I).post("fsConnect",a,r,s);return a}var w,A,u=f,z=null,H=!1,C=!1,F=d.locoScope,x=f.path.value,B=f.auth.value,I=f["loco-nonce"].value,L=k(u).find("button.button-primary"),Q=n.getElementById(u.id+"-warn"),G=!1,J=!1,K="",M;F.notices.convert(Q).stick();f.connection_type?(w={},w.connection_type=f.connection_type.value,C=!0):x&&B&&q({path:x,auth:B});a();return{applyCreds:function(a){if(a.nodeType)l(a);else{var b,c=w||{};for(b in c)c.hasOwnProperty(b)&&
|
||||
(a[b]=c[b])}return this},setForm:function(b){f=b;a();l(b);return this},connect:function(){x=f.path.value;B=f.auth.value;q(k(f).serializeArray());return this},listen:function(a){A=a;C&&a(!0);return this}}};return f}({},r,s));n.register("$19",function(f,d,r){function m(d,e,f,h){e="n"===f?c(e):b(e);h&&(e=a(e));return g([].sort,[e])(d)}function g(a,b){return function(c){a.apply(c,b);return c}}function c(a){return function(b,c){var d=b&&b[a]||0,f=c&&c[a]||0;return d===f?0:d>f?1:-1}}function b(a){return function(b,
|
||||
c){return(b&&b[a]||"").localeCompare(c&&c[a]||"")}}function a(a){return function(b,c){return-1*a(b,c)}}f.init=function(a){function b(a){var c=-1,d=a.length;for(k("tr",u).remove();++c<d;)u.appendChild(a[c].$)}function c(a){q=a?E.find(a,d):d.slice(0);s&&(a=f[s],q=m(q,s,a.type,a.desc));b(q)}var d=[],f=[],g=0,q,r,s,u=a.getElementsByTagName("tbody")[0],z=a.getElementsByTagName("thead")[0],E=n.require("$9","fulltext.js").init();z&&u&&(k("th",z).each(function(a,c){var l=c.getAttribute("data-sort-type");
|
||||
l&&(a=g,k(c).addClass("loco-sort").click(function(c){c.preventDefault();c=a;var g=f[c],l=g.type,n=!(g.desc=!g.desc);q=m(q||d.slice(0),c,l,n);b(q);r&&r.removeClass("loco-desc loco-asc");r=k(g.$).addClass(n?"loco-desc":"loco-asc").removeClass(n?"loco-asc":"loco-desc");s=c;return!1}),f[g]={$:c,type:l});c.hasAttribute("colspan")?g+=Number(c.getAttribute("colspan")):g++}),k("tr",u).each(function(a,b){var c,e,g,k=[],l={_:a,$:b},m=b.getElementsByTagName("td");for(e in f){c=m[e];(g=c.textContent.replace(/(^\s+|\s+$)/g,
|
||||
""))&&k.push(g);c.hasAttribute("data-sort-value")&&(g=c.getAttribute("data-sort-value"));switch(f[e].type){case "n":g=Number(g)}l[e]=g}d[a]=l;E.index(a,k)}),a=k('form.loco-filter input[type="text"]',a.parentNode),a.length&&(a=a[0],z=k(a.form),1<d.length?n.require("$10","LocoTextListener.js").listen(a,c):z.hide(),z.on("submit",function(a){a.preventDefault();return!1})))};return f}({},r,s));s=r.locoScope||(r.locoScope={});r=r.locoConf||(r.locoConf={});var G=n.require("$1","t.js").init(),K=r.wplang;
|
||||
n.require("$2","html.js");n.require("$3","number.js");n.require("$4","array.js");s.l10n=G;G.load(r.wpl10n);K&&G.pluraleq(K.pluraleq);s.string=n.require("$5","string.js");s.notices=n.require("$6","notices.js").init(G);s.ajax=n.require("$7","ajax.js").init(r).localise(G);s.locale=n.require("$8","wplocale.js");s.fulltext=n.require("$9","fulltext.js");s.watchtext=n.require("$10","LocoTextListener.js").listen;s.tooltip=n.require("$11","tooltip.js");s.po={ed:n.require("$12","poedit.js"),kbd:n.require("$13",
|
||||
"hotkeys.js"),init:n.require("$14","po.js").create,ace:n.require("$15","ace.js").strf("php"),ref:n.require("$16","refs.js")};s.apis=n.require("$17","apis.js");s.fs=n.require("$18","fsconn.js");k("#loco.wrap table.wp-list-table").each(function(f,d){n.require("$19","tables.js").init(d)})})(window,document,window.jQuery);
|
1
vendor/loco-translate/pub/js/min/config.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(n,e,c){function o(){var n=c("#loco-conf > div"),e=n.eq(0).clone(),o=n.length,t="["+o+"]";function i(n,e){var o=e.name.replace("[0]",t);c(e).attr("name",o).val("")}e.attr("id","loco-conf-"+o),e.find("input").each(i),e.find("textarea").each(i),e.find("h2").eq(0).html("New set <span>(untitled)</span>"),e.insertBefore("#loco-form-foot"),f(e.find("a.icon-del"),o),e.hide().slideDown(500),c("html, body").animate({scrollTop:function(n,e){for(var o=n.offsetTop;(n=n.offsetParent)&&n!==e;)o+=n.offsetTop;return o}(e[0])},500)}function f(n,e){return n.click(function(n){return n.preventDefault(),function(n){var e=c("#loco-conf-"+n);e.find('input[name="conf['+n+'][removed]"]').val("1"),e.slideUp(500,function(){c(this).hide().find("table").remove()})}(e),!1})}c("#loco-conf > div").each(function(n,e){f(c(e).find("a.icon-del"),n)}),c("#loco-add-butt").attr("disabled",!1).click(function(n){return n.preventDefault(),o(),!1})}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/debug.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(n,o,t){var a=t("#loco-utf8-check")[0].textContent;function c(o,a,e){"success"!==a&&(e=n.ajax.parse(n.ajax.strip(o.responseText))),t("#loco-ajax-check").text("FAILED: "+e).addClass("loco-danger")}1===a.length&&10003===a.charCodeAt(0)||n.notices.warn("This page has a problem rendering UTF-8").stick(),window.ajaxurl&&t("#loco-ajax-url").text(window.ajaxurl),n.ajax.post("ping",{echo:"ΟΚ ✓"},function(o,a,e){o&&o.ping?t("#loco-ajax-check").text(o.ping):c(e,a,o&&o.error&&o.error.message)},c);var e,r=o.apis,i=r.length,s=-1,l=n.locale.parse("fr");function d(o,a){return t("#loco-api-"+o).text(a)}function p(o){var e=o.getId();o.key()?o.translate("OK",l,function(o,a){a?d(e,"OK ✓"):d(e,"FAILED").addClass("loco-danger")}):d(e,"No API key")}for(;++s<i;){e=r[s];try{p(n.apis.create(e))}catch(o){d(e.id,String(o))}}}(window.locoScope,window.locoConf,window.jQuery);
|
1
vendor/loco-translate/pub/js/min/delete.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(e,o){var t=o.getElementById("loco-fs"),n=o.getElementById("loco-del");t&&n&&e.locoScope.fs.init(t).setForm(n)}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/editor.js
vendored
Normal file
1
vendor/loco-translate/pub/js/min/move.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(e,t,o){var c,u,i=t.getElementById("loco-fs"),a=t.getElementById("loco-move"),l=a.path.value;function d(n){o(a).find("button.button-primary").each(function(e,t){t.disabled=n})}i&&a&&(c=e.locoScope.fs.init(i).setForm(a).listen(function(e){d(!(e&&u))}),o(a).change(function(e){var t,n=e.target||{};"dest"!==n.name||!n.checked&&"text"!==n.type||(t=n.value)&&t!==u&&(u=t,d(!0),l!==t&&(i.dest.value=t,c.connect()))}).submit(function(e){return!!u||(e.preventDefault(),!1)}))}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/podiff.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(e,t,u){var i,o=[],n=e.locoConf,s=e.locoScope,a=0,r=n.paths.length-2,d=t.getElementById("loco-ui"),l=t.getElementById("loco-fs"),f=d.getElementsByTagName("form").item(0),c=d.getElementsByTagName("button"),m=u(d).find("div.diff-meta"),p=c.item(0),g=c.item(1);function h(){return u(d).removeClass("loading")}function v(e){return u(d).find("div.diff").html(e)}function C(e){return h(),u('<p class="error"></p>').text(e).appendTo(v(""))}function y(e,t){var n,a=t.getElementsByTagName("tr"),r=a.length,i=t.getAttribute("data-diff").split(/\D+/),o=i[0],s=i[1],d=i[2],l=i[3];function f(e,t,n){t<=n&&u("<span></span>").text(String(t)).prependTo(e)}for(e=0;e<r;e++)f((n=a[e].getElementsByTagName("td"))[0],o++,s),f(n[2],d++,l)}function j(a){i&&i.abort();var r=o[a];if(null!=r)return v(r),void h();v(""),u(d).addClass("loading"),i=s.ajax.post("diff",{lhs:n.paths[a],rhs:n.paths[a+1]},function(e,t,n){n===i&&((r=e&&e.html)?(v(o[a]=r).find("tbody").each(y),h()):C(e&&e.error||"Unknown error"))},function(e,t,n){e===i&&(i=null,C("Failed to generate diff"))})}function b(e){0<=e&&e<=r&&(j(a=e),function(){var e=a,t=e+1;p.disabled=r<=e,g.disabled=e<=0,m.addClass("jshide").removeClass("diff-meta-current"),m.eq(e).removeClass("jshide").addClass("diff-meta-current"),m.eq(t).removeClass("jshide")}())}l&&f&&s.fs.init(l).setForm(f),r&&(u(p).click(function(e){return e.preventDefault(),b(a+1),!1}).parent().removeClass("jshide"),u(g).click(function(e){return e.preventDefault(),b(a-1),!1}).parent().removeClass("jshide")),b(0)}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/poinit.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(t,e,c){var i,n,a,l,o,r,u,s=t.locoScope,f=e.getElementById("loco-fs"),d=e.getElementById("loco-poinit"),v=f&&s.fs.init(f),g=(a=(n=d)["select-locale"],l=n["custom-locale"],o=n["use-selector"],r=c(a).focus(p).closest("fieldset").click(p)[0],u=c(l).focus(x).closest("fieldset").click(x)[0],c(o).change(m),m(),s.watchtext(l,function(t){c(l.form).triggerHandler("change")}),{val:function(){var t=b();return t?s.locale.parse(t):s.locale.clone({lang:"zxx"})}});function h(){return o[0].checked}function p(){y(o[0].checked=!0)}function x(){l.value||(l.value=b()),y(!(o[1].checked=!0))}function b(){var t=c(h()?a:l).serializeArray();return t[0]&&t[0].value||""}function m(){return y(h()),!0}function y(t){l.disabled=t,a.disabled=!t,u.className=t?"disabled":"active",r.className=t?"active":"disabled",I()}var z,A=(z=d["select-path"],{val:function(){var t=k("path");return t&&t.value},txt:function(){var t=k("path");return t&&c(t.parentNode).find("code.path").text()}});function k(t){var e=function(){var t=c(z).serializeArray()[0];return t&&t.value||null}();return e&&d[t+"["+e+"]"]}function w(n){c(d).find("button.button-primary").each(function(t,e){e.disabled=n})}function I(){var t=g&&g.val(),e=t&&t.isValid()&&"zxx"!==t.lang,n=A&&A.val(),a=e&&n;if(j(t),w(!0),a){var c=A.txt();c!==i?(i=c,f.path.value=i,v.listen(N).connect()):w(!1)}}function N(t){w(!t)}function j(n){var t=c(d),e=n&&n.toString("_")||"",a=e?"zxx"===e?"<locale>":e:"<invalid>";t.find("code.path span").each(function(t,e){e.textContent=a}),t.find("span.lang").each(function(t,e){!function(t,e){e&&"zxx"!==e.lang?(t.setAttribute("lang",e.lang),t.setAttribute("class",e.getIcon())):(t.setAttribute("lang",""),t.setAttribute("class","lang nolang"))}(e,n)})}function B(t){var e=t&&t.redirect;e&&location.assign(e)}c(d).change(I).submit(function(t){return t.preventDefault(),v.applyCreds(d),s.ajax.submit(t.target,B),!1}),j(g.val())}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/potinit.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(t,e,n){var o=t.locoScope,i=e.getElementById("loco-fs"),c=e.getElementById("loco-potinit");function r(t){var e=t&&t.redirect;e&&location.assign(e)}n(c).submit(function(t){return t.preventDefault(),o.ajax.submit(t.target,r),!1}),i&&o.fs.init(i).setForm(c)}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/poview.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(n,o,f){var a,c,i,l,r,p,e,s,u,t=n.locoConf,d=n.locoScope,h=d.po.ref.init(d,t),v=o.getElementById("loco-po");function g(){r.length&&(p.push([i,l]),c.push(r),r=[]),i=null}function m(t){return f('<ol class="msgcat"></ol>').attr("start",t).appendTo(a)}function x(t){e!==t&&(f("#loco-content")[t?"removeClass":"addClass"]("loco-invalid"),e=t)}a=v,c=d.fulltext.init(),r=[],p=[],s=!(e=!0),(u=f(a).find("li")).each(function(t,e){var n,o=f(e);o.find("span.po-none").length?g():(l=t,null==i&&(i=t),(n=o.find(".po-text").text())&&(r=r.concat(n.replace(/\\[ntvfab\\"]/g," ").split(" "))))}),g(),d.watchtext(f(a.parentNode).find("form.loco-filter")[0].q,function(t){t?function(t){var e,n,o,i=c.find(t),l=-1,r=i.length;if(f("ol",a).remove(),r){for(;++l<r;)for(o=m((e=(n=p[i[l]])[0])+1);e<=n[1];e++)o.append(u[e]);x(!0)}else x(!1),m(0).append(f("<li></li>").text(d.l10n._("Nothing matches the text filter")));s=!0,b()}(t):s&&(x(!0),s=!1,f("ol",a).remove(),m(1).append(u),b())}),f(v).removeClass("loco-loading");var C,y,b=(y=v.clientHeight-2,function(){var t=function(t,e){for(var n=t.offsetTop||0;(t=t.offsetParent)&&t!==e;)n+=t.offsetTop||0;return n}(v,o.body),e=n.innerHeight-t-20;C!==e&&(v.style.height=e<y?String(e)+"px":"",C=e)});b(),f(n).resize(b),f(v).click(function(t){var e=t.target;if(e.hasAttribute("href"))return t.preventDefault(),h.load(e.textContent),!1})}(window,document,jQuery);
|
1
vendor/loco-translate/pub/js/min/setup.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
!function(e,o,a){function n(e,o,n){function r(){i("Failed to contact remote API"),c=null}function u(){c&&(clearTimeout(c),c=null)}var c=setTimeout(r,3e3);return i(""),a.ajax({url:s.apiUrl+"/"+e+"/"+o+".jsonp?version="+encodeURIComponent(n),dataType:"jsonp",success:function(e,o,n){if(c){u();var t=e&&e.exact;o=e&&e.status;t?function(e){d["json-content"].value=e,a("#loco-remote-empty").hide(),a("#loco-remote-found").show()}(t):404===o?i("Sorry, we don't know a bundle by this name"):(l.notices.debug(e.error||"Unknown server error"),r())}},error:function(){c&&(u(),r())},cache:!0}),{abort:u}}function i(e){d["json-content"].value="",a("#loco-remote-empty").show().find("span").text(e),a("#loco-remote-found").hide().removeClass("jshide")}var t,l=e.locoScope,s=e.locoConf,d=o.getElementById("loco-remote");a(d).find('button[type="button"]').click(function(e){return e.preventDefault(),t&&t.abort(),t=n(d.vendor.value,d.slug.value,d.version.value),!1}),a(d).find('input[type="reset"]').click(function(e){return e.preventDefault(),i(""),!1});a.ajax({url:s.apiUrl+"/vendors.jsonp",dataType:"jsonp",success:function(e){for(var o,n,t=-1,r=e.length,u=a(d.vendor).html("");++t<r;)o=e[t][0],n=e[t][1],u.append(a("<option></option>").attr("value",o).text(n))},cache:!0})}(window,document,jQuery);
|
367
vendor/loco-translate/readme.txt
vendored
Normal file
|
@ -0,0 +1,367 @@
|
|||
=== Loco Translate ===
|
||||
Contributors: timwhitlock
|
||||
Tags: translation, translators, localization, localisation, l10n, i18n, Gettext, PO, MO, productivity, multilingual, internationalization
|
||||
Requires at least: 4.1
|
||||
Requires PHP: 5.2.4
|
||||
Tested up to: 5.4.1
|
||||
Stable tag: 2.4.0
|
||||
License: GPLv2 or later
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Translate WordPress plugins and themes directly in your browser
|
||||
|
||||
|
||||
== Description ==
|
||||
|
||||
Loco Translate provides in-browser editing of WordPress translation files.
|
||||
|
||||
It also provides localization tools for developers, such as extracting strings and generating templates.
|
||||
|
||||
Features include:
|
||||
|
||||
* Built-in translation editor within WordPress admin
|
||||
* Integration with automatic translation APIs
|
||||
* Create and update language files directly in your theme or plugin
|
||||
* Extraction of translatable strings from your source code
|
||||
* Native MO file compilation without the need for Gettext on your system
|
||||
* Support for PO features including comments, references and plural forms
|
||||
* PO source view with clickable source code references
|
||||
* Protected language directory for saving custom translations
|
||||
* Configurable PO file backups with diff and restore capability
|
||||
* Built-in WordPress locale codes
|
||||
|
||||
|
||||
Official [Loco](https://localise.biz/) WordPress plugin by Tim Whitlock.
|
||||
For more information please visit our [plugin page](https://localise.biz/wordpress/plugin).
|
||||
|
||||
|
||||
== Installation ==
|
||||
|
||||
= Basic usage: =
|
||||
|
||||
Translators: To translate a theme into your language, follow these steps:
|
||||
|
||||
1. Create the protected languages directory at `wp-content/languages/loco/themes`
|
||||
2. Ensure this directory writeable by the web server
|
||||
3. Find your theme in the list at *Loco Translate > Themes*
|
||||
4. Click `+ New language` and follow the on-screen prompts.
|
||||
|
||||
|
||||
Developers: To translate your own theme or plugin for distribution, follow these steps:
|
||||
|
||||
1. Create a `languages` subdirectory in your bundle’s root directory
|
||||
2. Ensure this directory writeable by the web server
|
||||
3. Find the bundle at either *Loco Translate > Themes* or *Loco Translate > Plugins*
|
||||
4. Click `+ Create template` and follow the on-screen prompts to extract your strings.
|
||||
5. Click `+ New language` and follow the on-screen prompts to add your own translations.
|
||||
|
||||
|
||||
= Installing manually: =
|
||||
|
||||
1. Unzip all files to the `wp-content/plugins/loco-translate` directory
|
||||
2. Log into WordPress admin and activate the 'Loco Translate' plugin through the 'Plugins' menu
|
||||
3. Go to *Loco Translate > Home* in the left-hand menu to start translating
|
||||
|
||||
|
||||
More information on using the plugin is [available here](https://localise.biz/wordpress/plugin).
|
||||
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
Please visit the [FAQs page](https://localise.biz/wordpress/plugin/faqs) on our website for the most common issues.
|
||||
|
||||
= How do I use Loco Translate? =
|
||||
|
||||
Try our [Guides and Tutorials](https://localise.biz/wordpress/plugin#guides).
|
||||
|
||||
= How do I get more help? =
|
||||
|
||||
If you have a problem using Loco Translate, please try our [help pages](https://localise.biz/wordpress/plugin).
|
||||
There's a lot of information there to help you understand how it works and the most common pitfalls to avoid.
|
||||
|
||||
To report a bug please start a new topic in the [support forum](https://wordpress.org/support/plugin/loco-translate),
|
||||
but please check the [FAQs](https://localise.biz/wordpress/plugin/faqs) for similar issues first.
|
||||
If you decide to submit a bug report please post enough [relevant detail](https://localise.biz/wordpress/plugin/faqs/debug-info) for us to reproduce your issue.
|
||||
|
||||
= Is my data protected? =
|
||||
|
||||
We don't collect your data or snoop on you. See the [plugin privacy notice](https://localise.biz/wordpress/plugin/privacy).
|
||||
|
||||
|
||||
== Screenshots ==
|
||||
|
||||
1. Translating strings in the browser with the Loco PO Editor
|
||||
2. Showing translation progress for theme language files
|
||||
3. PO source view with text filter and clickable file references
|
||||
4. Restore tab showing PO diff view with revert function
|
||||
5. Showing access to translations by installed language
|
||||
|
||||
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 2.4.0
|
||||
* Added support for third party translation APIs
|
||||
* Added file references to editor source pane in code view
|
||||
* Added fuzzy matching during editor Sync operation
|
||||
* Style changes including rearrangement of editor buttons
|
||||
* Elevated warnings when scripts are tampered with
|
||||
* Removed remnants of legacy version 1.x
|
||||
|
||||
= 2.3.4 =
|
||||
* Updated translatable strings
|
||||
* Added missing template recommendation
|
||||
* Alerting in debug mode when scripts are tampered with
|
||||
* Fix for Hello Dolly being installed into a folder
|
||||
* Removed translation column in POT edit mode
|
||||
* Added setting to prevent 'translating' of POT files
|
||||
* Enabled some linkable translations using wp_kses
|
||||
* Bumped WordPress version to 5.4.1
|
||||
|
||||
= 2.3.3 =
|
||||
* Fixed fatal error when class not found
|
||||
|
||||
= 2.3.2 =
|
||||
* Removed login/email from default Last-Translator credit
|
||||
* Bumped WP compatibility to 5.4
|
||||
* Fixed PHP 7.4 deprecations
|
||||
|
||||
= 2.3.1 =
|
||||
* Default POT getter now looks in "lang" directory
|
||||
* Not calling deprecated magic quotes functions under PHP 7.4
|
||||
* Fixed issue with conflicting page hooks
|
||||
* Ajax file uploads now enabled by default
|
||||
* Removed legacy option migrations from 1.x branch
|
||||
* Bumped WP compatibility to 5.2.4
|
||||
|
||||
= 2.3.0 =
|
||||
* Added experimental support for multipart uploads
|
||||
* Added relocation tab for moving translation sets
|
||||
* Creation of missing directories when writing new files
|
||||
* Fixed duplicate file addition when iterating over symlink
|
||||
* Bumped WP compatibility to 5.2.1
|
||||
|
||||
= 2.2.2 =
|
||||
* Security fixes for reading sensitive files
|
||||
* Fixed old PHP version error in data files
|
||||
* Bumped WP compatibility to 5.1.1
|
||||
|
||||
= 2.2.1 =
|
||||
* Fixed bug where plural tabs not displaying RTL
|
||||
* Various improvements to PO parser incl. better charset handling
|
||||
* Excluding node_modules and vendor directories by default
|
||||
* Transients now have maximum lifespan of 10 days, refreshed after 24h
|
||||
* Symlink fix for followed theme paths detected outside theme
|
||||
* Deprecated config repository lookup
|
||||
* Bumped WP compatibility to 5.1
|
||||
|
||||
= 2.2.0 =
|
||||
* Fix for empty language code when getting plural rules
|
||||
* Added X-Loco-Version header to generated Gettext files
|
||||
* Added sanity check for mbstring.func_overload madness
|
||||
* Added "Assign template" link on missing template page
|
||||
* Added JavaScript string extraction (experimental)
|
||||
* Editor supports sprintf-js when javascript-format tag present
|
||||
* Fix for duplicate comments when end punctuation differs
|
||||
* Marking msgctxt more clearly in editor views
|
||||
* Added `loco_admin_shutdown` action hook
|
||||
* Bumped WP compatibility to 5.0 (beta)
|
||||
|
||||
= 2.1.5 =
|
||||
* Updated locale data
|
||||
* Minor fix to file reference resolution
|
||||
* Fixed windows paths with trailing backslash
|
||||
* Fixed ssh-keys toggling issue
|
||||
* Rejigged buffer handling during Ajax
|
||||
* Bumped WP compatibility to 4.9.8
|
||||
|
||||
= 2.1.4 =
|
||||
* Bumped WP compatibility to 4.9.6
|
||||
* Hooked in privacy policy suggestion
|
||||
|
||||
= 2.1.3 =
|
||||
* Added loco_locale_name filter and updated locale data
|
||||
* Fixed editor column sorting to update as values change
|
||||
* Supporting RTL text in editor preview rows
|
||||
* Minor refactor of debug mode routing check
|
||||
* Minor PO parser improvements
|
||||
* Bumped WP compatibility to 4.9.5
|
||||
|
||||
= 2.1.2 =
|
||||
* Fixed undeclared property in admin hook
|
||||
* Fixed incompatibility with older WordPress
|
||||
* Fixed incorrect millisecond reporting in footer
|
||||
* Removed locale progress column for en_US locale
|
||||
* Tweaks to debugging and error logging
|
||||
|
||||
= 2.1.1 =
|
||||
* Setting `Project-Id-Version` on new POT files
|
||||
* Added source view to quick links in file tables
|
||||
* Supporting only WordPress style locale codes
|
||||
* Editor screen tolerates missing PO headers
|
||||
* Ajax debugging improvements for issue reporting
|
||||
* Added loco_parse_locale action callback
|
||||
|
||||
= 2.1.0 =
|
||||
* Add `fs_protect` setting to avoid overwriting system files
|
||||
* Fixed bug in connect dialogue where errors not redisplayed
|
||||
* Minor improvements to inline notices
|
||||
* Removed downgrade notice under version tab
|
||||
* Fixed extraction bug where file header confused with comment
|
||||
* Resolved some inconsistencies between PHP and JS utilities
|
||||
* Added Restore tab with diff display
|
||||
* Added `loco_settings` hook
|
||||
* Prevented editor from changing PO document order
|
||||
* Added default string sorting to extracted strings
|
||||
* Added "Languages" section for grouping files by locale
|
||||
* Fixed bug where translations loaded before user profile language set
|
||||
* Added loco_locale_plurals filter for customising plural rules
|
||||
* Allowing PO files to enforce their own Plural-Forms rules
|
||||
* Added `loco_allow_remote` filter for debugging remote problems
|
||||
* Updated plural forms from Unicode CLDR
|
||||
* PHP extractor avoids repeated comments
|
||||
* Bumped WP compatibility to 4.9.4
|
||||
|
||||
= 2.0.17 =
|
||||
* Unofficial languages showing in “Installed” dropdown
|
||||
* Fixed extraction bug where comment confused with file header
|
||||
* Fixed issue where src attributes requested from server during HTML strip
|
||||
* Added loco_admin_init hook into ajax router for consistency
|
||||
* Added warning on file info page when file is managed by WordPress
|
||||
* Minor help link and layout tweaks
|
||||
* Bumped WP compatibility to 4.9.1
|
||||
|
||||
= 2.0.16 =
|
||||
* File writer observes wp_is_file_mod_allowed
|
||||
* Fixed progress bug in editor for locales with nplurals=1
|
||||
* Made plural form categories translatable for editor UI
|
||||
* Sync-from-source raises warning when files are skipped
|
||||
* Added hack for extracting from .twig as per .php
|
||||
* Added warning when child themes declare parent text domain
|
||||
* Added option to control PO line wrapping
|
||||
* Bumped WP compatibility to 4.8.2
|
||||
|
||||
= 2.0.15 =
|
||||
* Permanently removed legacy version 1.x
|
||||
* Fixed bug where editor code view was not redrawn on resize
|
||||
* Fixed bug where fuzzy flag caused format flag to be ignored
|
||||
* Fixed bug where autoloader responded to very long class names
|
||||
* Purging WP object cache when active plugin list changes
|
||||
* Added experimental source word count into POT info tab
|
||||
* Bumped WP compatibility to 4.8.1
|
||||
|
||||
= 2.0.14 =
|
||||
* Editor improvements inc. column sorting
|
||||
* Added warnings that legacy version will be removed
|
||||
* Added PO source view text filtering
|
||||
* Added _fs_nonce for 4.7.5 compatibility
|
||||
* Migrated to canonical text domain
|
||||
* Removed wp class autoloading
|
||||
|
||||
= 2.0.13 =
|
||||
* CSS conflict fixes
|
||||
* Added option for UTF-8 byte order mark
|
||||
* Printf highlighting observes no-php-format flag
|
||||
* Fixed issue with translator role losing “read” permission
|
||||
|
||||
= 2.0.12 =
|
||||
* Minor fix for root path configs
|
||||
* Added alternative PHP extensions setting
|
||||
* Bumped WP version to 4.7.3
|
||||
* LoadHelper fix for core files
|
||||
* Allow revoking of permissions from translator role
|
||||
* Allow network admins to deny access to site admins
|
||||
|
||||
= 2.0.11 =
|
||||
* Extra debug logging and error diagnostics
|
||||
* Forcefully clear output buffers before Ajax flush
|
||||
* Bumped WordPress version to 4.7
|
||||
* Experimental wildcard text domain support
|
||||
|
||||
= 2.0.10 =
|
||||
* Allows missing domain argument in plugin_locale filter
|
||||
* Reverted editor changes that disabled readonly text
|
||||
* Added invisibles and coding editor switches
|
||||
* Added table filtering via text query
|
||||
* Added Last-Translator user preference
|
||||
|
||||
= 2.0.9 =
|
||||
* Bumped minimum WordPress version to 4.1
|
||||
* Some optimisation of transient caching
|
||||
* Fixed hash table settings bug
|
||||
|
||||
= 2.0.8 =
|
||||
* Source refs fix for files in unknown subsets
|
||||
* Downgrades PO formatting exceptions to PHP warnings
|
||||
* Renamed function prefixes to avoid PHP 7 warnings
|
||||
* Better support for php-format and no-php-format flag
|
||||
* PO source and editor UI tweaks
|
||||
* Localised strings and implemented in js
|
||||
|
||||
= 2.0.7 =
|
||||
* Fixed prototype.js conflict
|
||||
* More Windows file path fixes
|
||||
* Added loco_current_translator filter
|
||||
* Fixed false positive in extra files test
|
||||
|
||||
= 2.0.6 =
|
||||
* PO wrapping bugfix
|
||||
* Downgraded source code bugfix
|
||||
* Tolerating headerless POT files
|
||||
* Core bundle metadata tweaks
|
||||
|
||||
= 2.0.5 =
|
||||
* Deferred missing tokenizer warning
|
||||
* Allows editing of files in unconfigured sets
|
||||
* Added maximum PHP file size for string extraction
|
||||
* Display of PHP fatal errors during Ajax
|
||||
|
||||
= 2.0.4 =
|
||||
* Reduced session failures to debug notices
|
||||
* Added wp_roles support for WP < 4.3
|
||||
* Fixed domain listener bugs
|
||||
|
||||
= 2.0.3 =
|
||||
* Added support for Windows servers
|
||||
* Removed incomplete config warning on bundle overview
|
||||
|
||||
= 2.0.2 =
|
||||
* Fixed bug when absolute path used to get plugins
|
||||
* Added loco_plugins_data filter
|
||||
* Added theme Template Name header extraction
|
||||
* Minor copy amends
|
||||
|
||||
= 2.0.1 =
|
||||
* Added help link in settings page
|
||||
* Fixed opendir warnings in legacy code
|
||||
* Catching session errors during init
|
||||
* Removing meta row link when plugin not found
|
||||
|
||||
= 2.0.0 =
|
||||
* First release of completely rebuilt version 2
|
||||
|
||||
|
||||
== Upgrade Notice ==
|
||||
|
||||
= 2.4.0 =
|
||||
* Various improvements including automatic translation support
|
||||
|
||||
|
||||
|
||||
== Keyboard shortcuts ==
|
||||
|
||||
The PO file editor supports the following keyboard shortcuts for faster translating:
|
||||
|
||||
* Done and Next: `Ctrl ↵`
|
||||
* Next string: `Ctrl ↓`
|
||||
* Previous string: `Ctrl ↑`
|
||||
* Next untranslated: `Shift Ctrl ↓`
|
||||
* Previous untranslated: `Shift Ctrl ↑`
|
||||
* Copy from source text: `Ctrl B`
|
||||
* Clear translation: `Ctrl K`
|
||||
* Toggle Fuzzy: `Ctrl U`
|
||||
* Save PO / compile MO: `Ctrl S`
|
||||
* Toggle invisibles: `Shift Ctrl I`
|
||||
* Suggest translation: `Ctrl J`
|
||||
|
||||
Mac users can use ⌘ Cmd instead of Ctrl.
|
473
vendor/loco-translate/src/Locale.php
vendored
Normal file
|
@ -0,0 +1,473 @@
|
|||
<?php
|
||||
/**
|
||||
* Represents a WordPress locale
|
||||
*
|
||||
* @property string $lang
|
||||
* @property string $region
|
||||
* @property string $variant
|
||||
*/
|
||||
class Loco_Locale implements JsonSerializable {
|
||||
|
||||
/**
|
||||
* Language subtags
|
||||
* @var array
|
||||
*/
|
||||
private $tag;
|
||||
|
||||
/**
|
||||
* Cached composite tag
|
||||
* @var string
|
||||
*/
|
||||
private $_tag;
|
||||
|
||||
/**
|
||||
* Cached icon css class
|
||||
* @var string
|
||||
*/
|
||||
private $icon;
|
||||
|
||||
/**
|
||||
* Name in English
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Name in language of self
|
||||
* @var string
|
||||
*/
|
||||
private $_name;
|
||||
|
||||
/**
|
||||
* Cache of raw plural data
|
||||
* @var array
|
||||
*/
|
||||
private $plurals;
|
||||
|
||||
/**
|
||||
* Validity cache
|
||||
* @var bool
|
||||
*/
|
||||
private $valid;
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
public static function parse( $tag ){
|
||||
$locale = new Loco_Locale('');
|
||||
try {
|
||||
$locale->setSubtags( loco_parse_wp_locale($tag) );
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// isValid should return false
|
||||
}
|
||||
do_action( 'loco_parse_locale', $locale, $tag );
|
||||
return $locale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Construct from subtags NOT from composite tag. See self::parse
|
||||
* Note that this skips normalization and validation steps
|
||||
* @param string
|
||||
* @param string
|
||||
* @param string
|
||||
*/
|
||||
public function __construct( $lang = '', $region = '', $variant = '' ){
|
||||
$this->tag = compact('lang','region','variant');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Allow read access to subtags
|
||||
*/
|
||||
public function __get( $t ){
|
||||
return isset($this->tag[$t]) ? $this->tag[$t] : '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Allow write access to subtags
|
||||
*/
|
||||
public function __set( $t, $s ){
|
||||
if( isset($this->tag[$t]) ){
|
||||
$this->tag[$t] = $s;
|
||||
$this->setSubtags( $this->tag );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set subtags as produced from loco_parse_wp_locale
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
public function setSubtags( array $tag ){
|
||||
$this->valid = false;
|
||||
$default = array( 'lang' => '', 'region' => '', 'variant' => '' );
|
||||
// disallow setting of unsupported tags
|
||||
if( $bad = array_diff_key($tag, $default) ){
|
||||
throw new Loco_error_LocaleException('Unsupported subtags: '.implode(',',$bad) );
|
||||
}
|
||||
$tag += $default;
|
||||
// language tag is minimum requirement
|
||||
if( ! $tag['lang'] ){
|
||||
throw new Loco_error_LocaleException('Locale must have a language');
|
||||
}
|
||||
// no UN codes in Wordpress
|
||||
if( is_numeric($tag['region']) ){
|
||||
throw new Loco_error_LocaleException('Numeric regions not supported');
|
||||
}
|
||||
// single, scalar variant. Only using for Formal german currently.
|
||||
if( is_array($tag['variant']) ){
|
||||
$tag['variant'] = implode('_',$tag['variant']);
|
||||
}
|
||||
// normalize case
|
||||
$tag['lang'] = strtolower($tag['lang']);
|
||||
$tag['region'] = strtoupper($tag['region']);
|
||||
$tag['variant'] = strtolower($tag['variant']);
|
||||
// set subtags and invalidate cache of language tag
|
||||
$this->tag = $tag;
|
||||
$this->_tag = null;
|
||||
$this->icon = null;
|
||||
$this->valid = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
public function normalize(){
|
||||
try {
|
||||
$this->setSubtags( $this->tag );
|
||||
}
|
||||
catch( Loco_error_LocaleException $e ){
|
||||
$this->_tag = '';
|
||||
$this->icon = null;
|
||||
$this->name = 'Invalid locale';
|
||||
$this->_name = null;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString(){
|
||||
$str = $this->_tag;
|
||||
if( is_null($str) ){
|
||||
$str = implode('_',array_filter($this->tag));
|
||||
$this->_tag = $str;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get stored name in current display language.
|
||||
* Note that no dynamic translation of English name is performed, but can be altered with loco_parse_locale filter
|
||||
* @return string | null
|
||||
*/
|
||||
public function getName(){
|
||||
if( $name = $this->name ){
|
||||
// use canonical native name only when current language matches
|
||||
// deliberately not matching whole tag such that fr_CA would show native name of fr_FR
|
||||
if( $_name = $this->getNativeName() ){
|
||||
$locale = self::parse( function_exists('get_user_locale') ? get_user_locale() : get_locale() );
|
||||
if( $this->lang === $locale->lang ){
|
||||
$name = $_name;
|
||||
}
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get canonical native name as defined by WordPress
|
||||
* @return string | null
|
||||
*/
|
||||
public function getNativeName(){
|
||||
if( $name = $this->_name ){
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIcon(){
|
||||
$icon = $this->icon;
|
||||
if( is_null($icon) ){
|
||||
$tag = array();
|
||||
if( ! $this->tag['lang'] ){
|
||||
$tag[] = 'lang lang-zxx';
|
||||
}
|
||||
foreach( $this->tag as $class => $code ){
|
||||
if( $code ){
|
||||
$tag[] = $class.' '.$class.'-'.$code;
|
||||
}
|
||||
}
|
||||
$icon = strtolower( implode(' ',$tag) );
|
||||
$this->icon = $icon;
|
||||
}
|
||||
return $icon;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
public function setIcon( $css ){
|
||||
if( $css ){
|
||||
$this->icon = (string) $css;
|
||||
}
|
||||
else {
|
||||
$this->icon = null;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
public function setName( $english_name, $native_name = '' ){
|
||||
$this->name = apply_filters('loco_locale_name', $english_name, $native_name );
|
||||
$this->_name = (string) $native_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test whether locale is valid
|
||||
*/
|
||||
public function isValid(){
|
||||
if( is_null($this->valid) ){
|
||||
$this->normalize();
|
||||
}
|
||||
return $this->valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve this locale's "official" name from WordPress's translation api
|
||||
* @return string English name currently set
|
||||
*/
|
||||
public function fetchName( Loco_api_WordPressTranslations $api ){
|
||||
$tag = (string) $this;
|
||||
// pull from WordPress translations API if network allowed
|
||||
if( $locale = $api->getLocale($tag) ){
|
||||
$this->setName( $locale->getName(), $locale->getNativeName() );
|
||||
}
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolve this locale's name from compiled Loco data
|
||||
* @return string English name currently set
|
||||
*/
|
||||
public function buildName(){
|
||||
$names = array();
|
||||
// should at least have a language or not valid
|
||||
if( $this->isValid() ){
|
||||
$code = $this->tag['lang'];
|
||||
$db = Loco_data_CompiledData::get('languages');
|
||||
if( $name = $db[$code] ){
|
||||
// if variant is present add only that in brackets (no lookup required)
|
||||
if( $code = $this->tag['variant'] ){
|
||||
$name .= ' ('.ucfirst($code).')';
|
||||
}
|
||||
// else add region in brackets if present
|
||||
else if( $code = $this->tag['region'] ){
|
||||
$db = Loco_data_CompiledData::get('regions');
|
||||
if( $extra = $db[$code] ){
|
||||
$name .= ' ('.$extra.')';
|
||||
}
|
||||
else {
|
||||
$name .= ' ('.$code.')';
|
||||
}
|
||||
}
|
||||
$this->setName( $name );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->setName( __('Invalid locale','loco-translate') );
|
||||
}
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure locale has a label, even if it has to fall back to language code or error
|
||||
* @return string
|
||||
*/
|
||||
public function ensureName( Loco_api_WordPressTranslations $api ){
|
||||
$name = $this->getName();
|
||||
if( ! $name ){
|
||||
$name = $this->fetchName($api);
|
||||
// failing that, build own own name from components
|
||||
if( ! $name ){
|
||||
$name = $this->buildName();
|
||||
// last resort, use tag as name
|
||||
if( ! $name ){
|
||||
$name = (string) $this;
|
||||
$this->setName( $name );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize(){
|
||||
$a = $this->tag;
|
||||
$a['label'] = $this->getName();
|
||||
// plural data expected by editor
|
||||
$p = $this->getPluralData();
|
||||
$a['pluraleq'] = $p[0];
|
||||
$a['plurals'] = $p[1];
|
||||
$a['nplurals'] = count($p[1]);
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get plural data with translated forms
|
||||
* @internal
|
||||
* @return array [ (string) equation, (array) forms ]
|
||||
*/
|
||||
public function getPluralData(){
|
||||
$cache = $this->plurals;
|
||||
if( ! $cache ){
|
||||
$lc = $this->lang;
|
||||
$db = Loco_data_CompiledData::get('plurals');
|
||||
$id = $lc && isset($db[$lc]) ? $db[$lc] : 0;
|
||||
$cache = $this->setPlurals( $db[''][$id] );
|
||||
}
|
||||
return $cache;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPluralCount(){
|
||||
$raw = $this->getPluralData();
|
||||
return count( $raw[1] );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function setPlurals( array $raw ){
|
||||
$raw = apply_filters( 'loco_locale_plurals', $raw, $this );
|
||||
// handle languages with no plural forms, where n is always 0
|
||||
if( ! isset($raw[1][1]) ){
|
||||
// Translators: Plural category for languages that have no plurals
|
||||
$raw[1] = array( _x('All forms','Plural category','loco-translate') );
|
||||
$raw[0] = '0';
|
||||
}
|
||||
// else translate all implemented plural forms
|
||||
// for meaning of categories, see http://cldr.unicode.org/index/cldr-spec/plural-rules
|
||||
else {
|
||||
$forms = array(
|
||||
// Translators: Plural category for zero quantity
|
||||
'zero' => _x('Zero','Plural category','loco-translate'),
|
||||
// Translators: Plural category for singular quantity
|
||||
'one' => _x('One','Plural category','loco-translate'),
|
||||
// Translators: Plural category used in some multi-plural languages
|
||||
'two' => _x('Two','Plural category','loco-translate'),
|
||||
// Translators: Plural category used in some multi-plural languages
|
||||
'few' => _x('Few','Plural category','loco-translate'),
|
||||
// Translators: Plural category used in some multi-plural languages
|
||||
'many' => _x('Many','Plural category','loco-translate'),
|
||||
// Translators: General plural category not covered by other forms
|
||||
'other' => _x('Other','Plural category','loco-translate'),
|
||||
);
|
||||
foreach( $raw[1] as $k => $v ){
|
||||
if( isset($forms[$v]) ){
|
||||
$raw[1][$k] = $forms[$v];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->plurals = $raw;
|
||||
return $raw;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get PO style Plural-Forms header value comprising number of forms and integer equation for n
|
||||
* @return string
|
||||
*/
|
||||
public function getPluralFormsHeader(){
|
||||
list( $equation, $forms ) = $this->getPluralData();
|
||||
return sprintf('nplurals=%u; plural=%s;', count($forms), $equation );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply PO style Plural-Forms header.
|
||||
* @param string e.g. "nplurals=2; plural=n != 1;"
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
public function setPluralFormsHeader( $str ){
|
||||
if( ! preg_match('/^nplurals=(\\d);\s*plural=([ +\\-\\/*%!=<>|&?:()n0-9]+);?$/', $str, $match ) ){
|
||||
throw new InvalidArgumentException('Invalid Plural-Forms header, '.json_encode($str) );
|
||||
}
|
||||
$cache = $this->getPluralData();
|
||||
$exprn = $match[2];
|
||||
// always alter if equation differs
|
||||
if( $cache[0] !== $exprn ){
|
||||
$this->plurals[0] = $exprn;
|
||||
// alter number of forms if changed
|
||||
$nplurals = max( 1, (int) $match[1] );
|
||||
if( $nplurals !== count($cache[1]) ){
|
||||
// named forms must also change, but Plural-Forms cannot contain this information
|
||||
// as a cheat, we'll assume first form always "one" and last always "other"
|
||||
for( $i = 1; $i < $nplurals; $i++ ){
|
||||
$name = 1 === $i ? 'one' : sprintf('Plural %u',$i);
|
||||
$forms[] = $name;
|
||||
}
|
||||
$forms[] = 'other';
|
||||
$this->setPlurals( array($exprn,$forms) );
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function exportJson(){
|
||||
return json_encode( $this->jsonSerialize() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Depends on compiled library
|
||||
if( ! function_exists('loco_parse_wp_locale') ){
|
||||
loco_include('lib/compiled/locales.php');
|
||||
}
|
||||
|
78
vendor/loco-translate/src/admin/DebugController.php
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Loco_admin_DebugController extends Loco_mvc_AdminController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->set('title','DEBUG');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
// debug package listener
|
||||
$themes = array();
|
||||
/* @var $bundle Loco_package_Bundle */
|
||||
foreach( Loco_package_Listener::singleton()->getThemes() as $bundle ){
|
||||
$themes[] = array (
|
||||
'id' => $bundle->getId(),
|
||||
'name' => $bundle->getName(),
|
||||
'default' => $bundle->getDefaultProject()->getSlug(),
|
||||
'count' => count($bundle),
|
||||
);
|
||||
}
|
||||
$this->set('themes', $themes );
|
||||
|
||||
$plugins = array();
|
||||
/* @var $bundle Loco_package_Bundle */
|
||||
foreach( Loco_package_Listener::singleton()->getPlugins() as $bundle ){
|
||||
$plugins[] = array (
|
||||
'id' => $bundle->getId(),
|
||||
'name' => $bundle->getName(),
|
||||
'default' => $bundle->getDefaultProject()->getSlug(),
|
||||
'count' => count($bundle),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// $this->set( 'plugins', Loco_package_Plugin::get_plugins() );
|
||||
// $this->set('installed', wp_get_installed_translations('plugins') );
|
||||
// $this->set('active', get_option( 'active_plugins', array() ) );
|
||||
// $this->set('langs',get_available_languages());
|
||||
|
||||
/*$plugins = get_plugins();
|
||||
$plugin_info = get_site_transient( 'update_plugins' );
|
||||
foreach( $plugins as $plugin_file => $plugin_data ){
|
||||
if ( isset( $plugin_info->response[$plugin_file] ) ) {
|
||||
$plugins[$plugin_file]['____'] = $plugin_info->response[$plugin_file];
|
||||
}
|
||||
}*/
|
||||
|
||||
/*/ inspect session and test flash messages
|
||||
$session = Loco_data_Session::get();
|
||||
$session->flash( 'success', microtime() );
|
||||
$this->set('session', $session->getArrayCopy() );
|
||||
Loco_data_Session::close();*/
|
||||
|
||||
// try some notices
|
||||
Loco_error_AdminNotices::add( new Loco_error_Success('This is a sample success message') );
|
||||
Loco_error_AdminNotices::add( new Loco_error_Warning('This is a sample warning') );
|
||||
Loco_error_AdminNotices::add( new Loco_error_Exception('This is a sample error') );
|
||||
Loco_error_AdminNotices::add( new Loco_error_Debug('This is a sample debug message') );
|
||||
//*/
|
||||
|
||||
return $this->view('admin/debug');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
42
vendor/loco-translate/src/admin/ErrorController.php
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Loco_admin_ErrorController extends Loco_mvc_AdminController {
|
||||
|
||||
|
||||
public function renderError( Exception $e ){
|
||||
$this->set('error', Loco_error_Exception::convert($e) );
|
||||
return $this->render();
|
||||
}
|
||||
|
||||
|
||||
public function render(){
|
||||
$e = $this->get('error');
|
||||
if( $e ){
|
||||
/* @var Loco_error_Exception $e */
|
||||
$file = Loco_mvc_FileParams::create( new Loco_fs_File( $e->getRealFile() ) );
|
||||
$file['line'] = $e->getRealLine();
|
||||
$this->set('file', $file );
|
||||
if( loco_debugging() ){
|
||||
$trace = array();
|
||||
foreach( $e->getRealTrace() as $raw ) {
|
||||
$frame = new Loco_mvc_ViewParams($raw);
|
||||
if( $frame->has('file') ){
|
||||
$frame['file'] = Loco_mvc_FileParams::create( new Loco_fs_File($frame['file']) )->relpath;
|
||||
}
|
||||
$trace[] = $frame;
|
||||
}
|
||||
$this->set('trace',$trace);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$e = new Loco_error_Exception('Unknown error');
|
||||
$this->set('error', $e );
|
||||
}
|
||||
return $this->view( $e->getTemplate() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
72
vendor/loco-translate/src/admin/Navigation.php
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* Generic navigation helper.
|
||||
*/
|
||||
class Loco_admin_Navigation extends ArrayIterator {
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_admin_Navigation
|
||||
*/
|
||||
public function add( $name, $href = null, $active = false ){
|
||||
$this[] = new Loco_mvc_ViewParams( compact('name','href','active') );
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/* not currently used
|
||||
* @return Loco_admin_Navigation
|
||||
*
|
||||
public function addRoute( $name, $action ){
|
||||
$href = Loco_mvc_AdminRouter::generate( $action );
|
||||
return $this->add( $name, $href );
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a breadcrumb trail for a given view below a bundle
|
||||
* @return Loco_admin_Navigation
|
||||
*/
|
||||
public static function createBreadcrumb( Loco_package_Bundle $bundle ){
|
||||
$nav = new Loco_admin_Navigation;
|
||||
|
||||
// root link depends on bundle type
|
||||
$type = strtolower( $bundle->getType() );
|
||||
if( 'core' !== $type ){
|
||||
$link = new Loco_mvc_ViewParams( array(
|
||||
'href' => Loco_mvc_AdminRouter::generate($type),
|
||||
) );
|
||||
if( 'theme' === $type ){
|
||||
$link['name'] = __('Themes','loco-translate');
|
||||
}
|
||||
else {
|
||||
$link['name'] = __('Plugins','loco-translate');
|
||||
}
|
||||
$nav[] = $link;
|
||||
}
|
||||
|
||||
// Add actual bundle page, href may be unset to show as current page if needed
|
||||
$nav->add (
|
||||
$bundle->getName(),
|
||||
Loco_mvc_AdminRouter::generate( $type.'-view', array( 'bundle' => $bundle->getHandle() ) )
|
||||
);
|
||||
|
||||
// client code will add current page
|
||||
return $nav;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_mvc_ViewParams
|
||||
*
|
||||
public function getSecondLast(){
|
||||
$i = count($this);
|
||||
if( $i > 1 ){
|
||||
return $this[ $i-2 ];
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
}
|
35
vendor/loco-translate/src/admin/RedirectController.php
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract class Loco_admin_RedirectController extends Loco_mvc_AdminController {
|
||||
|
||||
|
||||
/**
|
||||
* Get full URL for redirecting to.
|
||||
* @var string
|
||||
*/
|
||||
abstract public function getLocation();
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
$location = $this->getLocation();
|
||||
if( $location && wp_redirect($location) ){
|
||||
// @codeCoverageIgnoreStart
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function render(){
|
||||
return 'Failed to redirect';
|
||||
}
|
||||
|
||||
}
|
90
vendor/loco-translate/src/admin/RootController.php
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
/**
|
||||
* Highest level Loco admin screen.
|
||||
*/
|
||||
class Loco_admin_RootController extends Loco_admin_list_BaseController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-home'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render main entry home screen
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
// translators: home screen title where %s is the version number
|
||||
$this->set('title', sprintf( __('Loco Translate %s','loco-translate'), loco_plugin_version() ) );
|
||||
|
||||
// Show currently active theme on home page
|
||||
$theme = Loco_package_Theme::create(null);
|
||||
$this->set('theme', $this->bundleParam($theme) );
|
||||
|
||||
// Show plugins that have currently loaded translations
|
||||
$bundles = array();
|
||||
foreach( Loco_package_Listener::singleton()->getPlugins() as $bundle ){
|
||||
try {
|
||||
$bundles[] = $this->bundleParam($bundle);
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// bundle should exist if we heard it. reduce to debug notice
|
||||
Loco_error_AdminNotices::debug( $e->getMessage() );
|
||||
}
|
||||
}
|
||||
$this->set('plugins', $bundles );
|
||||
|
||||
|
||||
// Show recently "used' bundles
|
||||
$bundles = array();
|
||||
$recent = Loco_data_RecentItems::get();
|
||||
// filter in lieu of plugin setting
|
||||
$maxlen = apply_filters('loco_num_recent_bundles', 10 );
|
||||
foreach( $recent->getBundles(0,$maxlen) as $id ){
|
||||
try {
|
||||
$bundle = Loco_package_Bundle::fromId($id);
|
||||
$bundles[] = $this->bundleParam($bundle);
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// possible that bundle ID changed since being saved in recent items list
|
||||
}
|
||||
}
|
||||
$this->set('recent', $bundles );
|
||||
|
||||
|
||||
// current locale and related links
|
||||
$locale = Loco_Locale::parse( get_locale() );
|
||||
$api = new Loco_api_WordPressTranslations;
|
||||
$tag = (string) $locale;
|
||||
$this->set( 'siteLocale', new Loco_mvc_ViewParams( array(
|
||||
'code' => $tag,
|
||||
'name' => ( $name = $locale->ensureName($api) ),
|
||||
'attr' => 'class="'.$locale->getIcon().'" lang="'.$locale->lang.'"',
|
||||
'link' => '<a href="'.esc_url(Loco_mvc_AdminRouter::generate('lang-view', array('locale'=>$tag) )).'">'.esc_html($name).'</a>',
|
||||
//'opts' => admin_url('options-general.php').'#WPLANG',
|
||||
) ) );
|
||||
|
||||
// user's "admin" language may differ and is worth showing
|
||||
if( function_exists('get_user_locale') ){
|
||||
$locale = Loco_Locale::parse( get_user_locale() );
|
||||
$alt = (string) $locale;
|
||||
if( $tag !== $alt ){
|
||||
$this->set( 'adminLocale', new Loco_mvc_ViewParams( array(
|
||||
'name' => ( $name = $locale->ensureName($api) ),
|
||||
'link' => '<a href="'.esc_url(Loco_mvc_AdminRouter::generate('lang-view', array('locale'=>$tag) )).'">'.esc_html($name).'</a>',
|
||||
) ) );
|
||||
}
|
||||
}
|
||||
|
||||
$this->set('title', __('Welcome to Loco Translate','loco-translate') );
|
||||
|
||||
return $this->view('admin/root');
|
||||
}
|
||||
|
||||
|
||||
}
|
161
vendor/loco-translate/src/admin/bundle/BaseController.php
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
/**
|
||||
* Base controller for any admin screen related to a bundle
|
||||
*/
|
||||
abstract class Loco_admin_bundle_BaseController extends Loco_mvc_AdminController {
|
||||
|
||||
/**
|
||||
* @var Loco_package_Bundle
|
||||
*/
|
||||
private $bundle;
|
||||
|
||||
/**
|
||||
* @var Loco_package_Project
|
||||
*/
|
||||
private $project;
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_package_Bundle
|
||||
*/
|
||||
public function getBundle(){
|
||||
if( ! $this->bundle ){
|
||||
$type = $this->get('type');
|
||||
$handle = $this->get('bundle');
|
||||
$this->bundle = Loco_package_Bundle::createType( $type, $handle );
|
||||
}
|
||||
return $this->bundle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Commit bundle config to database
|
||||
* @return Loco_admin_bundle_BaseController
|
||||
*/
|
||||
protected function saveBundle(){
|
||||
$custom = new Loco_config_CustomSaved;
|
||||
if( $custom->setBundle($this->bundle)->persist() ){
|
||||
Loco_error_AdminNotices::success( __('Configuration saved','loco-translate') );
|
||||
}
|
||||
// invalidate bundle in memory so next fetch is re-configured from DB
|
||||
$this->bundle = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove bundle config from database
|
||||
* @return Loco_admin_bundle_BaseController
|
||||
*/
|
||||
protected function resetBundle(){
|
||||
$option = $this->bundle->getCustomConfig();
|
||||
if( $option && $option->remove() ){
|
||||
Loco_error_AdminNotices::success( __('Configuration reset','loco-translate') );
|
||||
// invalidate bundle in memory so next fetch falls back to auto-config
|
||||
$this->bundle = null;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_package_Project
|
||||
*/
|
||||
public function getProject(){
|
||||
if( ! $this->project ){
|
||||
$bundle = $this->getBundle();
|
||||
$domain = $this->get('domain');
|
||||
if( ! $domain ){
|
||||
throw new Loco_error_Exception( sprintf('Translation set not known in %s', $bundle ) );
|
||||
}
|
||||
$this->project = $bundle->getProjectById($domain);
|
||||
if( ! $this->project ){
|
||||
throw new Loco_error_Exception( sprintf('Unknown translation set: %s not in %s', json_encode($domain), $bundle ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_admin_Navigation
|
||||
*/
|
||||
protected function prepareNavigation(){
|
||||
$bundle = $this->getBundle();
|
||||
|
||||
// navigate up to bundle listing page
|
||||
$breadcrumb = Loco_admin_Navigation::createBreadcrumb( $bundle );
|
||||
$this->set( 'breadcrumb', $breadcrumb );
|
||||
|
||||
// navigate between bundle view siblings
|
||||
$tabs = new Loco_admin_Navigation;
|
||||
$this->set( 'tabs', $tabs );
|
||||
$actions = array (
|
||||
'view' => __('Overview','loco-translate'),
|
||||
'setup' => __('Setup','loco-translate'),
|
||||
'conf' => __('Advanced','loco-translate'),
|
||||
);
|
||||
if( loco_debugging() ){
|
||||
$actions['debug'] = __('Debug','loco-translate');
|
||||
}
|
||||
$suffix = $this->get('action');
|
||||
$prefix = strtolower( $this->get('type') );
|
||||
$getarg = array_intersect_key( $_GET, array('bundle'=>'') );
|
||||
foreach( $actions as $action => $name ){
|
||||
$href = Loco_mvc_AdminRouter::generate( $prefix.'-'.$action, $getarg );
|
||||
$tabs->add( $name, $href, $action === $suffix );
|
||||
}
|
||||
|
||||
return $breadcrumb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Prepare file system connect
|
||||
* @param string "create", "update", "delete"
|
||||
* @param string path relative to wp-content
|
||||
* @return Loco_mvc_HiddenFields
|
||||
*/
|
||||
protected function prepareFsConnect( $type, $relpath ){
|
||||
|
||||
$fields = new Loco_mvc_HiddenFields( array(
|
||||
'auth' => $type,
|
||||
'path' => $relpath,
|
||||
'loco-nonce' => wp_create_nonce('fsConnect'),
|
||||
'_fs_nonce' => wp_create_nonce('filesystem-credentials'), // <- WP 4.7.5 added security fix
|
||||
) ) ;
|
||||
$this->set('fsFields', $fields );
|
||||
|
||||
// may have fs credentials saved in session
|
||||
try {
|
||||
if( Loco_data_Settings::get()->fs_persist ){
|
||||
$session = Loco_data_Session::get();
|
||||
if( isset($session['loco-fs']) ){
|
||||
$fields['connection_type'] = $session['loco-fs']['connection_type'];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception $e ){
|
||||
Loco_error_AdminNotices::debug( $e->getMessage() );
|
||||
}
|
||||
|
||||
// Run pre-checks that may determine file should not be written
|
||||
if( $relpath ){
|
||||
$file = new Loco_fs_File( $relpath );
|
||||
$file->normalize( loco_constant('WP_CONTENT_DIR') );
|
||||
// total file system block makes connection type irrelevant
|
||||
try {
|
||||
$api = new Loco_api_WordPressFileSystem;
|
||||
$api->preAuthorize($file);
|
||||
}
|
||||
catch( Loco_error_WriteException $e ){
|
||||
$this->set('fsLocked', $e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
145
vendor/loco-translate/src/admin/bundle/ConfController.php
vendored
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* Bundle configuration page
|
||||
*/
|
||||
class Loco_admin_bundle_ConfController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('config');
|
||||
$this->enqueueScript('config');
|
||||
$bundle = $this->getBundle();
|
||||
// translators: where %s is a plugin or theme
|
||||
$this->set( 'title', sprintf( __('Configure %s','loco-translate'),$bundle->getName() ) );
|
||||
|
||||
$post = Loco_mvc_PostParams::get();
|
||||
// always set a nonce for current bundle
|
||||
$nonce = $this->setNonce( $this->get('_route').'-'.$this->get('bundle') );
|
||||
$this->set('nonce', $nonce );
|
||||
try {
|
||||
// Save configuration if posted
|
||||
if( $post->has('conf') ){
|
||||
if( ! $post->name ){
|
||||
$post->name = $bundle->getName();
|
||||
}
|
||||
$this->checkNonce( $nonce->action );
|
||||
$model = new Loco_config_FormModel;
|
||||
$model->loadForm( $post );
|
||||
// configure bundle from model in full
|
||||
$bundle->clear();
|
||||
$reader = new Loco_config_BundleReader( $bundle );
|
||||
$reader->loadModel( $model );
|
||||
$this->saveBundle();
|
||||
}
|
||||
// Delete configuration if posted
|
||||
else if( $post->has('unconf') ){
|
||||
$this->resetBundle();
|
||||
}
|
||||
}
|
||||
catch( Exception $e ){
|
||||
Loco_error_AdminNotices::warn( $e->getMessage() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Advanced tab','loco-translate') => $this->viewSnippet('tab-bundle-conf'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render() {
|
||||
|
||||
$parent = null;
|
||||
$bundle = $this->getBundle();
|
||||
$default = $bundle->getDefaultProject();
|
||||
$base = $bundle->getDirectoryPath();
|
||||
|
||||
|
||||
// parent themes are inherited into bundle, we don't want them in the child theme config
|
||||
if( $bundle->isTheme() && ( $parent = $bundle->getParent() ) ){
|
||||
$this->set( 'parent', new Loco_mvc_ViewParams( array(
|
||||
'name' => $parent->getName(),
|
||||
'href' => Loco_mvc_AdminRouter::generate('theme-conf', array( 'bundle' => $parent->getSlug() ) + $_GET ),
|
||||
) ) );
|
||||
}
|
||||
|
||||
// render postdata straight back to form if sent
|
||||
$data = Loco_mvc_PostParams::get();
|
||||
// else build initial data from current bundle state
|
||||
if( ! $data->has('conf') ){
|
||||
// create single default set for totally unconfigured bundles
|
||||
if( 0 === count($bundle) ){
|
||||
$bundle->createDefault('');
|
||||
}
|
||||
$writer = new Loco_config_BundleWriter($bundle);
|
||||
$data = $writer->toForm();
|
||||
// removed parent bundle from config form, as they are inherited
|
||||
/* @var Loco_package_Project $project */
|
||||
foreach( $bundle as $i => $project ){
|
||||
if( $parent && $parent->hasProject($project) ){
|
||||
// warn if child theme uses parent theme's text domain (but allowing to render so we don't get an empty form.
|
||||
if( $project === $default ){
|
||||
Loco_error_AdminNotices::warn( __("Child theme declares the same Text Domain as the parent theme",'loco-translate') );
|
||||
}
|
||||
// else safe to remove parent theme configuration as it should be held in its own bundle
|
||||
else {
|
||||
$data['conf'][$i]['removed'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build config blocks for form
|
||||
$i = 0;
|
||||
$conf = array();
|
||||
foreach( $data['conf'] as $raw ){
|
||||
if( empty($raw['removed']) ){
|
||||
$slug = $raw['slug'];
|
||||
$domain = $raw['domain'] or $domain = 'untitled';
|
||||
$raw['prefix'] = sprintf('conf[%u]', $i++ );
|
||||
$raw['short'] = ! $slug || ( $slug === $domain ) ? $domain : $domain.'→'.$slug;
|
||||
$conf[] = new Loco_mvc_ViewParams( $raw );
|
||||
}
|
||||
}
|
||||
|
||||
// bundle level configs
|
||||
$name = $bundle->getName();
|
||||
$excl = $data['exclude'];
|
||||
|
||||
|
||||
// access to type of configuration that's currently saved
|
||||
$this->set('saved', $bundle->isConfigured() );
|
||||
|
||||
// link to author if there are config problems
|
||||
$info = $bundle->getHeaderInfo();
|
||||
$this->set('author', $info->getAuthorLink() );
|
||||
|
||||
// link for downloading current configuration XML file
|
||||
$args = array (
|
||||
'path' => 'loco.xml',
|
||||
'action' => 'loco_download',
|
||||
'bundle' => $bundle->getHandle(),
|
||||
'type' => $bundle->getType()
|
||||
);
|
||||
$this->set( 'xmlUrl', Loco_mvc_AjaxRouter::generate( 'DownloadConf', $args ) );
|
||||
$this->set( 'manUrl', apply_filters('loco_external','https://localise.biz/wordpress/plugin/manual/bundle-config') );
|
||||
|
||||
$this->prepareNavigation()->add( __('Advanced configuration','loco-translate') );
|
||||
return $this->view('admin/bundle/conf', compact('conf','base','name','excl') );
|
||||
}
|
||||
|
||||
|
||||
}
|
52
vendor/loco-translate/src/admin/bundle/DebugController.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* Bundle debugger.
|
||||
* Shows bundle diagnostics and highlights problems
|
||||
*/
|
||||
class Loco_admin_bundle_DebugController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', 'Debug: '.$bundle );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$this->prepareNavigation()->add( __('Bundle diagnostics','loco-translate') );
|
||||
|
||||
$bundle = $this->getBundle();
|
||||
$debugger = new Loco_package_Debugger($bundle);
|
||||
$this->set('notices', $notices = new Loco_mvc_ViewParams );
|
||||
/* @var $notice Loco_error_Exception */
|
||||
foreach( $debugger as $notice ){
|
||||
$notices[] = new Loco_mvc_ViewParams( array(
|
||||
'style' => 'notice inline notice-'.$notice->getType(),
|
||||
'title' => $notice->getTitle(),
|
||||
'body' => $notice->getMessage(),
|
||||
) );
|
||||
}
|
||||
|
||||
$meta = $bundle->getHeaderInfo();
|
||||
$this->set('meta', new Loco_mvc_ViewParams( array(
|
||||
'vendor' => $meta->getVendorHost(),
|
||||
'author' => $meta->getAuthorCredit(),
|
||||
) ) );
|
||||
|
||||
if( count($bundle) ){
|
||||
$writer = new Loco_config_BundleWriter( $bundle );
|
||||
$this->set( 'xml', $writer->toXml() );
|
||||
}
|
||||
|
||||
return $this->view('admin/bundle/debug');
|
||||
}
|
||||
|
||||
}
|
162
vendor/loco-translate/src/admin/bundle/LocaleController.php
vendored
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
/**
|
||||
* Pseudo-bundle view, lists all files available in a single locale
|
||||
*/
|
||||
class Loco_admin_bundle_LocaleController extends Loco_mvc_AdminController {
|
||||
|
||||
/**
|
||||
* @var Loco_Locale
|
||||
*/
|
||||
private $locale;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$tag = $this->get('locale');
|
||||
$locale = Loco_Locale::parse($tag);
|
||||
if( $locale->isValid() ){
|
||||
$api = new Loco_api_WordPressTranslations;
|
||||
$this->set('title', $locale->ensureName($api) );
|
||||
$this->locale = $locale;
|
||||
$this->enqueueStyle('locale')->enqueueStyle('fileinfo');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-locale-view'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
// locale already parsed during init (for page title)
|
||||
$locale = $this->locale;
|
||||
if( ! $locale || ! $locale->isValid() ){
|
||||
throw new Loco_error_Exception('Invalid locale argument');
|
||||
}
|
||||
|
||||
// language may not be "installed" but we still want to inspect available files
|
||||
$api = new Loco_api_WordPressTranslations;
|
||||
$installed = $api->isInstalled($locale);
|
||||
|
||||
$tag = (string) $locale;
|
||||
$package = new Loco_package_Locale( $locale );
|
||||
|
||||
// Get PO files for this locale
|
||||
$files = $package->findLocaleFiles();
|
||||
$translations = array();
|
||||
$modified = 0;
|
||||
$npofiles = 0;
|
||||
$nfiles = 0;
|
||||
|
||||
// source locale means we want to see POT instead of translations
|
||||
if( 'en_US' === $tag ){
|
||||
$files = $package->findTemplateFiles()->augment($files);
|
||||
}
|
||||
|
||||
/* @var Loco_fs_File */
|
||||
foreach( $files as $file ){
|
||||
$nfiles++;
|
||||
if( 'pot' !== $file->extension() ){
|
||||
$npofiles++;
|
||||
}
|
||||
$modified = max( $modified, $file->modified() );
|
||||
$project = $package->getProject($file);
|
||||
// do similarly to Loco_admin_bundle_ViewController::createFileParams
|
||||
$meta = Loco_gettext_Metadata::load($file);
|
||||
$dir = new Loco_fs_LocaleDirectory( $file->dirname() );
|
||||
// arguments for deep link into project
|
||||
$slug = $project->getSlug();
|
||||
$domain = $project->getDomain()->getName();
|
||||
$bundle = $project->getBundle();
|
||||
$type = strtolower( $bundle->getType() );
|
||||
$args = array(
|
||||
// 'locale' => $tag,
|
||||
'bundle' => $bundle->getHandle(),
|
||||
'domain' => $project->getId(),
|
||||
'path' => $meta->getPath(false),
|
||||
);
|
||||
// append data required for PO table row, except use bundle data instead of locale data
|
||||
$translations[$type][] = new Loco_mvc_ViewParams( array (
|
||||
// bundle info
|
||||
'title' => $project->getName(),
|
||||
'domain' => $domain,
|
||||
'short' => ! $slug || $project->isDomainDefault() ? $domain : $domain.'→'.$slug,
|
||||
// file info
|
||||
'meta' => $meta,
|
||||
'name' => $file->basename(),
|
||||
'time' => $file->modified(),
|
||||
'type' => strtoupper( $file->extension() ),
|
||||
'todo' => $meta->countIncomplete(),
|
||||
'total' => $meta->getTotal(),
|
||||
// author / system / custom / other
|
||||
'store' => $dir->getTypeLabel( $dir->getTypeId() ),
|
||||
// links
|
||||
'view' => Loco_mvc_AdminRouter::generate( $type.'-file-view', $args ),
|
||||
'info' => Loco_mvc_AdminRouter::generate( $type.'-file-info', $args ),
|
||||
'edit' => Loco_mvc_AdminRouter::generate( $type.'-file-edit', $args ),
|
||||
'move' => Loco_mvc_AdminRouter::generate( $type.'-file-move', $args ),
|
||||
'delete' => Loco_mvc_AdminRouter::generate( $type.'-file-delete', $args ),
|
||||
'copy' => Loco_mvc_AdminRouter::generate( $type.'-msginit', $args ),
|
||||
) );
|
||||
}
|
||||
|
||||
$title = __( 'Installed languages', 'loco-translate' );
|
||||
$breadcrumb = new Loco_admin_Navigation;
|
||||
$breadcrumb->add( $title, Loco_mvc_AdminRouter::generate('lang') );
|
||||
//$breadcrumb->add( $locale->getName() );
|
||||
$breadcrumb->add( $tag );
|
||||
|
||||
// It's unlikely that an "installed" language would have no files, but could happen if only MO on disk
|
||||
if( 0 === $nfiles ){
|
||||
return $this->view('admin/errors/no-locale', compact('breadcrumb','locale') );
|
||||
}
|
||||
|
||||
// files may be available for language even if not installed (i.e. no core files on disk)
|
||||
if( ! $installed || ! isset($translations['core']) && 'en_US' !== $tag ){
|
||||
Loco_error_AdminNotices::warn( __('No core translation files are installed for this language','loco-translate') )
|
||||
->addLink('https://codex.wordpress.org/Installing_WordPress_in_Your_Language', __('Documentation','loco-translate') );
|
||||
}
|
||||
|
||||
// Translated type labels and "See all <type>" links
|
||||
$types = array(
|
||||
'core' => new Loco_mvc_ViewParams( array(
|
||||
'name' => __('WordPress Core','loco-translate'),
|
||||
'text' => __('See all core translations','loco-translate'),
|
||||
'href' => Loco_mvc_AdminRouter::generate('core')
|
||||
) ),
|
||||
'theme' => new Loco_mvc_ViewParams( array(
|
||||
'name' => __('Themes','loco-translate'),
|
||||
'text' => __('See all themes','loco-translate'),
|
||||
'href' => Loco_mvc_AdminRouter::generate('theme')
|
||||
) ),
|
||||
'plugin' => new Loco_mvc_ViewParams( array(
|
||||
'name' => __('Plugins','loco-translate'),
|
||||
'text' => __('See all plugins','loco-translate'),
|
||||
'href' => Loco_mvc_AdminRouter::generate('plugin')
|
||||
) ),
|
||||
);
|
||||
|
||||
$this->set( 'locale', new Loco_mvc_ViewParams( array(
|
||||
'code' => $tag,
|
||||
'name' => $locale->getName(),
|
||||
'attr' => 'class="'.$locale->getIcon().'" lang="'.$locale->lang.'"',
|
||||
) ) );
|
||||
|
||||
return $this->view( 'admin/bundle/locale', compact('breadcrumb','translations','types','npofiles','modified') );
|
||||
}
|
||||
|
||||
|
||||
}
|
193
vendor/loco-translate/src/admin/bundle/SetupController.php
vendored
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Loco_admin_bundle_SetupController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$bundle = $this->getBundle();
|
||||
|
||||
// translators: where %s is a plugin or theme
|
||||
$this->set( 'title', sprintf( __('Set up %s','loco-translate'),$bundle->getName() ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Setup tab','loco-translate') => $this->viewSnippet('tab-bundle-setup'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$this->prepareNavigation()->add( __('Bundle setup','loco-translate') );
|
||||
$bundle = $this->getBundle();
|
||||
$action = 'setup:'.$bundle->getId();
|
||||
|
||||
// execute auto-configure if posted
|
||||
$post = Loco_mvc_PostParams::get();
|
||||
if( $post->has('auto-setup') && $this->checkNonce( 'auto-'.$action) ){
|
||||
if( 0 === count($bundle) ){
|
||||
$bundle->createDefault();
|
||||
}
|
||||
foreach( $bundle as $project ){
|
||||
if( ! $project->getPot() && ( $file = $project->guessPot() ) ){
|
||||
$project->setPot( $file );
|
||||
}
|
||||
}
|
||||
// forcefully add every additional project into bundle
|
||||
foreach( $bundle->invert() as $project ){
|
||||
if( ! $project->getPot() && ( $file = $project->guessPot() ) ){
|
||||
$project->setPot( $file );
|
||||
}
|
||||
$bundle[] = $project;
|
||||
}
|
||||
$this->saveBundle();
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('auto', null );
|
||||
}
|
||||
// execute XML-based config if posted
|
||||
else if( $post->has('xml-setup') && $this->checkNonce( 'xml-'.$action) ){
|
||||
$bundle->clear();
|
||||
$model = new Loco_config_XMLModel;
|
||||
$model->loadXml( trim( $post['xml-content'] ) );
|
||||
$reader = new Loco_config_BundleReader($bundle);
|
||||
$reader->loadModel( $model );
|
||||
$this->saveBundle();
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('xml', null );
|
||||
}
|
||||
// execute JSON-based config if posted
|
||||
else if( $post->has('json-setup') && $this->checkNonce( 'json-'.$action) ){
|
||||
$bundle->clear();
|
||||
$model = new Loco_config_ArrayModel;
|
||||
$model->loadJson( trim( $post['json-content'] ) );
|
||||
$reader = new Loco_config_BundleReader($bundle);
|
||||
$reader->loadModel( $model );
|
||||
$this->saveBundle();
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('json', null );
|
||||
}
|
||||
// execute reset if posted
|
||||
else if( $post->has('reset-setup') && $this->checkNonce( 'reset-'.$action) ){
|
||||
$this->resetBundle();
|
||||
$bundle = $this->getBundle();
|
||||
}
|
||||
|
||||
// bundle author links
|
||||
$info = $bundle->getHeaderInfo();
|
||||
$this->set( 'credit', $info->getAuthorCredit() );
|
||||
|
||||
// render according to current configuration method (save type)
|
||||
$configured = $this->get('force') or $configured = $bundle->isConfigured();
|
||||
|
||||
$notices = new ArrayIterator;
|
||||
$this->set('notices', $notices );
|
||||
|
||||
// collect configuration warnings
|
||||
foreach( $bundle as $project ){
|
||||
$potfile = $project->getPot();
|
||||
if( ! $potfile ){
|
||||
$notices[] = sprintf('No translation template for the "%s" text domain', $project->getSlug() );
|
||||
}
|
||||
}
|
||||
// if extra files found consider incomplete
|
||||
if( $bundle->isTheme() || ( $bundle->isPlugin() && ! $bundle->isSingleFile() ) ){
|
||||
$unknown = Loco_package_Inverter::export($bundle);
|
||||
$n = 0;
|
||||
foreach( $unknown as $ext => $files ){
|
||||
$n += count($files);
|
||||
}
|
||||
if( $n ){
|
||||
$notices[] = sprintf( _n("One file can't be matched to a known set of strings","%s files can't be matched to a known set of strings",$n,'loco-translate'), number_format($n) );
|
||||
}
|
||||
}
|
||||
|
||||
// display setup options if at least one option specified
|
||||
$doconf = false;
|
||||
|
||||
// enable form to invoke auto-configuration
|
||||
if( $this->get('auto') ){
|
||||
$fields = new Loco_mvc_HiddenFields();
|
||||
$fields->setNonce( 'auto-'.$action );
|
||||
$this->set('autoFields', $fields );
|
||||
$doconf = true;
|
||||
}
|
||||
|
||||
// enable form to paste XML config
|
||||
if( $this->get('xml') ){
|
||||
$fields = new Loco_mvc_HiddenFields();
|
||||
$fields->setNonce( 'xml-'.$action );
|
||||
$this->set('xmlFields', $fields );
|
||||
$doconf = true;
|
||||
}
|
||||
|
||||
// enable form to paste JSON config (via remote lookup)
|
||||
if( $this->get('json') ){
|
||||
$fields = new Loco_mvc_HiddenFields( array(
|
||||
'json-content' => '',
|
||||
'version' => $info->Version,
|
||||
) );
|
||||
$fields->setNonce( 'json-'.$action );
|
||||
$this->set('jsonFields', $fields );
|
||||
|
||||
// other information for looking up bundle via api
|
||||
$this->set('vendorSlug', $bundle->getSlug() );
|
||||
|
||||
// remote config is done via JavaScript
|
||||
$this->enqueueScript('setup');
|
||||
$apiBase = apply_filters( 'loco_api_url', 'https://localise.biz/api' );
|
||||
$this->set('js', new Loco_mvc_ViewParams( array(
|
||||
'apiUrl' => $apiBase.'/wp/'.strtolower( $bundle->getType() ),
|
||||
) ) );
|
||||
$doconf = true;
|
||||
}
|
||||
|
||||
// display configurator if configurating
|
||||
if( $doconf ){
|
||||
return $this->view( 'admin/bundle/setup/conf' );
|
||||
}
|
||||
// else set configurator links back to self with required option
|
||||
// ...
|
||||
|
||||
|
||||
if( ! $configured || ! count($bundle) ){
|
||||
return $this->view( 'admin/bundle/setup/none' );
|
||||
}
|
||||
|
||||
if( 'db' === $configured ){
|
||||
// form for resetting config
|
||||
$fields = new Loco_mvc_HiddenFields();
|
||||
$fields->setNonce( 'reset-'.$action );
|
||||
$this->set( 'reset', $fields );
|
||||
return $this->view('admin/bundle/setup/saved');
|
||||
}
|
||||
|
||||
if( 'internal' === $configured ){
|
||||
return $this->view('admin/bundle/setup/core');
|
||||
}
|
||||
|
||||
if( 'file' === $configured ){
|
||||
return $this->view('admin/bundle/setup/author');
|
||||
}
|
||||
|
||||
if( count($notices) ){
|
||||
return $this->view('admin/bundle/setup/partial');
|
||||
}
|
||||
|
||||
return $this->view('admin/bundle/setup/meta');
|
||||
}
|
||||
|
||||
}
|
324
vendor/loco-translate/src/admin/bundle/ViewController.php
vendored
Normal file
|
@ -0,0 +1,324 @@
|
|||
<?php
|
||||
/**
|
||||
* Bundle overview.
|
||||
* First tier bundle view showing resources across all projects
|
||||
*/
|
||||
class Loco_admin_bundle_ViewController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', $bundle->getName() );
|
||||
$this->enqueueStyle('bundle');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-bundle-view'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a link for a specific file resource within a project
|
||||
* @return string
|
||||
*/
|
||||
private function getResourceLink( $page, Loco_package_Project $project, Loco_gettext_Metadata $meta, array $args = array() ){
|
||||
$args['path'] = $meta->getPath(false);
|
||||
return $this->getProjectLink( $page, $project, $args );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a link for a project, but without being for a specific file
|
||||
* @return string
|
||||
*/
|
||||
private function getProjectLink( $page, Loco_package_Project $project, array $args = array() ){
|
||||
$args['bundle'] = $this->get('bundle');
|
||||
$args['domain'] = $project->getId();
|
||||
$route = strtolower( $this->get('type') ).'-'.$page;
|
||||
return Loco_mvc_AdminRouter::generate( $route, $args );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize view parameters for a project
|
||||
* @param Loco_package_Project
|
||||
* @return Loco_mvc_ViewParams
|
||||
*/
|
||||
private function createProjectParams( Loco_package_Project $project ){
|
||||
$name = $project->getName();
|
||||
$domain = $project->getDomain()->getName();
|
||||
$slug = $project->getSlug();
|
||||
$p = new Loco_mvc_ViewParams( array (
|
||||
'id' => $project->getId(),
|
||||
'name' => $name,
|
||||
'slug' => $slug,
|
||||
'domain' => $domain,
|
||||
'short' => ! $slug || $project->isDomainDefault() ? $domain : $domain.'→'.$slug,
|
||||
) );
|
||||
|
||||
// POT template file
|
||||
$file = $project->getPot();
|
||||
if( $file && $file->exists() ){
|
||||
$meta = Loco_gettext_Metadata::load($file);
|
||||
$p['pot'] = new Loco_mvc_ViewParams( array(
|
||||
// POT info
|
||||
'name' => $file->basename(),
|
||||
'time' => $file->modified(),
|
||||
// POT links
|
||||
'info' => $this->getResourceLink('file-info', $project, $meta ),
|
||||
'edit' => $this->getResourceLink('file-edit', $project, $meta ),
|
||||
) );
|
||||
}
|
||||
|
||||
// PO/MO files
|
||||
$po = $project->findLocaleFiles('po');
|
||||
$mo = $project->findLocaleFiles('mo');
|
||||
$p['po'] = $this->createProjectPairs( $project, $po, $mo );
|
||||
|
||||
// also pull invalid files so everything is available to the UI
|
||||
$mo = $project->findNotLocaleFiles('mo');
|
||||
$po = $project->findNotLocaleFiles('po')->augment( $project->findNotLocaleFiles('pot') );
|
||||
$p['_po'] = $this->createProjectPairs( $project, $po, $mo );
|
||||
|
||||
// always offer msginit even if we find out later we can't extract any strings
|
||||
$p['nav'][] = new Loco_mvc_ViewParams( array(
|
||||
'href' => $this->getProjectLink('msginit', $project ),
|
||||
'name' => __('New language','loco-translate'),
|
||||
'icon' => 'add',
|
||||
) );
|
||||
|
||||
$pot = $project->getPot();
|
||||
|
||||
// prevent editing of POT when config prohibits
|
||||
if( $project->isPotLocked() || 1 < Loco_data_Settings::get()->pot_protect ) {
|
||||
if( $pot && $pot->exists() ){
|
||||
$meta = Loco_gettext_Metadata::load($pot);
|
||||
$p['nav'][] = new Loco_mvc_ViewParams( array(
|
||||
'href' => $this->getResourceLink('file-view', $project, $meta ),
|
||||
'name' => __('View template','loco-translate'),
|
||||
'icon' => 'file',
|
||||
) );
|
||||
}
|
||||
}
|
||||
// offer template editing if permitted
|
||||
else if( $pot && $pot->exists() ){
|
||||
$p['pot'] = $pot;
|
||||
$meta = Loco_gettext_Metadata::load($pot);
|
||||
$p['nav'][] = new Loco_mvc_ViewParams( array(
|
||||
'href' => $this->getResourceLink('file-edit', $project, $meta ),
|
||||
'name' => __('Edit template','loco-translate'),
|
||||
'icon' => 'pencil',
|
||||
) );
|
||||
}
|
||||
// else offer creation of new Template
|
||||
else {
|
||||
$p['nav'][] = new Loco_mvc_ViewParams( array(
|
||||
'href' => $this->getProjectLink('xgettext', $project ),
|
||||
'name' => __('Create template','loco-translate'),
|
||||
'icon' => 'add',
|
||||
) );
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collect PO/MO pairings, ignoring any PO that is in use as a template
|
||||
*/
|
||||
private function createPairs( Loco_fs_FileList $po, Loco_fs_FileList $mo, Loco_fs_File $pot = null ){
|
||||
$pairs = array();
|
||||
/* @var $pofile Loco_fs_LocaleFile */
|
||||
foreach( $po as $pofile ){
|
||||
if( $pot && $pofile->equal($pot) ){
|
||||
continue;
|
||||
}
|
||||
$pair = array( $pofile, null );
|
||||
$mofile = $pofile->cloneExtension('mo');
|
||||
if( $mofile->exists() ){
|
||||
$pair[1] = $mofile;
|
||||
}
|
||||
$pairs[] = $pair;
|
||||
}
|
||||
/* @var $mofile Loco_fs_LocaleFile */
|
||||
foreach( $mo as $mofile ){
|
||||
$pofile = $mofile->cloneExtension('po');
|
||||
if( $pot && $pofile->equal($pot) ){
|
||||
continue;
|
||||
}
|
||||
if( ! $pofile->exists() ){
|
||||
$pairs[] = array( null, $mofile );
|
||||
}
|
||||
}
|
||||
return $pairs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize view parameters for each row representing a localized resource pair
|
||||
* @return array collection of entries corresponding to available PO/MO pair.
|
||||
*/
|
||||
private function createProjectPairs( Loco_package_Project $project, Loco_fs_LocaleFileList $po, Loco_fs_LocaleFileList $mo ){
|
||||
// populate official locale names for all found, or default to our own
|
||||
if( $locales = $po->getLocales() + $mo->getLocales() ){
|
||||
$api = new Loco_api_WordPressTranslations;
|
||||
/* @var $locale Loco_Locale */
|
||||
foreach( $locales as $tag => $locale ){
|
||||
$locale->ensureName($api);
|
||||
}
|
||||
}
|
||||
// collate as unique [PO,MO] pairs ensuring canonical template excluded
|
||||
$pairs = $this->createPairs( $po, $mo, $project->getPot() );
|
||||
$rows = array();
|
||||
foreach( $pairs as $pair ){
|
||||
// favour PO file if it exists
|
||||
list( $pofile, $mofile ) = $pair;
|
||||
$file = $pofile or $file = $mofile;
|
||||
// establish locale, or assume invalid
|
||||
$locale = null;
|
||||
/* @var Loco_fs_LocaleFile $file */
|
||||
if( 'pot' !== $file->extension() ){
|
||||
$tag = $file->getSuffix();
|
||||
if( isset($locales[$tag]) ){
|
||||
$locale = $locales[$tag];
|
||||
}
|
||||
}
|
||||
$rows[] = $this->createFileParams( $project, $file, $locale );
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Loco_package_Project
|
||||
* @param Loco_fs_File
|
||||
* @param Loco_Locale
|
||||
* @return Loco_mvc_ViewParams
|
||||
*/
|
||||
private function createFileParams( Loco_package_Project $project, Loco_fs_File $file, Loco_Locale $locale = null ){
|
||||
// Pull Gettext meta data from cache if possible
|
||||
$meta = Loco_gettext_Metadata::load($file);
|
||||
$dir = new Loco_fs_LocaleDirectory( $file->dirname() );
|
||||
// routing arguments
|
||||
$args = array (
|
||||
'path' => $meta->getPath(false),
|
||||
);
|
||||
// Return data required for PO table row
|
||||
return new Loco_mvc_ViewParams( array (
|
||||
// locale info
|
||||
'lcode' => $locale ? (string) $locale : '',
|
||||
'lname' => $locale ? $locale->getName() : '',
|
||||
'lattr' => $locale ? 'class="'.$locale->getIcon().'" lang="'.$locale->lang.'"' : '',
|
||||
// file info
|
||||
'meta' => $meta,
|
||||
'name' => $file->basename(),
|
||||
'time' => $file->modified(),
|
||||
'type' => strtoupper( $file->extension() ),
|
||||
'todo' => $meta->countIncomplete(),
|
||||
'total' => $meta->getTotal(),
|
||||
// author / system / custom / other
|
||||
'store' => $dir->getTypeLabel( $dir->getTypeId() ),
|
||||
// links
|
||||
'view' => $this->getProjectLink('file-view', $project, $args ),
|
||||
'info' => $this->getProjectLink('file-info', $project, $args ),
|
||||
'edit' => $this->getProjectLink('file-edit', $project, $args ),
|
||||
'move' => $this->getProjectLink('file-move', $project, $args ),
|
||||
'delete' => $this->getProjectLink('file-delete', $project, $args ),
|
||||
'copy' => $this->getProjectLink('msginit', $project, $args ),
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare view parameters for all projects in a bundle
|
||||
* @param Loco_package_Bundle
|
||||
* @return array<Loco_mvc_ViewParams>
|
||||
*/
|
||||
private function createBundleListing( Loco_package_Bundle $bundle ){
|
||||
$projects = array();
|
||||
/* @var $project Loco_package_Project */
|
||||
foreach( $bundle as $project ){
|
||||
$projects[] = $this->createProjectParams($project);
|
||||
}
|
||||
return $projects;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$this->prepareNavigation();
|
||||
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('name', $bundle->getName() );
|
||||
|
||||
// bundle may not be fully configured
|
||||
$configured = $bundle->isConfigured();
|
||||
|
||||
// Hello Dolly is an exception. don't show unless configured deliberately
|
||||
if( 'Hello Dolly' === $bundle->getName() && 'hello.php' === basename($bundle->getHandle()) ){
|
||||
if( ! $configured || 'meta' === $configured ){
|
||||
$this->set( 'redirect', Loco_mvc_AdminRouter::generate('core-view') );
|
||||
return $this->view('admin/bundle/alias');
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all configured projects
|
||||
$projects = $this->createBundleListing( $bundle );
|
||||
$unknown = array();
|
||||
|
||||
// sniff additional unknown files if bundle is a theme or directory-based plugin that's been auto-detected
|
||||
if( 'file' === $configured || 'internal' === $configured ){
|
||||
// presumed complete
|
||||
}
|
||||
else if( $bundle->isTheme() || ( $bundle->isPlugin() && ! $bundle->isSingleFile() ) ){
|
||||
// TODO This needs abstracting into the Loco_package_Inverter class
|
||||
$prefixes = array();
|
||||
$po = new Loco_fs_LocaleFileList;
|
||||
$mo = new Loco_fs_LocaleFileList;
|
||||
foreach( Loco_package_Inverter::export($bundle) as $ext => $files ){
|
||||
$list = 'mo' === $ext ? $mo : $po;
|
||||
foreach( $files as $file ){
|
||||
$file = new Loco_fs_LocaleFile($file);
|
||||
$list->addLocalized( $file );
|
||||
// Only look in system locations if locale is valid and domain/prefix available
|
||||
$locale = $file->getLocale();
|
||||
if( $locale->isValid() && ( $domain = $file->getPrefix() ) ){
|
||||
$prefixes[$domain] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// pick up given files in system locations only
|
||||
foreach( $prefixes as $domain => $_bool ){
|
||||
$dummy = new Loco_package_Project( $bundle, new Loco_package_TextDomain($domain), '' );
|
||||
$bundle->addProject( $dummy ); // <- required to configure locations
|
||||
$dummy->excludeTargetPath( $bundle->getDirectoryPath() );
|
||||
$po->augment( $dummy->findLocaleFiles('po') );
|
||||
$mo->augment( $dummy->findLocaleFiles('mo') );
|
||||
}
|
||||
// a fake project is required to disable functions that require a configured project
|
||||
$dummy = new Loco_package_Project( $bundle, new Loco_package_TextDomain(''), '' );
|
||||
$unknown = $this->createProjectPairs( $dummy, $po, $mo );
|
||||
}
|
||||
|
||||
$this->set('projects', $projects );
|
||||
$this->set('unknown', $unknown );
|
||||
|
||||
return $this->view( 'admin/bundle/view' );
|
||||
}
|
||||
|
||||
|
||||
}
|
66
vendor/loco-translate/src/admin/config/ApisController.php
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* API keys/settings screen
|
||||
*/
|
||||
class Loco_admin_config_ApisController extends Loco_admin_config_BaseController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->set( 'title', __('API keys','loco-translate') );
|
||||
|
||||
// collect support API keys
|
||||
$apis = array();
|
||||
foreach( Loco_api_Providers::builtin() as $api ){
|
||||
$apis[ $api['id'] ] = new Loco_mvc_ViewParams($api);
|
||||
}
|
||||
$this->set('apis',$apis);
|
||||
|
||||
// handle save action
|
||||
$nonce = $this->setNonce('save-apis');
|
||||
try {
|
||||
if( $this->checkNonce($nonce->action) ){
|
||||
$post = Loco_mvc_PostParams::get();
|
||||
if( $post->has('api') ){
|
||||
// Save only options in post. Avoids overwrite of missing site options
|
||||
$data = array();
|
||||
$filter = array();
|
||||
foreach( $apis as $id => $api ){
|
||||
$fields = $post->api[$id];
|
||||
if( is_array($fields) ){
|
||||
foreach( $fields as $prop => $value ){
|
||||
$apis[$id][$prop] = $value;
|
||||
$prop = $id.'_api_'.$prop;
|
||||
$data[$prop] = $value;
|
||||
$filter[] = $prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( $filter ){
|
||||
Loco_data_Settings::get()->populate($data,$filter)->persistIfDirty();
|
||||
Loco_error_AdminNotices::success( __('Settings saved','loco-translate') );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$title = __('Plugin settings','loco-translate');
|
||||
$breadcrumb = new Loco_admin_Navigation;
|
||||
$breadcrumb->add( $title );
|
||||
|
||||
return $this->view('admin/config/apis', compact('breadcrumb') );
|
||||
}
|
||||
|
||||
}
|
47
vendor/loco-translate/src/admin/config/BaseController.php
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* Base controller for global plugin configuration screens
|
||||
*/
|
||||
abstract class Loco_admin_config_BaseController extends Loco_mvc_AdminController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
// navigate between config view siblings, but only if privileged user
|
||||
if( current_user_can('manage_options') ){
|
||||
$tabs = new Loco_admin_Navigation;
|
||||
$this->set( 'tabs', $tabs );
|
||||
$actions = array (
|
||||
'' => __('Site options','loco-translate'),
|
||||
'user' => __('User options','loco-translate'),
|
||||
'apis' => __('API keys','loco-translate'),
|
||||
'version' => __('Version','loco-translate'),
|
||||
);
|
||||
if( loco_debugging() ){
|
||||
$actions['debug'] = __('Debug','loco-translate');
|
||||
}
|
||||
$suffix = (string) $this->get('action');
|
||||
foreach( $actions as $action => $name ){
|
||||
$href = Loco_mvc_AdminRouter::generate( 'config-'.$action, $_GET );
|
||||
$tabs->add( $name, $href, $action === $suffix );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-config'),
|
||||
__('API keys','loco-translate') => $this->viewSnippet('tab-config-apis'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
168
vendor/loco-translate/src/admin/config/DebugController.php
vendored
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin config check (system diagnostics)
|
||||
*/
|
||||
class Loco_admin_config_DebugController extends Loco_admin_config_BaseController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->set( 'title', __('Debug','loco-translate') );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return int
|
||||
*/
|
||||
private function memory_size( $raw ){
|
||||
$bytes = wp_convert_hr_to_bytes($raw);
|
||||
return Loco_mvc_FileParams::renderBytes($bytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
private function rel_path( $path ){
|
||||
if( is_string($path) && $path && '/' === $path[0] ){
|
||||
$file = new Loco_fs_File( $path );
|
||||
$path = $file->getRelativePath(ABSPATH);
|
||||
}
|
||||
else if( ! $path ){
|
||||
$path = '(none)';
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$title = __('System diagnostics','loco-translate');
|
||||
$breadcrumb = new Loco_admin_Navigation;
|
||||
$breadcrumb->add( $title );
|
||||
|
||||
// extensions that are normally enabled in PHP by default
|
||||
loco_check_extension('json');
|
||||
loco_check_extension('ctype');
|
||||
|
||||
// product versions:
|
||||
$versions = new Loco_mvc_ViewParams( array (
|
||||
'Loco Translate' => loco_plugin_version(),
|
||||
'WordPress' => $GLOBALS['wp_version'],
|
||||
'PHP' => phpversion().' ('.PHP_SAPI.')',
|
||||
'Server' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : ( function_exists('apache_get_version') ? apache_get_version() : '' ),
|
||||
) );
|
||||
// we want to know about modules in case there are security mods installed known to break functionality
|
||||
if( function_exists('apache_get_modules') && ( $mods = preg_grep('/^mod_/',apache_get_modules() ) ) ){
|
||||
$versions['Server'] .= ' + '.implode(', ',$mods);
|
||||
}
|
||||
|
||||
// byte code cache (currently only checking for Zend OPcache)
|
||||
if( function_exists('opcache_get_configuration') && ini_get('opcache.enable') ){
|
||||
$info = opcache_get_configuration();
|
||||
$vers = $info['version'];
|
||||
$versions[ $vers['opcache_product_name'] ] = ' '.$vers['version'];
|
||||
}
|
||||
|
||||
// utf8 / encoding:
|
||||
$encoding = new Loco_mvc_ViewParams( array (
|
||||
'OK' => "\xCE\x9F\xCE\x9A",
|
||||
'tick' => "\xE2\x9C\x93",
|
||||
'json' => json_decode('"\\u039f\\u039a \\u2713"'),
|
||||
'mbstring' => loco_check_extension('mbstring') ? "\xCE\x9F\xCE\x9A \xE2\x9C\x93" : 'No',
|
||||
) );
|
||||
|
||||
// Sanity check mbstring.func_overload
|
||||
if( 2 !== strlen("\xC2\xA3") ){
|
||||
$encoding->mbstring = 'Error, disable mbstring.func_overload';
|
||||
}
|
||||
|
||||
// PHP / env memory settings:
|
||||
$memory = new Loco_mvc_PostParams( array(
|
||||
'WP_MEMORY_LIMIT' => $this->memory_size( loco_constant('WP_MEMORY_LIMIT') ),
|
||||
'WP_MAX_MEMORY_LIMIT' => $this->memory_size( loco_constant('WP_MAX_MEMORY_LIMIT') ),
|
||||
'PHP memory_limit' => $this->memory_size( ini_get('memory_limit') ),
|
||||
'PHP post_max_size' => $this->memory_size( ini_get('post_max_size') ),
|
||||
//'PHP upload_max_filesize' => $this->memory_size( ini_get('upload_max_filesize') ),
|
||||
'PHP max_execution_time' => (string) ini_get('max_execution_time'),
|
||||
) );
|
||||
|
||||
// Check if raising memory limit works (wp>=4.6)
|
||||
if( function_exists('wp_is_ini_value_changeable') && wp_is_ini_value_changeable('memory_limit') ){
|
||||
$memory['PHP memory_limit'] .= ' (changeable)';
|
||||
}
|
||||
|
||||
// Ajaxing:
|
||||
$this->enqueueScript('debug');
|
||||
$this->set( 'js', new Loco_mvc_ViewParams( array (
|
||||
'nonces' => array( 'ping' => wp_create_nonce('ping'), 'apis' => wp_create_nonce('apis') ),
|
||||
) ) );
|
||||
|
||||
// Third party API integrations:
|
||||
$apis = array();
|
||||
$jsapis = array();
|
||||
foreach( Loco_api_Providers::export() as $api ){
|
||||
$apis[] = new Loco_mvc_ViewParams($api);
|
||||
$jsapis[] = $api;
|
||||
}
|
||||
if( $apis ){
|
||||
$this->set('apis',$apis);
|
||||
$jsconf = $this->get('js');
|
||||
$jsconf['apis'] = $jsapis;
|
||||
}
|
||||
|
||||
// File system access
|
||||
$dir = new Loco_fs_Directory( loco_constant('LOCO_LANG_DIR') ) ;
|
||||
$ctx = new Loco_fs_FileWriter( $dir );
|
||||
$fsp = Loco_data_Settings::get()->fs_protect;
|
||||
$fs = new Loco_mvc_PostParams( array(
|
||||
'langdir' => $this->rel_path( $dir->getPath() ),
|
||||
'writable' => $ctx->writable(),
|
||||
'disabled' => $ctx->disabled(),
|
||||
'fs_protect' => 1 === $fsp ? 'Warn' : ( $fsp ? 'Block' : 'Off' ),
|
||||
) );
|
||||
|
||||
// Debug and error log settings
|
||||
$debug = new Loco_mvc_ViewParams( array(
|
||||
'WP_DEBUG' => loco_constant('WP_DEBUG') ? 'On' : 'Off',
|
||||
'WP_DEBUG_LOG' => loco_constant('WP_DEBUG_LOG') ? 'On' : 'Off',
|
||||
'WP_DEBUG_DISPLAY' => loco_constant('WP_DEBUG_DISPLAY') ? 'On' : 'Off',
|
||||
'PHP display_errors' => ini_get('display_errors') ? 'On' : 'Off',
|
||||
'PHP log_errors' => ini_get('log_errors') ? 'On' : 'Off',
|
||||
'PHP error_log' => $this->rel_path( ini_get('error_log') ),
|
||||
) );
|
||||
|
||||
/* Output buffering settings
|
||||
$this->set('ob', new Loco_mvc_ViewParams( array(
|
||||
'output_handler' => ini_get('output_handler'),
|
||||
'zlib.output_compression' => ini_get('zlib.output_compression'),
|
||||
'zlib.output_compression_level' => ini_get('zlib.output_compression_level'),
|
||||
'zlib.output_handler' => ini_get('zlib.output_handler'),
|
||||
) ) );*/
|
||||
|
||||
// alert to known system setting problems:
|
||||
if( version_compare(PHP_VERSION,'7.4','<') ){
|
||||
if( get_magic_quotes_gpc() ){
|
||||
Loco_error_AdminNotices::add( new Loco_error_Debug('You have "magic_quotes_gpc" enabled. We recommend you disable this in PHP') );
|
||||
}
|
||||
if( get_magic_quotes_runtime() ){
|
||||
Loco_error_AdminNotices::add( new Loco_error_Debug('You have "magic_quotes_runtime" enabled. We recommend you disable this in PHP') );
|
||||
}
|
||||
}
|
||||
|
||||
// alert to third party plugins known to interfere with functioning of this plugin
|
||||
if( class_exists('\\LocoAutoTranslateAddon\\LocoAutoTranslate',false) ){
|
||||
Loco_error_AdminNotices::add( new Loco_error_Warning('Unoffical add-ons for Loco Translate may affect functionality. We cannot provide support when third party products are installed.') );
|
||||
}
|
||||
|
||||
return $this->view('admin/config/debug', compact('breadcrumb','versions','encoding','memory','fs','debug') );
|
||||
}
|
||||
|
||||
}
|
49
vendor/loco-translate/src/admin/config/PrefsController.php
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* User-level plugin preferences
|
||||
*/
|
||||
class Loco_admin_config_PrefsController extends Loco_admin_config_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->set( 'title', __('User options','loco-translate') );
|
||||
|
||||
// user preference options
|
||||
$opts = Loco_data_Preferences::get();
|
||||
$this->set( 'opts', $opts );
|
||||
|
||||
// handle save action
|
||||
$nonce = $this->setNonce('save-prefs');
|
||||
try {
|
||||
if( $this->checkNonce($nonce->action) ){
|
||||
$post = Loco_mvc_PostParams::get();
|
||||
if( $post->has('opts') ){
|
||||
$opts->populate( $post->opts )->persist();
|
||||
Loco_error_AdminNotices::success( __('Settings saved','loco-translate') );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add($e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$title = __('Plugin settings','loco-translate');
|
||||
$breadcrumb = new Loco_admin_Navigation;
|
||||
$breadcrumb->add( $title );
|
||||
|
||||
return $this->view('admin/config/prefs', compact('breadcrumb') );
|
||||
}
|
||||
|
||||
}
|
86
vendor/loco-translate/src/admin/config/SettingsController.php
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* Site-wide Loco options (plugin settings)
|
||||
*/
|
||||
class Loco_admin_config_SettingsController extends Loco_admin_config_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
|
||||
// set current plugin options and defaults for placeholders
|
||||
$opts = Loco_data_Settings::get();
|
||||
$this->set( 'opts', $opts );
|
||||
$this->set( 'dflt', Loco_data_Settings::create() );
|
||||
|
||||
// roles and capabilities
|
||||
$perms = new Loco_data_Permissions;
|
||||
|
||||
// handle save action
|
||||
$nonce = $this->setNonce('save-config');
|
||||
try {
|
||||
if( $this->checkNonce($nonce->action) ){
|
||||
$post = Loco_mvc_PostParams::get();
|
||||
if( $post->has('opts') ){
|
||||
$opts->populate( $post->opts )->persist();
|
||||
$perms->populate( $post->has('caps') ? $post->caps : array() );
|
||||
// done update
|
||||
Loco_error_AdminNotices::success( __('Settings saved','loco-translate') );
|
||||
// remove saved params from session if persistent options unset
|
||||
if( ! $opts['fs_persist'] ){
|
||||
$session = Loco_data_Session::get();
|
||||
if( isset($session['loco-fs']) ){
|
||||
unset( $session['loco-fs'] );
|
||||
$session->persist();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add($e);
|
||||
}
|
||||
|
||||
$this->set('caps', $caps = new Loco_mvc_ViewParams );
|
||||
// there is no distinct role for network admin, so we'll fake it for UI
|
||||
if( is_multisite() ){
|
||||
$caps[''] = new Loco_mvc_ViewParams( array(
|
||||
'label' => __('Super Admin','default'),
|
||||
'name' => 'dummy-admin-cap',
|
||||
'attrs' => 'checked disabled'
|
||||
) );
|
||||
}
|
||||
foreach( $perms->getRoles() as $id => $role ){
|
||||
$caps[$id] = new Loco_mvc_ViewParams( array(
|
||||
'value' => '1',
|
||||
'label' => $perms->getRoleName($id),
|
||||
'name' => 'caps['.$id.'][loco_admin]',
|
||||
'attrs' => $perms->isProtectedRole($role) ? 'checked disabled ' : ( $role->has_cap('loco_admin') ? 'checked ' : '' ),
|
||||
) );
|
||||
}
|
||||
// allow/deny warning levels
|
||||
$this->set('verbose', new Loco_mvc_ViewParams( array(
|
||||
0 => __('Allow','loco-translate'),
|
||||
1 => __('Allow (with warning)','loco-translate'),
|
||||
2 => __('Disallow','loco-translate'),
|
||||
) ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$title = __('Plugin settings','loco-translate');
|
||||
$breadcrumb = new Loco_admin_Navigation;
|
||||
$breadcrumb->add( $title );
|
||||
|
||||
return $this->view('admin/config/settings', compact('breadcrumb') );
|
||||
}
|
||||
|
||||
}
|
65
vendor/loco-translate/src/admin/config/VersionController.php
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin version / upgrade screen
|
||||
*/
|
||||
class Loco_admin_config_VersionController extends Loco_admin_config_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->set( 'title', __('Version','loco-translate') );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$title = __('Plugin settings','loco-translate');
|
||||
$breadcrumb = new Loco_admin_Navigation;
|
||||
$breadcrumb->add( $title );
|
||||
|
||||
// current plugin version
|
||||
$version = loco_plugin_version();
|
||||
|
||||
// check for auto-update availability
|
||||
if( $updates = get_site_transient('update_plugins') ){
|
||||
$key = loco_plugin_self();
|
||||
if( isset($updates->response[$key]) ){
|
||||
$latest = $updates->response[$key]->new_version;
|
||||
// if current version is lower than latest, prompt update
|
||||
if( version_compare($version,$latest,'<') ){
|
||||
$this->setUpdate($latest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// notify if running a development snapshot, but only if ahead of latest stable
|
||||
if( '-dev' === substr($version,-4) ){
|
||||
$this->set( 'devel', true );
|
||||
}
|
||||
|
||||
// $this->setUpdate('2.0.1-debug');
|
||||
return $this->view('admin/config/version', compact('breadcrumb','version') );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string version
|
||||
* @return void
|
||||
*/
|
||||
private function setUpdate( $version ){
|
||||
$action = 'upgrade-plugin_'.loco_plugin_self();
|
||||
$link = admin_url( 'update.php?action=upgrade-plugin&plugin='.rawurlencode(loco_plugin_self()) );
|
||||
|
||||
$this->set('update', $version );
|
||||
$this->set('update_href', wp_nonce_url( $link, $action ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
167
vendor/loco-translate/src/admin/file/BaseController.php
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
/**
|
||||
* Base class for a file resource belonging to a bundle
|
||||
* Root > List > Bundle > Resource
|
||||
*/
|
||||
abstract class Loco_admin_file_BaseController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
/**
|
||||
* @var Loco_Locale
|
||||
*/
|
||||
private $locale;
|
||||
|
||||
|
||||
/**
|
||||
* @return Loco_Locale
|
||||
*/
|
||||
protected function getLocale(){
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check file is valid or return error
|
||||
* @param Loco_fs_File
|
||||
* @return string rendered error
|
||||
*/
|
||||
protected function getFileError( Loco_fs_File $file = null ){
|
||||
// file must exist for editing
|
||||
if( is_null($file) || ! $file->exists() ){
|
||||
return $this->view( 'admin/errors/file-missing', array() );
|
||||
}
|
||||
if( $file->isDirectory() ){
|
||||
$this->set('info', Loco_mvc_FileParams::create($file) );
|
||||
return $this->view( 'admin/errors/file-isdir', array() );
|
||||
}
|
||||
// security validations
|
||||
try {
|
||||
Loco_gettext_Data::ext( $file );
|
||||
// TODO also need to block access to files outside content directory
|
||||
// this is more difficult as can symlink into and out of the tree.
|
||||
}
|
||||
catch( Exception $e ){
|
||||
return $this->view( 'admin/errors/file-sec', array( 'reason' => $e->getMessage() ) );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
|
||||
// views at this level are always related to a file
|
||||
// file is permitted to be missing during this execution.
|
||||
$path = $this->get('path');
|
||||
if( ! $path ){
|
||||
throw new Loco_error_Exception('path argument required');
|
||||
}
|
||||
$file = new Loco_fs_LocaleFile( $path );
|
||||
$file->normalize( loco_constant('WP_CONTENT_DIR') );
|
||||
$ext = strtolower( $file->extension() );
|
||||
// POT file has no locale
|
||||
if( 'pot' === $ext ){
|
||||
$locale = null;
|
||||
$localised = false;
|
||||
}
|
||||
// else file may have a locale suffix (unless invalid, such as "default.po")
|
||||
else {
|
||||
$locale = $file->getLocale();
|
||||
$localised = $locale->isValid();
|
||||
}
|
||||
|
||||
if( $localised ){
|
||||
$this->locale = $locale;
|
||||
$code = (string) $locale;
|
||||
$this->set( 'locale', new Loco_mvc_ViewParams( array(
|
||||
'code' => $code,
|
||||
'lang' => $locale->lang,
|
||||
'icon' => $locale->getIcon(),
|
||||
'name' => $locale->ensureName( new Loco_api_WordPressTranslations ),
|
||||
'href' => Loco_mvc_AdminRouter::generate('lang-view', array('locale'=>$code) ),
|
||||
) ) );
|
||||
}
|
||||
else {
|
||||
$this->set( 'locale', null );
|
||||
}
|
||||
|
||||
$this->set('file', $file );
|
||||
$this->set('filetype', strtoupper($ext) );
|
||||
$this->set('title', $file->basename() );
|
||||
|
||||
// navigate up to root from this bundle sub view
|
||||
$bundle = $this->getBundle();
|
||||
$breadcrumb = Loco_admin_Navigation::createBreadcrumb( $bundle );
|
||||
$this->set( 'breadcrumb', $breadcrumb );
|
||||
|
||||
// navigate between sub view siblings for this resource
|
||||
$tabs = new Loco_admin_Navigation;
|
||||
$this->set( 'tabs', $tabs );
|
||||
$actions = array (
|
||||
'file-edit' => __('Editor','loco-translate'),
|
||||
'file-view' => __('Source','loco-translate'),
|
||||
'file-info' => __('File info','loco-translate'),
|
||||
'file-diff' => __('Restore','loco-translate'),
|
||||
'file-move' => $localised ? __('Relocate','loco-translate') : null,
|
||||
'file-delete' => __('Delete','loco-translate'),
|
||||
);
|
||||
|
||||
$suffix = $this->get('action');
|
||||
$prefix = $this->get('type');
|
||||
$args = array_intersect_key($_GET,array('path'=>1,'bundle'=>1,'domain'=>1));
|
||||
foreach( $actions as $action => $name ){
|
||||
if( is_string($name) ){
|
||||
$href = Loco_mvc_AdminRouter::generate( $prefix.'-'.$action, $args );
|
||||
$tabs->add( $name, $href, $action === $suffix );
|
||||
}
|
||||
}
|
||||
|
||||
// Provide common language creation link if project scope is is valid
|
||||
try {
|
||||
$project = $this->getProject();
|
||||
$args = array( 'bundle' => $bundle->getHandle(), 'domain' => $project->getId() );
|
||||
$this->set( 'msginit', new Loco_mvc_ViewParams( array (
|
||||
'href' => Loco_mvc_AdminRouter::generate( $prefix.'-msginit', $args ),
|
||||
'text' => __('New language','loco-translate'),
|
||||
) ) );
|
||||
}
|
||||
catch( Exception $e ){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function view( $tpl, array $args = array() ){
|
||||
|
||||
if( $breadcrumb = $this->get('breadcrumb') ){
|
||||
|
||||
// Add project name into breadcrumb if not the same as bundle name
|
||||
try {
|
||||
$project = $this->getProject();
|
||||
if( $project->getName() !== $this->getBundle()->getName() ){
|
||||
$breadcrumb->add( $project->getName() );
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
// ignore missing project in breadcrumb
|
||||
}
|
||||
|
||||
// Always add page title as final breadcrumb element
|
||||
$title = $this->get('title') or $title = 'Untitled';
|
||||
$breadcrumb->add( $title );
|
||||
}
|
||||
|
||||
return parent::view( $tpl, $args );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
113
vendor/loco-translate/src/admin/file/DeleteController.php
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* File delete function
|
||||
*/
|
||||
class Loco_admin_file_DeleteController extends Loco_admin_file_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* Expand single path to all files that will be deleted
|
||||
* @param Loco_fs_File primary file being deleted, probably the PO
|
||||
* @return array
|
||||
*/
|
||||
private function expandFiles( Loco_fs_File $file ){
|
||||
try {
|
||||
$siblings = new Loco_fs_Siblings( $file );
|
||||
}
|
||||
catch( InvalidArgumentException $e ){
|
||||
$ext = $file->extension();
|
||||
throw new Loco_error_Exception( sprintf('Refusing to delete a %s file', strtoupper($ext) ) );
|
||||
}
|
||||
return $siblings->expand();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$file = $this->get('file');
|
||||
|
||||
// set up form for delete confirmation
|
||||
if( $file->exists() && ! $file->isDirectory() ){
|
||||
// nonce action will be specific to file for extra security
|
||||
// TODO could also add file MD5 to avoid deletion after changes made.
|
||||
$path = $file->getPath();
|
||||
$action = 'delete:'.$path;
|
||||
// set up view now in case of late failure
|
||||
$fields = new Loco_mvc_HiddenFields( array() );
|
||||
$fields->setNonce( $action );
|
||||
$this->set( 'hidden', $fields );
|
||||
// attempt delete if valid nonce posted back
|
||||
if( $this->checkNonce($action) ){
|
||||
$api = new Loco_api_WordPressFileSystem;
|
||||
// delete dependant files first, so master still exists if others fail
|
||||
$files = array_reverse( $this->expandFiles($file) );
|
||||
try {
|
||||
/* @var $trash Loco_fs_File */
|
||||
foreach( $files as $trash ){
|
||||
$api->authorizeDelete($trash);
|
||||
$trash->unlink();
|
||||
}
|
||||
// flash message for display after redirect
|
||||
try {
|
||||
$n = count( $files );
|
||||
Loco_data_Session::get()->flash('success', sprintf( _n('File deleted','%u files deleted',$n,'loco-translate'),$n) );
|
||||
Loco_data_Session::close();
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// tolerate session failure
|
||||
}
|
||||
// redirect to bundle overview
|
||||
$href = Loco_mvc_AdminRouter::generate( $this->get('type').'-view', array( 'bundle' => $this->get('bundle') ) );
|
||||
if( wp_redirect($href) ){
|
||||
exit;
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add( $e );
|
||||
}
|
||||
}
|
||||
}
|
||||
// set page title before render sets inline title
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', sprintf( __('Delete %s','loco-translate'), $file->basename() ).' ‹ '.$bundle->getName() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$file = $this->get('file');
|
||||
if( $fail = $this->getFileError($file) ){
|
||||
return $fail;
|
||||
}
|
||||
|
||||
$files = $this->expandFiles( $file );
|
||||
$info = Loco_mvc_FileParams::create($file);
|
||||
$this->set( 'info', $info );
|
||||
$this->set( 'title', sprintf( __('Delete %s','loco-translate'), $info->name ) );
|
||||
|
||||
// warn about additional files that will be deleted along with this
|
||||
if( $deps = array_slice($files,1) ){
|
||||
$count = count($deps);
|
||||
$this->set('warn', sprintf( _n( 'One dependent file will also be deleted', '%u dependent files will also be deleted', $count, 'loco-translate' ), $count ) );
|
||||
$infos = array();
|
||||
foreach( $deps as $depfile ){
|
||||
$infos[] = Loco_mvc_FileParams::create( $depfile );
|
||||
}
|
||||
$this->set('deps', $infos );
|
||||
}
|
||||
|
||||
$this->prepareFsConnect( 'delete', $this->get('path') );
|
||||
|
||||
$this->enqueueScript('delete');
|
||||
return $this->view('admin/file/delete');
|
||||
}
|
||||
|
||||
}
|
156
vendor/loco-translate/src/admin/file/DiffController.php
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
/**
|
||||
* File revisions and rollback
|
||||
*/
|
||||
class Loco_admin_file_DiffController extends Loco_admin_file_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('podiff');
|
||||
|
||||
$pofile = $this->get('file');
|
||||
if( $pofile->exists() && ! $pofile->isDirectory() ){
|
||||
$path = $pofile->getPath();
|
||||
$action = 'restore:'.$path;
|
||||
// set up view now in case of late failure
|
||||
$fields = new Loco_mvc_HiddenFields( array() );
|
||||
$fields->setNonce( $action );
|
||||
$this->set( 'hidden', $fields );
|
||||
// attempt rollback if valid nonce posted back with backup path
|
||||
if( $this->checkNonce($action) ){
|
||||
try {
|
||||
$post = Loco_mvc_PostParams::get();
|
||||
$api = new Loco_api_WordPressFileSystem;
|
||||
// Restore
|
||||
if( $path = $post->backup ){
|
||||
$target = new Loco_fs_File( $path );
|
||||
$target->normalize( loco_constant('WP_CONTENT_DIR') );
|
||||
// parse PO. we'll need it for MO compile anyway
|
||||
$source = $target->getContents();
|
||||
$data = Loco_gettext_Data::fromSource( $source );
|
||||
// backup current master before restoring
|
||||
$backups = new Loco_fs_Revisions($pofile);
|
||||
if( $num_backups = Loco_data_Settings::get()->num_backups ){
|
||||
$api->authorizeCopy($pofile);
|
||||
$backups->create();
|
||||
}
|
||||
// authorize master for file modification
|
||||
$api->authorizeUpdate($pofile);
|
||||
// recompile binary if it exists
|
||||
$mofile = $pofile->cloneExtension('mo');
|
||||
if( $mofile->exists() ){
|
||||
$mofile->putContents( $data->msgfmt() );
|
||||
}
|
||||
// replacing source file last in case of failures
|
||||
$pofile->putContents( $source );
|
||||
Loco_error_AdminNotices::success( __('File restored','loco-translate') );
|
||||
// prune to configured level after success
|
||||
$backups->prune( $num_backups );
|
||||
$backups = null;
|
||||
}
|
||||
// Delete
|
||||
else if( $path = $post->delete ){
|
||||
$target = new Loco_fs_File( $path );
|
||||
$target->normalize( loco_constant('WP_CONTENT_DIR') );
|
||||
$api->authorizeDelete( $target );
|
||||
$target->unlink();
|
||||
Loco_error_AdminNotices::success( __('File deleted','loco-translate') );
|
||||
}
|
||||
else {
|
||||
throw new Loco_error_Exception('Nothing selected');
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add( $e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', sprintf( __('Restore %s','loco-translate'), $pofile->basename() ).' ‹ '.$bundle->getName() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$file = $this->get('file');
|
||||
if( $fail = $this->getFileError($file) ){
|
||||
return $fail;
|
||||
}
|
||||
|
||||
$info = Loco_mvc_FileParams::create($file);
|
||||
$info['mtime'] = $file->modified();
|
||||
$this->set( 'master', $info );
|
||||
$this->set( 'title', sprintf( __('Restore %s','loco-translate'), $info->name ) );
|
||||
|
||||
$enabled = Loco_data_Settings::get()->num_backups;
|
||||
$this->set( 'enabled', $enabled );
|
||||
|
||||
$files = array();
|
||||
$wp_content = loco_constant('WP_CONTENT_DIR');
|
||||
$paths = array( $file->getRelativePath($wp_content) );
|
||||
|
||||
$podate = 'pot' === $file->extension() ? 'POT-Creation-Date' : 'PO-Revision-Date';
|
||||
$backups = new Loco_fs_Revisions($file);
|
||||
|
||||
foreach( $backups->getPaths() as $path ){
|
||||
$tmp = new Loco_fs_File( $path );
|
||||
$info = Loco_mvc_FileParams::create($tmp);
|
||||
// time file was snapshotted is actually the time the next version was updated
|
||||
// $info['mtime'] = $backups->getTimestamp($path);
|
||||
// pull "real" update time, meaning when the revision was last updated as current version
|
||||
try {
|
||||
$head = Loco_gettext_Data::head($tmp)->getHeaders();
|
||||
if( $value = $head->trimmed($podate) ){
|
||||
$info['potime'] = Loco_gettext_Data::parseDate($value);
|
||||
}
|
||||
else {
|
||||
throw new Loco_error_Exception('Backup has no '.$podate.' field');
|
||||
}
|
||||
}
|
||||
catch( Exception $e ){
|
||||
Loco_error_AdminNotices::debug( $e->getMessage() );
|
||||
continue;
|
||||
}
|
||||
$paths[] = $tmp->getRelativePath($wp_content);
|
||||
$files[] = $info;
|
||||
}
|
||||
|
||||
// no backups = no restore
|
||||
if( ! $files ){
|
||||
return $this->view('admin/errors/no-backups');
|
||||
}
|
||||
|
||||
/*/ warn if current backup settings aren't enough to restore without losing older revisions
|
||||
$min = count($files) + 1;
|
||||
if( $enabled < $min ){
|
||||
$notice = Loco_error_AdminNotices::info('We recommend enabling more backups before restoring');
|
||||
$notice->addLink( apply_filters('loco_external','https://localise.biz/wordpress/plugin/manual/settings#po'), __('Documentation','loco-translate') )
|
||||
->addLink( Loco_mvc_AdminRouter::generate('config').'#loco--num-backups', __('Settings') );
|
||||
}*/
|
||||
|
||||
// restore permissions required are create and delete on current location
|
||||
$this->prepareFsConnect( 'update', $this->get('path') );
|
||||
|
||||
// prepare revision arguments for JavaScript
|
||||
$this->set( 'js', new Loco_mvc_ViewParams( array(
|
||||
'paths' => $paths,
|
||||
'nonces' => array (
|
||||
'diff' => wp_create_nonce('diff'),
|
||||
)
|
||||
) ) );
|
||||
|
||||
$this->enqueueScript('podiff');
|
||||
return $this->view('admin/file/diff', compact('files','backups') );
|
||||
}
|
||||
|
||||
|
||||
}
|
245
vendor/loco-translate/src/admin/file/EditController.php
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
<?php
|
||||
/**
|
||||
* PO editor view
|
||||
*/
|
||||
class Loco_admin_file_EditController extends Loco_admin_file_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('editor');
|
||||
//
|
||||
$file = $this->get('file');
|
||||
$bundle = $this->getBundle();
|
||||
// translators: %1$s is the file name, %2$s is the bundle name
|
||||
$this->set('title', sprintf( __('Editing %1$s in %2$s','loco-translate'), $file->basename(), $bundle ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-file-edit'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool whether po files is in read-only mode
|
||||
* @return array
|
||||
*/
|
||||
private function getNonces( $readonly ){
|
||||
$nonces = array();
|
||||
foreach( $readonly ? array('fsReference') : array('sync','save','fsReference','apis') as $name ){
|
||||
$nonces[$name] = wp_create_nonce($name);
|
||||
}
|
||||
return $nonces;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool whether po files is in read-only mode
|
||||
* @return array
|
||||
*/
|
||||
private function getApiProviders( $readonly ){
|
||||
return $readonly ? null : array_values( array_filter(Loco_api_Providers::export(),array(__CLASS__,'filterApiProvider') ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param string[]
|
||||
* @return bool
|
||||
*/
|
||||
private static function filterApiProvider( array $api ){
|
||||
return (bool) $api['key'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
// file must exist for editing
|
||||
$file = $this->get('file');
|
||||
if( $fail = $this->getFileError($file) ){
|
||||
return $fail;
|
||||
}
|
||||
|
||||
// editor will be rendered
|
||||
$this->enqueueScript('editor');
|
||||
|
||||
// Parse file data into JavaScript for editor
|
||||
try {
|
||||
$this->set('modified', $file->modified() );
|
||||
$data = Loco_gettext_Data::load( $file );
|
||||
}
|
||||
catch( Exception $e ){
|
||||
Loco_error_AdminNotices::add( Loco_error_Exception::convert($e) );
|
||||
$data = Loco_gettext_Data::dummy();
|
||||
}
|
||||
|
||||
$head = $data->getHeaders();
|
||||
|
||||
// default is to permit editing of any file
|
||||
$readonly = false;
|
||||
|
||||
// Establish if file belongs to a configured project
|
||||
try {
|
||||
$bundle = $this->getBundle();
|
||||
$project = $this->getProject();
|
||||
}
|
||||
// Fine if not, this just means sync isn't possible.
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add( $e );
|
||||
Loco_error_AdminNotices::debug( sprintf("Sync is disabled because this file doesn't relate to a known set of translations", $bundle ) );
|
||||
$project = null;
|
||||
}
|
||||
|
||||
// Establish PO/POT edit mode
|
||||
$potfile = null;
|
||||
$locale = $this->getLocale();
|
||||
if( $locale instanceof Loco_Locale ){
|
||||
// alternative POT file may be forced by PO headers
|
||||
if( $value = $head['X-Loco-Template'] ){
|
||||
$potfile = new Loco_fs_File($value);
|
||||
$potfile->normalize( $bundle->getDirectoryPath() );
|
||||
}
|
||||
// else use project-configured template, assuming there is one
|
||||
// no way to get configured POT if invalid project
|
||||
else if( $project ){
|
||||
$potfile = $project->getPot();
|
||||
// Handle situation where project defines a localised file as the official template
|
||||
if( $potfile && $potfile->equal($file) ){
|
||||
$locale = null;
|
||||
$potfile = null;
|
||||
}
|
||||
}
|
||||
if( $potfile ){
|
||||
// Validate template file as long as it exists
|
||||
if( $potfile->exists() ){
|
||||
try {
|
||||
$potdata = Loco_gettext_Data::load( $potfile );
|
||||
if( ! $potdata->equalSource($data) ){
|
||||
Loco_error_AdminNotices::debug( sprintf( __("Translations don't match template. Run sync to update from %s",'loco-translate'), $potfile->basename() ) );
|
||||
}
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// translators: Where %s is the name of the invalid POT file
|
||||
Loco_error_AdminNotices::warn( sprintf( __('Translation template is invalid (%s)','loco-translate'), $potfile->basename() ) );
|
||||
$potfile = null;
|
||||
}
|
||||
}
|
||||
// else template doesn't exist, so sync will be done to source code
|
||||
else {
|
||||
// Loco_error_AdminNotices::debug( sprintf( __('Template file not found (%s)','loco-translate'), $potfile->basename() ) );
|
||||
$potfile = null;
|
||||
}
|
||||
}
|
||||
if( $locale ){
|
||||
// allow PO file to dictate its own Plural-Forms
|
||||
try {
|
||||
$locale->setPluralFormsHeader( $head['Plural-Forms'] );
|
||||
}
|
||||
catch( InvalidArgumentException $e ){
|
||||
// ignore invalid Plural-Forms
|
||||
}
|
||||
// fill in missing PO headers now locale is fully resolved
|
||||
$data->localize($locale);
|
||||
|
||||
// If MO file will be compiled, check for library/config problems
|
||||
if ( 2 !== strlen( "\xC2\xA3" ) ) {
|
||||
Loco_error_AdminNotices::warn('Your mbstring configuration will result in corrupt MO files. Please ensure mbstring.func_overload is disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$settings = Loco_data_Settings::get();
|
||||
|
||||
if( is_null($locale) ){
|
||||
// notify if template is locked (save and sync will be disabled)
|
||||
if( $project && $project->isPotLocked() ){
|
||||
$this->set('fsDenied', true );
|
||||
$readonly = true;
|
||||
}
|
||||
// translators: Warning when POT file is opened in the file editor. It can be disabled in settings.
|
||||
else if( 1 === $settings->pot_protect ){
|
||||
Loco_error_AdminNotices::warn( __("This is NOT a translation file. Manual editing of source strings is not recommended.",'loco-translate') )
|
||||
->addLink( Loco_mvc_AdminRouter::generate('config').'#loco--pot-protect', __('Settings','loco-translate') )
|
||||
->addLink( apply_filters('loco_external','https://localise.biz/wordpress/plugin/manual/templates'), __('Documentation','loco-translate') );
|
||||
}
|
||||
}
|
||||
|
||||
// back end expects paths relative to wp-content
|
||||
$wp_content = loco_constant('WP_CONTENT_DIR');
|
||||
|
||||
$this->set( 'js', new Loco_mvc_ViewParams( array(
|
||||
'podata' => $data->jsonSerialize(),
|
||||
'powrap' => (int) $settings->po_width,
|
||||
'multipart' => (bool) $settings->ajax_files,
|
||||
'locale' => $locale ? $locale->jsonSerialize() : null,
|
||||
'potpath' => $locale && $potfile ? $potfile->getRelativePath($wp_content) : null,
|
||||
'popath' => $this->get('path'),
|
||||
'readonly' => $readonly,
|
||||
'project' => $project ? array (
|
||||
'bundle' => $bundle->getId(),
|
||||
'domain' => (string) $project->getId(),
|
||||
) : null,
|
||||
'nonces' => $this->getNonces($readonly),
|
||||
'apis' => $locale ? $this->getApiProviders($readonly) : null,
|
||||
) ) );
|
||||
$this->set( 'ui', new Loco_mvc_ViewParams( array(
|
||||
// Translators: button for adding a new string when manually editing a POT file
|
||||
'add' => _x('Add','Editor','loco-translate'),
|
||||
// Translators: button for removing a string when manually editing a POT file
|
||||
'del' => _x('Remove','Editor','loco-translate'),
|
||||
'help' => __('Help','loco-translate'),
|
||||
// Translators: Button that saves translations to disk
|
||||
'save' => _x('Save','Editor','loco-translate'),
|
||||
// Translators: Button that runs in-editor sync/operation
|
||||
'sync' => _x('Sync','Editor','loco-translate'),
|
||||
// Translators: Button that reloads current screen
|
||||
'revert' => _x('Revert','Editor','loco-translate'),
|
||||
// Translators: Button that opens window for auto-translating
|
||||
'auto' => _x('Auto','Editor','loco-translate'),
|
||||
// Translators: Button for downloading a PO, MO or POT file
|
||||
'download' => _x('Download','Editor','loco-translate'),
|
||||
// Translators: Placeholder text for text filter above editor
|
||||
'filter' => __('Filter translations','loco-translate'),
|
||||
// Translators: Button that toggles invisible characters
|
||||
'invs' => _x('Toggle invisibles','Editor','loco-translate'),
|
||||
// Translators: Button that toggles between "code" and regular text editing modes
|
||||
'code' => _x('Toggle code view','Editor','loco-translate'),
|
||||
) ) );
|
||||
|
||||
// Download form params
|
||||
$hidden = new Loco_mvc_HiddenFields( array(
|
||||
'path' => '',
|
||||
'source' => '',
|
||||
'route' => 'download',
|
||||
'action' => 'loco_download',
|
||||
) );
|
||||
$this->set( 'dlFields', $hidden->setNonce('download') );
|
||||
$this->set( 'dlAction', admin_url('admin-ajax.php','relative') );
|
||||
|
||||
// Remote file system required if file is not directly writable
|
||||
$this->prepareFsConnect( 'update', $this->get('path') );
|
||||
|
||||
// set simpler title for breadcrumb
|
||||
$this->set('title', $file->basename() );
|
||||
|
||||
// ok to render editor as either po or pot
|
||||
$tpl = $locale ? 'po' : 'pot';
|
||||
return $this->view( 'admin/file/edit-'.$tpl, array() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
201
vendor/loco-translate/src/admin/file/InfoController.php
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
/**
|
||||
* File info / management view.
|
||||
*/
|
||||
class Loco_admin_file_InfoController extends Loco_admin_file_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('fileinfo');
|
||||
//
|
||||
$file = $this->get('file');
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', $file->basename().' ‹ '.$bundle->getName() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-file-info'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$file = $this->get('file');
|
||||
$name = $file->basename();
|
||||
$this->set('title', $name );
|
||||
|
||||
if( $fail = $this->getFileError($file) ){
|
||||
return $fail;
|
||||
}
|
||||
|
||||
// file info
|
||||
$ext = strtolower( $file->extension() );
|
||||
$finfo = Loco_mvc_FileParams::create( $file );
|
||||
$this->set('file', $finfo );
|
||||
$finfo['type'] = strtoupper($ext);
|
||||
if( $file->exists() ){
|
||||
$finfo['existent'] = true;
|
||||
$finfo['writable'] = $file->writable();
|
||||
$finfo['deletable'] = $file->deletable();
|
||||
$finfo['mtime'] = $file->modified();
|
||||
// Notify if file is managed by WordPress
|
||||
$api = new Loco_api_WordPressFileSystem;
|
||||
if( $api->isAutoUpdatable($file) ){
|
||||
$finfo['autoupdate'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// location info
|
||||
$dir = new Loco_fs_LocaleDirectory( $file->dirname() );
|
||||
$dinfo = Loco_mvc_FileParams::create( $dir );
|
||||
$this->set('dir', $dinfo );
|
||||
$dinfo['type'] = $dir->getTypeId();
|
||||
if( $dir->exists() && $dir->isDirectory() ){
|
||||
$dinfo['existent'] = true;
|
||||
$dinfo['writable'] = $dir->writable();
|
||||
}
|
||||
|
||||
// collect note worthy problems with file headers
|
||||
$debugging = loco_debugging();
|
||||
$debug = array();
|
||||
|
||||
// get the name of the web server for information purposes
|
||||
$this->set('httpd', Loco_compat_PosixExtension::getHttpdUser() );
|
||||
|
||||
// unknown file template if required
|
||||
$locale = null;
|
||||
$project = null;
|
||||
$tpl = 'admin/file/info-other';
|
||||
|
||||
// we should know the project the file belongs to, but permitting orphans for debugging
|
||||
try {
|
||||
$project = $this->getProject();
|
||||
$template = $project->getPot();
|
||||
$isTemplate = $template && $file->equal($template);
|
||||
$this->set('isTemplate', $isTemplate );
|
||||
$this->set('project', $project );
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
$debug[] = $e->getMessage();
|
||||
$isTemplate = false;
|
||||
$template = null;
|
||||
}
|
||||
|
||||
// file will be Gettext most likely
|
||||
if( 'pot' === $ext || 'po' === $ext || 'mo' === $ext ){
|
||||
// treat as template until locale verified
|
||||
$tpl = 'admin/file/info-pot';
|
||||
// don't attempt to pull locale of template file
|
||||
if( 'pot' !== $ext && ! $isTemplate ){
|
||||
$locale = $file->getLocale();
|
||||
$code = (string) $locale;
|
||||
if( $locale->isValid() ){
|
||||
// find PO/MO counter parts
|
||||
if( 'po' === $ext ){
|
||||
$tpl = 'admin/file/info-po';
|
||||
$sibling = $file->cloneExtension('mo');
|
||||
}
|
||||
else {
|
||||
$tpl = 'admin/file/info-mo';
|
||||
$sibling = $file->cloneExtension('po');
|
||||
}
|
||||
$info = Loco_mvc_FileParams::create($sibling);
|
||||
$this->set( 'sibling', $info );
|
||||
if( $sibling->exists() ){
|
||||
$info['existent'] = true;
|
||||
$info['writable'] = $sibling->writable();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Do full parse to get stats and headers
|
||||
try {
|
||||
$data = Loco_gettext_Data::load($file);
|
||||
$head = $data->getHeaders();
|
||||
$author = $head->trimmed('Last-Translator') or $author = __('Unknown author','loco-translate');
|
||||
$this->set( 'author', $author );
|
||||
// date headers may not be same as file modification time (files copied to server etc..)
|
||||
$podate = $head->trimmed( $locale ? 'PO-Revision-Date' : 'POT-Creation-Date' );
|
||||
$potime = Loco_gettext_Data::parseDate($podate) or $potime = $file->modified();
|
||||
$this->set('potime', $potime );
|
||||
// access to meta stats, normally cached on listing pages
|
||||
$meta = Loco_gettext_Metadata::create($file,$data);
|
||||
$this->set( 'meta', $meta );
|
||||
// allow PO header to specify alternative template for sync
|
||||
if( $head->has('X-Loco-Template') ){
|
||||
$altpot = new Loco_fs_File($head['X-Loco-Template']);
|
||||
$altpot->normalize( $this->getBundle()->getDirectoryPath() );
|
||||
if( $altpot->exists() && ( ! $template || ! $template->equal($altpot) ) ){
|
||||
$template = $altpot;
|
||||
}
|
||||
}
|
||||
// establish whether PO is in sync with POT
|
||||
if( $template && ! $isTemplate && 'po' === $ext && $template->exists() ){
|
||||
try {
|
||||
$this->set('potfile', new Loco_mvc_FileParams( array(
|
||||
'synced' => Loco_gettext_Data::load($template)->equalSource($data),
|
||||
), $template ) );
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// ignore invalid template in this context
|
||||
}
|
||||
}
|
||||
if( $debugging ){
|
||||
// missing or invalid headers are tollerated but developers should be notified
|
||||
if( $debugging && ! count($head) ){
|
||||
$debug[] = __('File does not have a valid header','loco-translate');
|
||||
}
|
||||
// Language header sanity checks, raising developer (debug) warnings
|
||||
if( $locale ){
|
||||
if( $value = $head['Language'] ){
|
||||
$check = (string) Loco_Locale::parse($value);
|
||||
if( $check !== $code ){
|
||||
$debug[]= sprintf( __('Language header is "%s" but file name contains "%s"','loco-translate'), $value, $code );
|
||||
}
|
||||
}
|
||||
if( $value = $head['Plural-Forms'] ){
|
||||
try {
|
||||
$locale->setPluralFormsHeader($value);
|
||||
}
|
||||
catch( InvalidArgumentException $e ){
|
||||
$debug[] = sprintf('Plural-Forms header is invalid, "%s"',$value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Other sanity checks
|
||||
if( $project && ( $value = $head['Project-Id-Version'] ) && $value !== $project->getName() ){
|
||||
$debug[] = sprintf('Project-Id-Version header is "%s" but project is "%s"', $value, $project );
|
||||
}
|
||||
}
|
||||
// Count source text for templates only (assumed English)
|
||||
if( 'admin/file/info-pot' === $tpl ){
|
||||
$counter = new Loco_gettext_WordCount($data);
|
||||
$this->set('words', $counter->count() );
|
||||
}
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
$this->set('error', $e->getMessage() );
|
||||
$tpl = 'admin/file/info-other';
|
||||
}
|
||||
}
|
||||
|
||||
if( $debugging && $debug ){
|
||||
$this->set( 'debug', new Loco_mvc_ViewParams($debug) );
|
||||
}
|
||||
|
||||
return $this->view( $tpl );
|
||||
}
|
||||
|
||||
}
|
185
vendor/loco-translate/src/admin/file/MoveController.php
vendored
Normal file
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
/**
|
||||
* Translation set relocation tool.
|
||||
* Moves PO/MO pair and all related files to a new location
|
||||
*/
|
||||
class Loco_admin_file_MoveController extends Loco_admin_file_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$file = $this->get('file');
|
||||
/* @var Loco_fs_File $file */
|
||||
if( $file->exists() && ! $file->isDirectory() ){
|
||||
$files = new Loco_fs_Siblings($file);
|
||||
// nonce action will be specific to file for extra security
|
||||
$path = $file->getPath();
|
||||
$action = 'move:'.$path;
|
||||
// set up view now in case of late failure
|
||||
$fields = new Loco_mvc_HiddenFields( array() );
|
||||
$fields->setNonce( $action );
|
||||
$fields['auth'] = 'move';
|
||||
$fields['path'] = $this->get('path');
|
||||
$this->set('hidden',$fields );
|
||||
// attempt move if valid nonce posted back
|
||||
while( $this->checkNonce($action) ){
|
||||
// Chosen location should be valid as a posted "dest" parameter
|
||||
if( ! Loco_mvc_PostParams::get()->has('dest') ){
|
||||
Loco_error_AdminNotices::err('No destination posted');
|
||||
break;
|
||||
}
|
||||
$target = new Loco_fs_LocaleFile( Loco_mvc_PostParams::get()->dest );
|
||||
$ext = $target->extension();
|
||||
// primary file extension should only be permitted to change between po and pot
|
||||
if( $ext !== $file->extension() && 'po' !== $ext && 'pot' !== $ext ){
|
||||
Loco_error_AdminNotices::err('Invalid file extension, *.po or *.pot only');
|
||||
break;
|
||||
}
|
||||
$target->normalize( loco_constant('WP_CONTENT_DIR') );
|
||||
$target_dir = $target->getParent()->getPath();
|
||||
// Primary file gives template remapping, so all files are renamed with same stub.
|
||||
// this can only be one of three things: (en -> en) or (foo-en -> en) or (en -> foo-en)
|
||||
// suffix will then consist of file extension, plus any other stuff like backup file date.
|
||||
$target_base = $target->filename();
|
||||
$source_snip = strlen( $file->filename() );
|
||||
// buffer all files to move to preempt write failures
|
||||
$movable = array();
|
||||
$api = new Loco_api_WordPressFileSystem;
|
||||
foreach( $files->expand() as $source ){
|
||||
$suffix = substr( $source->basename(), $source_snip ); // <- e.g. "-backup.po~"
|
||||
$target = new Loco_fs_File( $target_dir.'/'.$target_base.$suffix );
|
||||
// permit valid change of file extension on primary source file (po/pot)
|
||||
if( $source === $files->getSource() && $target->extension() !== $ext ){
|
||||
$target = $target->cloneExtension($ext);
|
||||
}
|
||||
if( ! $api->authorizeMove($source,$target) ) {
|
||||
Loco_error_AdminNotices::err('Failed to authorize relocation of '.$source->basename() );
|
||||
break 2;
|
||||
}
|
||||
$movable[] = array($source,$target);
|
||||
}
|
||||
// commit moves. If any fail we'll have separated the files, which is bad
|
||||
$count = 0;
|
||||
$total = count($movable);
|
||||
foreach( $movable as $pair ){
|
||||
try {
|
||||
$pair[0]->move( $pair[1] );
|
||||
$count++;
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::add($e);
|
||||
}
|
||||
}
|
||||
// flash messages for display after redirect
|
||||
try {
|
||||
if( $count ) {
|
||||
Loco_data_Session::get()->flash( 'success', sprintf( _n( 'File moved', '%u files moved', $total, 'loco-translate' ), $total ) );
|
||||
}
|
||||
if( $total > $count ){
|
||||
$diff = $total - $count;
|
||||
Loco_data_Session::get()->flash( 'error', sprintf( _n( 'One file could not be moved', '%u files could not be moved', $diff, 'loco-translate' ), $diff ) );
|
||||
}
|
||||
Loco_data_Session::close();
|
||||
}
|
||||
catch( Exception $e ){
|
||||
// tolerate session failure
|
||||
}
|
||||
// redirect to bundle overview
|
||||
$href = Loco_mvc_AdminRouter::generate( $this->get('type').'-view', array( 'bundle' => $this->get('bundle') ) );
|
||||
if( wp_redirect($href) ){
|
||||
exit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// set page title before render sets inline title
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', sprintf( __('Move %s','loco-translate'), $file->basename() ).' ‹ '.$bundle->getName() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
$file = $this->get('file');
|
||||
if( $fail = $this->getFileError($file) ){
|
||||
return $fail;
|
||||
}
|
||||
// relocation requires knowing text domain and locale
|
||||
try {
|
||||
$project = $this->getProject();
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
Loco_error_AdminNotices::warn($e->getMessage());
|
||||
$project = null;
|
||||
}
|
||||
$files = new Loco_fs_Siblings($file);
|
||||
$file = new Loco_fs_LocaleFile( $files->getSource() );
|
||||
$locale = $file->getLocale();
|
||||
// switch between canonical move and custom file path mode
|
||||
$custom = is_null($project) || $this->get('custom') || 'po' !== $file->extension() || ! $locale->isValid();
|
||||
// common page elements:
|
||||
$this->set('files',$files->expand() );
|
||||
$this->set('title', sprintf( __('Move %s','loco-translate'), $file->filename() ) );
|
||||
$this->enqueueScript('move');
|
||||
// set info for existing file location
|
||||
$content_dir = loco_constant('WP_CONTENT_DIR');
|
||||
$current = $file->getRelativePath($content_dir);
|
||||
$parent = new Loco_fs_LocaleDirectory( $file->dirname() );
|
||||
$typeId = $parent->getTypeId();
|
||||
$this->set('current', new Loco_mvc_ViewParams(array(
|
||||
'path' => $parent->getRelativePath($content_dir),
|
||||
'type' => $parent->getTypeLabel($typeId),
|
||||
)) );
|
||||
// moving files will require deletion permission on current file location
|
||||
// plus write permission on target location, but we don't know what that is yet.
|
||||
$fields = $this->prepareFsConnect('move',$current);
|
||||
$fields['path'] = '';
|
||||
$fields['dest'] = '';
|
||||
// custom file move template (POT mode)
|
||||
if( $custom ){
|
||||
$this->get('hidden')->offsetSet('custom','1');
|
||||
$this->set('file', Loco_mvc_FileParams::create($file) );
|
||||
return $this->view('admin/file/move-pot');
|
||||
}
|
||||
// establish valid locations for translation set, which may include current:
|
||||
$filechoice = $project->initLocaleFiles($locale);
|
||||
// start with current location so always first in list
|
||||
$locations = array();
|
||||
$locations[$typeId] = new Loco_mvc_ViewParams( array(
|
||||
'label' => $parent->getTypeLabel($typeId),
|
||||
'paths' => array( new Loco_mvc_ViewParams( array(
|
||||
'path' => $current,
|
||||
'active' => true,
|
||||
) ) )
|
||||
) );
|
||||
/* @var Loco_fs_File $pofile */
|
||||
foreach( $filechoice as $pofile ){
|
||||
$relpath = $pofile->getRelativePath($content_dir);
|
||||
if( $current === $relpath ){
|
||||
continue;
|
||||
}
|
||||
// initialize location type (system, etc..)
|
||||
$parent = new Loco_fs_LocaleDirectory( $pofile->dirname() );
|
||||
$typeId = $parent->getTypeId();
|
||||
if( ! isset($locations[$typeId]) ){
|
||||
$locations[$typeId] = new Loco_mvc_ViewParams( array(
|
||||
'label' => $parent->getTypeLabel($typeId),
|
||||
'paths' => array(),
|
||||
) );
|
||||
}
|
||||
$choice = new Loco_mvc_ViewParams( array(
|
||||
'path' => $relpath,
|
||||
) );
|
||||
$locations[$typeId]['paths'][] = $choice;
|
||||
}
|
||||
$this->set('locations', $locations );
|
||||
$this->set('advanced', $_SERVER['REQUEST_URI'].'&custom=1' );
|
||||
return $this->view('admin/file/move-po');
|
||||
}
|
||||
|
||||
}
|
101
vendor/loco-translate/src/admin/file/ViewController.php
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
/**
|
||||
* File view / source formatted view.
|
||||
*/
|
||||
class Loco_admin_file_ViewController extends Loco_admin_file_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('poview');
|
||||
//
|
||||
$file = $this->get('file');
|
||||
$bundle = $this->getBundle();
|
||||
$this->set( 'title', 'Source of '.$file->basename().' ‹ '.$bundle->getName() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-file-view'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
// file must exist for editing
|
||||
/* @var Loco_fs_File $file */
|
||||
$file = $this->get('file');
|
||||
$name = $file->basename();
|
||||
$type = strtolower( $file->extension() );
|
||||
$this->set('title', $name );
|
||||
|
||||
if( $fail = $this->getFileError($file) ){
|
||||
return $fail;
|
||||
}
|
||||
|
||||
// Establish if file belongs to a configured project
|
||||
try {
|
||||
$bundle = $this->getBundle();
|
||||
$project = $this->getProject();
|
||||
}
|
||||
catch( Exception $e ){
|
||||
$project = null;
|
||||
}
|
||||
|
||||
// Parse data before rendering, so we know it's a valid Gettext format
|
||||
try {
|
||||
$this->set('modified', $file->modified() );
|
||||
$data = Loco_gettext_Data::load( $file );
|
||||
}
|
||||
catch( Loco_error_ParseException $e ){
|
||||
Loco_error_AdminNotices::add( Loco_error_Exception::convert($e) );
|
||||
$data = Loco_gettext_Data::dummy();
|
||||
}
|
||||
|
||||
$this->set( 'meta', Loco_gettext_Metadata::create($file, $data) );
|
||||
|
||||
// binary MO will be hex-formatted in template
|
||||
if( 'mo' === $type ){
|
||||
$this->set('bin', $file->getContents() );
|
||||
return $this->view('admin/file/view-mo' );
|
||||
}
|
||||
|
||||
// else is a PO or POT file
|
||||
$this->enqueueScript('poview');//->enqueueScript('min/highlight');
|
||||
$lines = preg_split('/(?:\\n|\\r\\n?)/', Loco_gettext_Data::ensureUtf8( $file->getContents() ) );
|
||||
$this->set( 'lines', $lines );
|
||||
|
||||
// ajax parameters required for pulling reference sources
|
||||
$this->set('js', new Loco_mvc_ViewParams( array (
|
||||
'popath' => $this->get('path'),
|
||||
'nonces' => array(
|
||||
'fsReference' => wp_create_nonce('fsReference'),
|
||||
),
|
||||
'project' => $bundle ? array (
|
||||
'bundle' => $bundle->getId(),
|
||||
'domain' => $project ? $project->getId() : '',
|
||||
) : null,
|
||||
) ) );
|
||||
|
||||
|
||||
// treat as PO if file name has locale
|
||||
if( $this->getLocale() ){
|
||||
return $this->view('admin/file/view-po' );
|
||||
}
|
||||
|
||||
// else view as POT
|
||||
return $this->view('admin/file/view-pot' );
|
||||
}
|
||||
|
||||
}
|
0
vendor/loco-translate/src/admin/init/BaseController.php
vendored
Normal file
327
vendor/loco-translate/src/admin/init/InitPoController.php
vendored
Normal file
|
@ -0,0 +1,327 @@
|
|||
<?php
|
||||
/**
|
||||
* pre-msginit function. Prepares arguments for creating a new PO language file
|
||||
*/
|
||||
class Loco_admin_init_InitPoController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('poinit');
|
||||
//
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', __('New language','loco-translate').' ‹ '.$bundle );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-init-po'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sort to the left the best option for saving new translation files
|
||||
* @return Loco_mvc_ViewParams
|
||||
*/
|
||||
private function sortPreferred( array $choices ){
|
||||
usort( $choices, array(__CLASS__,'_onSortPreferred') );
|
||||
$best = current( $choices );
|
||||
if( $best && ! $best['disabled'] ){
|
||||
return $best;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function _onSortPreferred( Loco_mvc_ViewParams $a, Loco_mvc_ViewParams $b ){
|
||||
$x = self::scoreFileChoice($a);
|
||||
$y = self::scoreFileChoice($b);
|
||||
return $x === $y ? 0 : ( $x > $y ? -1 : 1 );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Score an individual file choice for sorting preferred
|
||||
* @return int
|
||||
*/
|
||||
private static function scoreFileChoice( Loco_mvc_ViewParams $p ){
|
||||
$score = 0;
|
||||
if( $p['writable'] ){
|
||||
$score++;
|
||||
}
|
||||
if( $p['disabled'] ){
|
||||
$score -= 2;
|
||||
}
|
||||
if( $p['systype'] ){
|
||||
$score--;
|
||||
}
|
||||
return $score;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function _onSortLocationKeys( $a, $b ){
|
||||
static $order = array('custom' => 4, 'wplang' => 3, 'theme' => 2, 'plugin' => 2, 'other' => 1 );
|
||||
$x = $order[$a];
|
||||
$y = $order[$b];
|
||||
return $x === $y ? 0 : ( $x > $y ? -1 : 1 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$breadcrumb = $this->prepareNavigation();
|
||||
// "new" tab is confusing when no project-scope navigation
|
||||
// $this->get('tabs')->add( __('New PO','loco-translate'), '', true );
|
||||
|
||||
// bundle mandatory, but project optional
|
||||
$bundle = $this->getBundle();
|
||||
|
||||
try {
|
||||
$project = $this->getProject();
|
||||
$slug = $project->getSlug();
|
||||
$domain = (string) $project->getDomain();
|
||||
$subhead = sprintf( __('Initializing new translations in "%s"','loco-translate'), $slug?$slug:$domain );
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
$project = null;
|
||||
$subhead = __('Initializing new translations in unknown set','loco-translate');
|
||||
}
|
||||
|
||||
$title = __('New language','loco-translate');
|
||||
$this->set('subhead', $subhead );
|
||||
|
||||
// navigate up to bundle listing page
|
||||
$breadcrumb->add( $title );
|
||||
$this->set( 'breadcrumb', $breadcrumb );
|
||||
|
||||
// default locale is a placeholder
|
||||
$locale = new Loco_Locale('zxx');
|
||||
$content_dir = untrailingslashit( loco_constant('WP_CONTENT_DIR') );
|
||||
$copying = false;
|
||||
|
||||
// Permit using any provided file a template instead of POT
|
||||
if( $potpath = $this->get('path') ){
|
||||
$potfile = new Loco_fs_LocaleFile($potpath);
|
||||
$potfile->normalize( $content_dir );
|
||||
if( ! $potfile->exists() ){
|
||||
throw new Loco_error_Exception('Forced template argument must exist');
|
||||
}
|
||||
$copying = true;
|
||||
// forced source could be a POT (although UI would normally prevent it)
|
||||
if( $potfile->getSuffix() ){
|
||||
$locale = $potfile->getLocale();
|
||||
$this->set('sourceLocale', $locale );
|
||||
}
|
||||
}
|
||||
// else project not configured. UI should prevent this by not offering msginit
|
||||
else if( ! $project ){
|
||||
throw new Loco_error_Exception('Cannot add new language to unconfigured set');
|
||||
}
|
||||
// else POT file may or may not be known, and may or may not exist
|
||||
else {
|
||||
$potfile = $project->getPot();
|
||||
}
|
||||
|
||||
|
||||
$locales = array();
|
||||
$installed = array();
|
||||
$api = new Loco_api_WordPressTranslations;
|
||||
// pull installed list first, this will include en_US and any non-standard languages installed
|
||||
foreach( $api->getInstalledCore() as $tag ){
|
||||
$locale = Loco_Locale::parse($tag);
|
||||
if( $locale->isValid() ){
|
||||
$tag = (string) $tag;
|
||||
// We may not have names for these, so just the language tag will show
|
||||
$installed[$tag] = new Loco_mvc_ViewParams( array(
|
||||
'value' => $tag,
|
||||
'icon' => $locale->getIcon(),
|
||||
'label' => $locale->ensureName($api),
|
||||
) );
|
||||
}
|
||||
}
|
||||
// pull the same list of "available" languages as used in WordPress settings
|
||||
/* @var $locale Loco_Locale */
|
||||
foreach( $api->getAvailableCore() as $tag => $locale ){
|
||||
if( ! array_key_exists($tag,$installed) ){
|
||||
$locales[$tag] = new Loco_mvc_ViewParams( array(
|
||||
'value' => $tag,
|
||||
'icon' => $locale->getIcon(),
|
||||
'label' => $locale->ensureName($api),
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
// two locale lists built for "installed" and "available" dropdowns
|
||||
$this->set( 'locales', $locales );
|
||||
$this->set( 'installed', $installed );
|
||||
|
||||
// Critical that user selects the correct save location:
|
||||
if( $project ){
|
||||
$filechoice = $project->initLocaleFiles( $locale );
|
||||
}
|
||||
// without configured project we will only allow save to same location
|
||||
else {
|
||||
$filechoice = new Loco_fs_FileList;
|
||||
}
|
||||
|
||||
|
||||
// show information about POT file if we are initializing from template
|
||||
if( $potfile && $potfile->exists() ){
|
||||
$meta = Loco_gettext_Metadata::load($potfile);
|
||||
$total = $meta->getTotal();
|
||||
$summary = sprintf( _n('One string found in %2$s','%s strings found in %s',$total,'loco-translate'), number_format($total), $potfile->basename() );
|
||||
$this->set( 'pot', new Loco_mvc_ViewParams( array(
|
||||
'name' => $potfile->basename(),
|
||||
'path' => $meta->getPath(false),
|
||||
) ) );
|
||||
// if copying an existing PO file, we can fairly safely establish the correct prefixing
|
||||
if( $copying ){
|
||||
$poname = ( $prefix = $potfile->getPrefix() ) ? sprintf('%s-%s.po',$prefix,$locale) : sprintf('%s.po',$locale);
|
||||
$pofile = new Loco_fs_LocaleFile( $poname );
|
||||
$pofile->normalize( $potfile->dirname() );
|
||||
$filechoice->add( $pofile );
|
||||
}
|
||||
/// else if POT is in a folder we don't know about, we may as well add to the choices
|
||||
// TODO this means another utility function in project for prefixing rules on individual location
|
||||
}
|
||||
// else no template exists, so we prompt to extract from source
|
||||
else {
|
||||
$this->set( 'ext', new Loco_mvc_ViewParams( array(
|
||||
'link' => Loco_mvc_AdminRouter::generate( $this->get('type').'-xgettext', $_GET ),
|
||||
'text' => __('Create template','loco-translate'),
|
||||
) ) );
|
||||
// if forcing source extraction show brief description of source files
|
||||
if( $this->get('extract') ){
|
||||
// Tokenizer required for string extraction
|
||||
if( ! loco_check_extension('tokenizer') ){
|
||||
return $this->view('admin/errors/no-tokenizer');
|
||||
}
|
||||
$nfiles = count( $project->findSourceFiles() );
|
||||
$summary = sprintf( _n('1 source file will be scanned for translatable strings','%s source files will be scanned for translatable strings',$nfiles,'loco-translate'), number_format_i18n($nfiles) );
|
||||
}
|
||||
// else prompt for template creation before continuing
|
||||
else {
|
||||
$this->set( 'skip', new Loco_mvc_ViewParams( array(
|
||||
'link' => Loco_mvc_AdminRouter::generate( $this->get('_route'), $_GET + array( 'extract' => '1' ) ),
|
||||
'text' => __('Skip template','loco-translate'),
|
||||
) ) );
|
||||
// POT could still be defined, it might just not exist yet
|
||||
if( $potfile ){
|
||||
$this->set('pot', Loco_mvc_FileParams::create($potfile) );
|
||||
}
|
||||
// else offer assignment of a new file
|
||||
else {
|
||||
$this->set( 'conf', new Loco_mvc_ViewParams( array(
|
||||
'link' => Loco_mvc_AdminRouter::generate( $this->get('type').'-conf', array_intersect_key($_GET,array('bundle'=>'')) ),
|
||||
'text' => __('Assign template','loco-translate'),
|
||||
) ) );
|
||||
}
|
||||
return $this->view('admin/init/init-prompt');
|
||||
}
|
||||
}
|
||||
$this->set( 'summary', $summary );
|
||||
|
||||
// group established locations into types (official, etc..)
|
||||
// there is no point checking whether any of these file exist, because we don't know what language will be chosen yet.
|
||||
$sortable = array();
|
||||
$locations = array();
|
||||
$fs_protect = Loco_data_Settings::get()->fs_protect;
|
||||
$fs_failure = null;
|
||||
/* @var Loco_fs_File $pofile */
|
||||
foreach( $filechoice as $pofile ){
|
||||
$parent = new Loco_fs_LocaleDirectory( $pofile->dirname() );
|
||||
$systype = $parent->getUpdateType();
|
||||
$typeId = $parent->getTypeId();
|
||||
if( ! isset($locations[$typeId]) ){
|
||||
$locations[$typeId] = new Loco_mvc_ViewParams( array(
|
||||
'label' => $parent->getTypeLabel( $typeId ),
|
||||
'paths' => array(),
|
||||
) );
|
||||
}
|
||||
// folder may be unwritable (requiring connect to create file) or may be denied under security settings
|
||||
try {
|
||||
$context = $parent->getWriteContext()->authorize();
|
||||
$writable = $context->writable();
|
||||
$disabled = false;
|
||||
}
|
||||
catch( Loco_error_WriteException $e ){
|
||||
$fs_failure = $e->getMessage();
|
||||
$writable = false;
|
||||
$disabled = true;
|
||||
}
|
||||
$choice = new Loco_mvc_ViewParams( array (
|
||||
'checked' => '',
|
||||
'writable' => $writable,
|
||||
'disabled' => $disabled,
|
||||
'systype' => $systype,
|
||||
'parent' => Loco_mvc_FileParams::create( $parent ),
|
||||
'hidden' => $pofile->getRelativePath($content_dir),
|
||||
'holder' => str_replace( (string) $locale, '<span><locale></span>', $pofile->basename() ),
|
||||
) );
|
||||
// may need to show system file warnings
|
||||
if( $systype && $fs_protect ){
|
||||
$choice['syswarn'] = true;
|
||||
}
|
||||
$sortable[] = $choice;
|
||||
$locations[$typeId]['paths'][] = $choice;
|
||||
}
|
||||
|
||||
// display locations in runtime preference order
|
||||
uksort( $locations, array(__CLASS__,'_onSortLocationKeys') );
|
||||
$this->set( 'locations', $locations );
|
||||
|
||||
// pre-select best (safest/writable) option
|
||||
if( $preferred = $this->sortPreferred( $sortable ) ){
|
||||
$preferred['checked'] = 'checked';
|
||||
}
|
||||
// else show total lock message. probably file mods disallowed
|
||||
else if( $fs_failure ){
|
||||
$this->set('fsLocked', $fs_failure );
|
||||
}
|
||||
|
||||
// hidden fields to pass through to Ajax endpoint
|
||||
$this->set('hidden', new Loco_mvc_HiddenFields( array(
|
||||
'action' => 'loco_json',
|
||||
'route' => 'msginit',
|
||||
'loco-nonce' => $this->setNonce('msginit')->value,
|
||||
'type' => $bundle->getType(),
|
||||
'bundle' => $bundle->getHandle(),
|
||||
'domain' => $project ? $project->getId() : '',
|
||||
'source' => $potpath,
|
||||
) ) );
|
||||
|
||||
$this->set('help', new Loco_mvc_ViewParams( array(
|
||||
'href' => apply_filters('loco_external','https://localise.biz/wordpress/plugin/manual/msginit'),
|
||||
'text' => __("What's this?",'loco-translate'),
|
||||
) ) );
|
||||
|
||||
// file system prompts will be handled when paths are selected (i.e. we don't have one yet)
|
||||
$this->prepareFsConnect( 'create', '' );
|
||||
|
||||
$this->enqueueScript('poinit');
|
||||
return $this->view( 'admin/init/init-po', array() );
|
||||
}
|
||||
|
||||
|
||||
}
|
151
vendor/loco-translate/src/admin/init/InitPotController.php
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
/**
|
||||
* pre-xgettext function. Initializes a new PO file for a given locale
|
||||
*/
|
||||
class Loco_admin_init_InitPotController extends Loco_admin_bundle_BaseController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('poinit');
|
||||
//
|
||||
$bundle = $this->getBundle();
|
||||
$this->set('title', __('New template','loco-translate').' ‹ '.$bundle );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-init-pot'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$breadcrumb = $this->prepareNavigation();
|
||||
// "new" tab is confusing when no project-scope navigation
|
||||
// $this->get('tabs')->add( __('New POT','loco-translate'), '', true );
|
||||
|
||||
$bundle = $this->getBundle();
|
||||
$project = $this->getProject();
|
||||
|
||||
$slug = $project->getSlug();
|
||||
$domain = (string) $project->getDomain();
|
||||
$this->set('domain', $domain );
|
||||
|
||||
// Tokenizer required for string extraction
|
||||
if( ! loco_check_extension('tokenizer') ){
|
||||
return $this->view('admin/errors/no-tokenizer');
|
||||
}
|
||||
|
||||
// Establish default POT path whether it exists or not
|
||||
$pot = $project->getPot();
|
||||
while( ! $pot ){
|
||||
$name = ( $slug ? $slug : $domain ).'.pot';
|
||||
/* @var $dir Loco_fs_Directory */
|
||||
foreach( $project->getConfiguredTargets() as $dir ){
|
||||
$pot = new Loco_fs_File( $dir->getPath().'/'.$name );
|
||||
break 2;
|
||||
}
|
||||
// unlikely to have no configured targets, but possible ... so default to standard
|
||||
$pot = new Loco_fs_File( $bundle->getDirectoryPath().'/languages/'.$name );
|
||||
break;
|
||||
}
|
||||
|
||||
// POT should actually not exist at this stage. It should be edited instead.
|
||||
if( $pot->exists() ){
|
||||
throw new Loco_error_Exception( __('Template file already exists','loco-translate') );
|
||||
}
|
||||
|
||||
// Bundle may deliberately lock template to avoid end-user tampering
|
||||
// it makes little sense to do so when template doesn't exist, but we will honour the setting anyway.
|
||||
if( $project->isPotLocked() ){
|
||||
throw new Loco_error_Exception('Template is protected from updates by the bundle configuration');
|
||||
}
|
||||
|
||||
// Just warn if POT writing will fail when saved, but still show screen
|
||||
$dir = $pot->getParent();
|
||||
|
||||
// Avoiding full source scan until actioned, but calculate size to manage expectations
|
||||
$bytes = 0;
|
||||
$nfiles = 0;
|
||||
$nskip = 0;
|
||||
$largest = 0;
|
||||
$sources = $project->findSourceFiles();
|
||||
// skip files larger than configured maximum
|
||||
$opts = Loco_data_Settings::get();
|
||||
$max = wp_convert_hr_to_bytes( $opts->max_php_size );
|
||||
/* @var $sourceFile Loco_fs_File */
|
||||
foreach( $sources as $sourceFile ){
|
||||
$nfiles++;
|
||||
$fsize = $sourceFile->size();
|
||||
$largest = max( $largest, $fsize );
|
||||
if( $fsize > $max ){
|
||||
$nskip += 1;
|
||||
// uncomment to log which files are too large to be scanned
|
||||
// Loco_error_AdminNotices::debug( sprintf('%s is %s',$sourceFile,Loco_mvc_FileParams::renderBytes($fsize)) );
|
||||
}
|
||||
else {
|
||||
$bytes += $fsize;
|
||||
}
|
||||
}
|
||||
$this->set( 'scan', new Loco_mvc_ViewParams( array (
|
||||
'bytes' => $bytes,
|
||||
'count' => $nfiles,
|
||||
'skip' => $nskip,
|
||||
'size' => Loco_mvc_FileParams::renderBytes($bytes),
|
||||
'large' => Loco_mvc_FileParams::renderBytes($max),
|
||||
'largest' => Loco_mvc_FileParams::renderBytes($largest),
|
||||
) ) );
|
||||
|
||||
// file metadata
|
||||
$this->set('pot', Loco_mvc_FileParams::create( $pot ) );
|
||||
$this->set('dir', Loco_mvc_FileParams::create( $dir ) );
|
||||
|
||||
$title = __('New template file','loco-translate');
|
||||
$subhead = sprintf( __('New translations template for "%s"','loco-translate'), $project );
|
||||
$this->set('subhead', $subhead );
|
||||
|
||||
// navigate up to bundle listing page
|
||||
$breadcrumb->add( $title );
|
||||
$this->set( 'breadcrumb', $breadcrumb );
|
||||
|
||||
// ajax service takes the target directory path
|
||||
$content_dir = loco_constant('WP_CONTENT_DIR');
|
||||
$target_path = $pot->getParent()->getRelativePath($content_dir);
|
||||
|
||||
// hidden fields to pass through to Ajax endpoint
|
||||
$this->set( 'hidden', new Loco_mvc_ViewParams( array(
|
||||
'action' => 'loco_json',
|
||||
'route' => 'xgettext',
|
||||
'loco-nonce' => $this->setNonce('xgettext')->value,
|
||||
'type' => $bundle->getType(),
|
||||
'bundle' => $bundle->getHandle(),
|
||||
'domain' => $project->getId(),
|
||||
'path' => $target_path,
|
||||
'name' => $pot->basename(),
|
||||
) ) );
|
||||
|
||||
// File system connect required if location not writable
|
||||
$relpath = $pot->getRelativePath($content_dir);
|
||||
$this->prepareFsConnect('create', $relpath );
|
||||
|
||||
$this->enqueueScript('potinit');
|
||||
return $this->view( 'admin/init/init-pot' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
86
vendor/loco-translate/src/admin/list/BaseController.php
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* Common controller for listing of all bundle types
|
||||
*/
|
||||
abstract class Loco_admin_list_BaseController extends Loco_mvc_AdminController {
|
||||
|
||||
private $bundles = array();
|
||||
|
||||
|
||||
/**
|
||||
* build renderable bundle variables
|
||||
* @return Loco_mvc_ViewParams
|
||||
*/
|
||||
protected function bundleParam( Loco_package_Bundle $bundle ){
|
||||
$handle = $bundle->getHandle();
|
||||
// compatibility will be 'ok', 'warn' or 'error' depending on severity
|
||||
if( $default = $bundle->getDefaultProject() ){
|
||||
$compat = $default->getPot() instanceof Loco_fs_File;
|
||||
}
|
||||
else {
|
||||
$compat = false;
|
||||
}
|
||||
//$info = $bundle->getHeaderInfo();
|
||||
return new Loco_mvc_ViewParams( array (
|
||||
'id' => $bundle->getId(),
|
||||
'name' => $bundle->getName(),
|
||||
'dflt' => $default ? $default->getDomain() : '--',
|
||||
'size' => count( $bundle ),
|
||||
'save' => $bundle->isConfigured(),
|
||||
'type' => $type = strtolower( $bundle->getType() ),
|
||||
'view' => Loco_mvc_AdminRouter::generate( $type.'-view', array( 'bundle' => $handle ) ),
|
||||
'time' => $bundle->getLastUpdated(),
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add bundle to enabled or disabled list, depending on whether it is configured
|
||||
*/
|
||||
protected function addBundle( Loco_package_Bundle $bundle ){
|
||||
$this->bundles[] = $this->bundleParam($bundle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-list-bundles'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
// breadcrumb is just the root
|
||||
$here = new Loco_admin_Navigation( array (
|
||||
new Loco_mvc_ViewParams( array( 'name' => $this->get('title') ) ),
|
||||
) );
|
||||
|
||||
/*/ tab between the types of bundles
|
||||
$types = array (
|
||||
'' => __('Home','loco-translate'),
|
||||
'theme' => __('Themes','loco-translate'),
|
||||
'plugin' => __('Plugins','loco-translate'),
|
||||
);
|
||||
$current = $this->get('_route');
|
||||
$tabs = new Loco_admin_Navigation;
|
||||
foreach( $types as $type => $name ){
|
||||
$href = Loco_mvc_AdminRouter::generate($type);
|
||||
$tabs->add( $name, $href, $type === $current );
|
||||
}
|
||||
*/
|
||||
|
||||
return $this->view( 'admin/list/bundles', array (
|
||||
'bundles' => $this->bundles,
|
||||
'breadcrumb' => $here,
|
||||
) );
|
||||
}
|
||||
|
||||
|
||||
}
|
16
vendor/loco-translate/src/admin/list/CoreController.php
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* Dummy controller skips "core" list view, rendering the core projects directly as a single bundle.
|
||||
* Route: loco-core -> loco-core-view
|
||||
*/
|
||||
class Loco_admin_list_CoreController extends Loco_admin_RedirectController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLocation(){
|
||||
return Loco_mvc_AdminRouter::generate('core-view');
|
||||
}
|
||||
|
||||
}
|
109
vendor/loco-translate/src/admin/list/LocalesController.php
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
/**
|
||||
* Lists all installed locales.
|
||||
* WordPress decides what is "installed" based on presence of core translation files
|
||||
*/
|
||||
class Loco_admin_list_LocalesController extends Loco_mvc_AdminController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(){
|
||||
parent::init();
|
||||
$this->enqueueStyle('locale');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelpTabs(){
|
||||
return array (
|
||||
__('Overview','default') => $this->viewSnippet('tab-list-locales'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$this->set( 'title', __( 'Installed languages', 'loco-translate' ) );
|
||||
|
||||
$used = array();
|
||||
$locales = array();
|
||||
$api = new Loco_api_WordPressTranslations;
|
||||
|
||||
$active = get_locale();
|
||||
|
||||
// list which sites have each language as their WPLANG setting
|
||||
if( $multisite = is_multisite() ){
|
||||
$this->set('multisite',true);
|
||||
/* @var WP_Site $site */
|
||||
foreach( get_sites() as $site ){
|
||||
$id = (int) $site->blog_id;
|
||||
$tag = get_blog_option( $id, 'WPLANG') or $tag = 'en_US';
|
||||
$name = get_blog_option( $id, 'blogname' );
|
||||
$used[$tag][] = $name;
|
||||
}
|
||||
}
|
||||
// else single site shows tick instead of site name
|
||||
else {
|
||||
$used[$active][] = '✓';
|
||||
}
|
||||
|
||||
// add installed languages to file crawler
|
||||
$finder = new Loco_package_Locale;
|
||||
|
||||
// Pull "installed" languages (including en_US)
|
||||
foreach( $api->getInstalledCore() as $tag ){
|
||||
$locale = Loco_Locale::parse($tag);
|
||||
if( $locale->isValid() ){
|
||||
$tag = (string) $locale;
|
||||
$finder->addLocale($locale);
|
||||
$args = array( 'locale' => $tag );
|
||||
$locales[$tag] = new Loco_mvc_ViewParams( array(
|
||||
'nfiles' => 0,
|
||||
'time' => 0,
|
||||
'lcode' => $tag,
|
||||
'lname' => $locale->ensureName($api),
|
||||
'lattr' => 'class="'.$locale->getIcon().'" lang="'.$locale->lang.'"',
|
||||
'href' => Loco_mvc_AdminRouter::generate('lang-view',$args),
|
||||
'used' => isset($used[$tag]) ? implode( ', ', $used[$tag] ) : ( $multisite ? '--' : '' ),
|
||||
'active' => $active === $tag,
|
||||
) );
|
||||
}
|
||||
}
|
||||
$this->set('locales', $locales );
|
||||
|
||||
|
||||
// Count up unique PO files
|
||||
foreach( $finder->findLocaleFiles() as $file ){
|
||||
if( preg_match('/(?:^|-)([_a-zA-Z]+).po$/', $file->basename(), $r ) ){
|
||||
$locale = Loco_Locale::parse($r[1]);
|
||||
if( $locale->isValid() ){
|
||||
$tag = (string) $locale;
|
||||
$locales[$tag]['nfiles']++;
|
||||
$locales[$tag]['time'] = max( $locales[$tag]['time'], $file->modified() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// POT files are in en_US locale
|
||||
$tag = 'en_US';
|
||||
foreach( $finder->findTemplateFiles() as $file ){
|
||||
$locales[$tag]['nfiles']++;
|
||||
$locales[$tag]['time'] = max( $locales[$tag]['time'], $file->modified() );
|
||||
}
|
||||
|
||||
|
||||
return $this->view( 'admin/list/locales' );
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
31
vendor/loco-translate/src/admin/list/PluginsController.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* List all bundles of type "plugin"
|
||||
* Route: loco-plugin
|
||||
*/
|
||||
class Loco_admin_list_PluginsController extends Loco_admin_list_BaseController {
|
||||
|
||||
|
||||
public function render(){
|
||||
|
||||
$this->set( 'type', 'plugin' );
|
||||
$this->set( 'title', __( 'Translate plugins', 'loco-translate' ) );
|
||||
|
||||
foreach( Loco_package_Plugin::get_plugins() as $handle => $data ){
|
||||
try {
|
||||
$bundle = Loco_package_Plugin::create( $handle );
|
||||
$this->addBundle($bundle);
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
catch( Exception $e ){
|
||||
$bundle = new Loco_package_Plugin( $handle, $handle );
|
||||
$this->addBundle( $bundle );
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
|
||||
}
|
26
vendor/loco-translate/src/admin/list/ThemesController.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* List all bundles of type "theme"
|
||||
* Route: loco-theme
|
||||
*/
|
||||
class Loco_admin_list_ThemesController extends Loco_admin_list_BaseController {
|
||||
|
||||
|
||||
|
||||
|
||||
public function render(){
|
||||
|
||||
$this->set('type', 'theme' );
|
||||
$this->set('title', __( 'Translate themes', 'loco-translate' ) );
|
||||
|
||||
/* @var $theme WP_Theme */
|
||||
foreach( wp_get_themes() as $theme ){
|
||||
$bundle = Loco_package_Theme::create( $theme->get_stylesheet() );
|
||||
$this->addBundle( $bundle );
|
||||
}
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
|
||||
}
|
67
vendor/loco-translate/src/ajax/ApisController.php
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Ajax "apis" route, for handing off Ajax requests to hooked API integrations.
|
||||
*/
|
||||
class Loco_ajax_ApisController extends Loco_mvc_AjaxController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
$post = $this->validate();
|
||||
|
||||
// Fire an event so translation apis can register their hooks as lazily as possible
|
||||
do_action('loco_api_ajax');
|
||||
|
||||
// API client id should be posted
|
||||
$hook = (string) $post->hook;
|
||||
|
||||
// API client must be hooked in using loco_api_providers filter
|
||||
// this normally filters on Loco_api_Providers::export() but should do the same with an empty array.
|
||||
$config = null;
|
||||
foreach( apply_filters('loco_api_providers', array() ) as $candidate ){
|
||||
if( is_array($candidate) && array_key_exists('id',$candidate) && $candidate['id'] === $hook ){
|
||||
$config = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( is_null($config) ){
|
||||
throw new Loco_error_Exception('API not registered: '.$hook );
|
||||
}
|
||||
|
||||
// Get input texts to translate via registered hook. shouldn't be posted if empty.
|
||||
$sources = $post->sources;
|
||||
if( ! is_array($sources) || ! $sources ){
|
||||
throw new Loco_error_Exception('Empty sources posted to '.$hook.' hook');
|
||||
}
|
||||
|
||||
// The front end sends translations detected as HTML separately. This is to support common external apis.
|
||||
// $isHtml = 'html' === $post->type;
|
||||
|
||||
// We need a locale too, which should be valid as it's the same one loaded into the front end.
|
||||
$locale = Loco_Locale::parse( (string) $post->locale );
|
||||
if( ! $locale->isValid() ){
|
||||
throw new Loco_error_Exception('Invalid locale');
|
||||
}
|
||||
|
||||
// Check if hook is registered, else sources will be returned as-is
|
||||
$action = 'loco_api_translate_'.$hook;
|
||||
if( ! has_filter($action) ){
|
||||
throw new Loco_error_Exception('API not hooked. Use `add_filter('.var_export($action,1).',...)`');
|
||||
}
|
||||
|
||||
// This is effectively a filter whereby the returned array should be a translation of the input array
|
||||
// TODO might be useful for translation hooks to know the PO file this comes from
|
||||
$targets = apply_filters( $action, $sources, $locale, $config );
|
||||
if( count($targets) !== count($sources) ){
|
||||
Loco_error_AdminNotices::warn('Number of translations does not match number of source strings');
|
||||
}
|
||||
|
||||
// Response data doesn't need anything except the translations
|
||||
$this->set('targets',$targets);
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
|
||||
}
|
58
vendor/loco-translate/src/ajax/DiffController.php
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* Ajax "diff" route, for rendering PO/POT file diffs
|
||||
*/
|
||||
class Loco_ajax_DiffController extends Loco_mvc_AjaxController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
$post = $this->validate();
|
||||
|
||||
// require x2 valid files for diffing
|
||||
if( ! $post->lhs || ! $post->rhs ){
|
||||
throw new InvalidArgumentException('Path parameters required');
|
||||
}
|
||||
|
||||
$dir = loco_constant('WP_CONTENT_DIR');
|
||||
$lhs = new Loco_fs_File( $post->lhs ); $lhs->normalize($dir);
|
||||
$rhs = new Loco_fs_File( $post->rhs ); $rhs->normalize($dir);
|
||||
|
||||
// avoid diffing non Gettext source files
|
||||
$exts = array_flip( array( 'pot', 'pot~', 'po', 'po~' ) );
|
||||
|
||||
/* @var $file Loco_fs_File */
|
||||
foreach( array($lhs,$rhs) as $file ){
|
||||
if( ! $file->exists() ){
|
||||
throw new InvalidArgumentException('File paths must exist');
|
||||
}
|
||||
if( ! $file->underContentDirectory() ){
|
||||
throw new InvalidArgumentException('Files must be under '.basename($dir) );
|
||||
}
|
||||
$ext = $file->extension();
|
||||
if( ! isset($exts[$ext]) ){
|
||||
throw new InvalidArgumentException('Disallowed file extension');
|
||||
}
|
||||
}
|
||||
|
||||
// OK to diff files as HTML table
|
||||
$renderer = new Loco_output_DiffRenderer;
|
||||
$emptysrc = $renderer->_startDiff().$renderer->_endDiff();
|
||||
$tablesrc = $renderer->renderFiles( $rhs, $lhs );
|
||||
|
||||
if( $tablesrc === $emptysrc ){
|
||||
// translators: Where %s is a file name
|
||||
$message = __('Revisions are identical, you can delete %s','loco-translate');
|
||||
$this->set( 'error', sprintf( $message, $rhs->basename() ) );
|
||||
}
|
||||
else {
|
||||
$this->set( 'html', $tablesrc );
|
||||
}
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
|
||||
}
|
35
vendor/loco-translate/src/ajax/DownloadConfController.php
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/**
|
||||
* Downloads a bundle configuration as XML or Json
|
||||
*/
|
||||
class Loco_ajax_DownloadConfController extends Loco_ajax_common_BundleController {
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$this->validate();
|
||||
$bundle = $this->getBundle();
|
||||
|
||||
$file = new Loco_fs_File( $this->get('path') );
|
||||
// TODO should we download axtual loco.xml file if bundle is configured from it?
|
||||
//$file->normalize( $bundle->getDirectoryPath() );
|
||||
//if( $file->exists() ){}
|
||||
|
||||
$writer = new Loco_config_BundleWriter($bundle);
|
||||
|
||||
switch( $file->extension() ){
|
||||
case 'xml':
|
||||
return $writer->toXml();
|
||||
case 'json':
|
||||
return json_encode( $writer->jsonSerialize() );
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new Loco_error_Exception('Specify either XML or JSON file path');
|
||||
}
|
||||
|
||||
|
||||
}
|
59
vendor/loco-translate/src/ajax/DownloadController.php
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* Ajax "download" route, for outputting raw gettext file contents.
|
||||
*/
|
||||
class Loco_ajax_DownloadController extends Loco_mvc_AjaxController {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
|
||||
$post = $this->validate();
|
||||
|
||||
// we need a path, but it may not need to exist
|
||||
$file = new Loco_fs_File( $this->get('path') );
|
||||
$file->normalize( loco_constant( 'WP_CONTENT_DIR') );
|
||||
$is_binary = 'mo' === strtolower( $file->extension() );
|
||||
|
||||
// posted source must be clean and must parse as whatever the file extension claims to be
|
||||
if( $raw = $post->source ){
|
||||
// compile source if target is MO
|
||||
if( $is_binary ) {
|
||||
$raw = Loco_gettext_Data::fromSource($raw)->msgfmt();
|
||||
}
|
||||
}
|
||||
// else file can be output directly if it exists.
|
||||
// note that files on disk will not be parsed or manipulated. they will download strictly as-is
|
||||
else if( $file->exists() ){
|
||||
$raw = $file->getContents();
|
||||
}
|
||||
/*/ else if PO exists but MO doesn't, we can compile it on the fly
|
||||
else if( ! $is_binary ){
|
||||
|
||||
}*/
|
||||
else {
|
||||
throw new Loco_error_Exception('File not found and no source posted');
|
||||
}
|
||||
|
||||
// Observe UTF-8 BOM setting
|
||||
if( ! $is_binary ){
|
||||
$has_bom = "\xEF\xBB\xBF" === substr($raw,0,3);
|
||||
$use_bom = (bool) Loco_data_Settings::get()->po_utf8_bom;
|
||||
// only alter file if valid UTF-8. Deferring detection overhead until required
|
||||
if( $has_bom !== $use_bom && 'UTF-8' === mb_detect_encoding( $raw, array('UTF-8','ISO-8859-1'), true ) ){
|
||||
if( $use_bom ){
|
||||
$raw = "\xEF\xBB\xBF".$raw; // prepend
|
||||
}
|
||||
else {
|
||||
$raw = substr($raw,3); // strip bom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $raw;
|
||||
}
|
||||
|
||||
|
||||
}
|
151
vendor/loco-translate/src/ajax/FsConnectController.php
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
/**
|
||||
* Ajax service that provides remote server authentication for file system *write* operations
|
||||
*/
|
||||
class Loco_ajax_FsConnectController extends Loco_mvc_AjaxController {
|
||||
|
||||
/**
|
||||
* @var Loco_api_WordPressFileSystem
|
||||
*/
|
||||
private $api;
|
||||
|
||||
|
||||
/**
|
||||
* @param Loco_fs_File existing file path (must exist)
|
||||
* @return bool
|
||||
*/
|
||||
private function authorizeDelete( Loco_fs_File $file ){
|
||||
$files = new Loco_fs_Siblings($file);
|
||||
// require remote authentication if at least one dependant file is not deletable directly
|
||||
foreach( $files->expand() as $file ){
|
||||
if( ! $this->api->authorizeDelete($file) ){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// else no dependants failed deletable test
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Loco_fs_File file being moved (must exist)
|
||||
* @param Loco_fs_File target path (should not exist)
|
||||
* @return bool
|
||||
*/
|
||||
private function authorizeMove( Loco_fs_File $source, Loco_fs_File $target = null ){
|
||||
return $this->api->authorizeMove($source,$target);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Loco_fs_File new file path (should not exist)
|
||||
* @return bool
|
||||
*/
|
||||
private function authorizeCreate( Loco_fs_File $file ){
|
||||
return $this->api->authorizeCreate($file);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function authorizeUpdate( Loco_fs_File $file ){
|
||||
if( ! $this->api->authorizeUpdate($file) ){
|
||||
return false;
|
||||
}
|
||||
// if backups are enabled, we need to be able to create new files too (i.e. update parent directory)
|
||||
if( Loco_data_Settings::get()->num_backups && ! $this->api->authorizeCopy($file) ){
|
||||
return false;
|
||||
}
|
||||
// updating file may also recompile binary, which may or may not exist
|
||||
$files = new Loco_fs_Siblings( $file );
|
||||
if( $file = $files->getBinary() ){
|
||||
return $this->api->authorizeSave($file);
|
||||
}
|
||||
// else no dependants to update
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
// establish operation being authorized (create,delete,etc..)
|
||||
$post = $this->validate();
|
||||
$type = $post->auth;
|
||||
$func = 'authorize'.ucfirst($type);
|
||||
$auth = array( $this, $func );
|
||||
if( ! is_callable($auth) ){
|
||||
throw new Loco_error_Exception('Unexpected file operation');
|
||||
}
|
||||
// all auth methods require at least one file argument
|
||||
$file = new Loco_fs_File( $post->path );
|
||||
$base = loco_constant('WP_CONTENT_DIR');
|
||||
$file->normalize($base);
|
||||
$args = array($file);
|
||||
// some auth methods also require a destination/target (move,copy,etc..)
|
||||
if( $dest = $post->dest ){
|
||||
$file = new Loco_fs_File($dest);
|
||||
$file->normalize($base);
|
||||
$args[] = $file;
|
||||
}
|
||||
// call auth method and respond with status and prompt HTML if connect required
|
||||
try {
|
||||
$this->api = new Loco_api_WordPressFileSystem;
|
||||
if( call_user_func_array($auth,$args) ){
|
||||
$this->set( 'authed', true );
|
||||
$this->set( 'valid', $this->api->getOutputCredentials() );
|
||||
$this->set( 'creds', $this->api->getInputCredentials() );
|
||||
$this->set( 'method', $this->api->getFileSystem()->method );
|
||||
$this->set( 'success', __('Connected to remote file system','loco-translate') );
|
||||
// warning when writing to this location is risky (overwrites during wp update)
|
||||
if( Loco_data_Settings::get()->fs_protect && $file->getUpdateType() ){
|
||||
if( 'create' === $type ){
|
||||
$message = __('This file may be overwritten or deleted when you update WordPress','loco-translate');
|
||||
}
|
||||
else if( 'delete' === $type ){
|
||||
$message = __('This directory is managed by WordPress, be careful what you delete','loco-translate');
|
||||
}
|
||||
else if( 'move' === $type ){
|
||||
$message = __('This directory is managed by WordPress. Removed files may be restored during updates','loco-translate');
|
||||
}
|
||||
else {
|
||||
$message = __('Changes to this file may be overwritten or deleted when you update WordPress','loco-translate');
|
||||
}
|
||||
$this->set('warning',$message);
|
||||
}
|
||||
}
|
||||
else if( $html = $this->api->getForm() ){
|
||||
$this->set( 'authed', false );
|
||||
$this->set( 'prompt', $html );
|
||||
// supporting text based on file operation type explains why auth is required
|
||||
if( 'create' === $type ){
|
||||
$message = __('Creating this file requires permission','loco-translate');
|
||||
}
|
||||
else if( 'delete' === $type ){
|
||||
$message = __('Deleting this file requires permission','loco-translate');
|
||||
}
|
||||
else if( 'move' === $type ){
|
||||
$message = __('This move operation requires permission','loco-translate');
|
||||
}
|
||||
else {
|
||||
$message = __('Saving this file requires permission','loco-translate');
|
||||
}
|
||||
// message is printed before default text, so needs delimiting.
|
||||
$this->set('message',$message.'.');
|
||||
}
|
||||
else {
|
||||
throw new Loco_error_Exception('Failed to get credentials form');
|
||||
}
|
||||
}
|
||||
catch( Loco_error_WriteException $e ){
|
||||
$this->set('authed', false );
|
||||
$this->set('reason', $e->getMessage() );
|
||||
}
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
|
||||
}
|
198
vendor/loco-translate/src/ajax/FsReferenceController.php
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
/**
|
||||
* Ajax service that returns source code for a given file system reference
|
||||
* Currently this is only PHP, but could theoretically be any file type.
|
||||
*/
|
||||
class Loco_ajax_FsReferenceController extends Loco_ajax_common_BundleController {
|
||||
|
||||
|
||||
/**
|
||||
* @param string
|
||||
* @return Loco_fs_File
|
||||
*/
|
||||
private function findSourceFile( $refpath ){
|
||||
|
||||
/*/ absolute file path means no search paths required
|
||||
if( Loco_fs_File::abs($refpath) ){
|
||||
$srcfile = new Loco_fs_File( $refpath );
|
||||
if( $srcfile->exists() ){
|
||||
return $srcfile;
|
||||
}
|
||||
}*/
|
||||
|
||||
// reference may be resolvable via referencing PO file's location
|
||||
$pofile = new Loco_fs_File( $this->get('path') );
|
||||
$pofile->normalize( loco_constant('WP_CONTENT_DIR') );
|
||||
if( ! $pofile->exists() ){
|
||||
throw new InvalidArgumentException('PO/POT file required to resolve reference');
|
||||
}
|
||||
$search = new Loco_gettext_SearchPaths;
|
||||
$search->init($pofile);
|
||||
if( $srcfile = $search->match($refpath) ){
|
||||
return $srcfile;
|
||||
}
|
||||
|
||||
// check against PO file location when no search paths or search paths failed
|
||||
$srcfile = new Loco_fs_File($refpath);
|
||||
$srcfile->normalize( $pofile->dirname() );
|
||||
if( $srcfile->exists() ){
|
||||
return $srcfile;
|
||||
}
|
||||
|
||||
// reference may be resolvable via known project roots
|
||||
try {
|
||||
$bundle = $this->getBundle();
|
||||
// Loco extractions will always be relative to bundle root
|
||||
$srcfile = new Loco_fs_File( $refpath );
|
||||
$srcfile->normalize( $bundle->getDirectoryPath() );
|
||||
if( $srcfile->exists() ){
|
||||
return $srcfile;
|
||||
}
|
||||
|
||||
// check relative to parent theme root
|
||||
if( $bundle->isTheme() && ( $parent = $bundle->getParent() ) ){
|
||||
$srcfile = new Loco_fs_File( $refpath );
|
||||
$srcfile->normalize( $parent->getDirectoryPath() );
|
||||
if( $srcfile->exists() ){
|
||||
return $srcfile;
|
||||
}
|
||||
}
|
||||
|
||||
// final attempt - search all project source roots
|
||||
// TODO is there too large a risk of false positives? especially with files like index.php
|
||||
/* @var $root Loco_fs_Directory */
|
||||
/*foreach( $this->getProject($bundle)->getConfiguredSources() as $root ){
|
||||
if( $root->isDirectory() ){
|
||||
$srcfile = new Loco_fs_File( $refpath );
|
||||
$srcfile->normalize( $root->getPath() );
|
||||
if( $srcfile->exists() ){
|
||||
return $srcfile;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
catch( Loco_error_Exception $e ){
|
||||
// permitted for there to be no bundle or project when viewing orphaned file
|
||||
}
|
||||
|
||||
throw new Loco_error_Exception( sprintf('Failed to find source file matching "%s"',$refpath) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(){
|
||||
$post = $this->validate();
|
||||
|
||||
// at the very least we need a reference to examine
|
||||
if( ! $post->has('ref') ){
|
||||
throw new InvalidArgumentException('ref parameter required');
|
||||
}
|
||||
|
||||
// reference must parse as <path>:<line>
|
||||
$ref = $post->ref;
|
||||
if( ! preg_match('/^(.+):(\\d+)$/', $ref, $r ) ){
|
||||
throw new InvalidArgumentException('Invalid file reference, '.$ref );
|
||||
}
|
||||
|
||||
// find file or fail
|
||||
list( , $refpath, $refline ) = $r;
|
||||
$srcfile = $this->findSourceFile($refpath);
|
||||
|
||||
// deny access to sensitive files
|
||||
if( 'wp-config.php' === $srcfile->basename() ){
|
||||
throw new InvalidArgumentException('File access disallowed');
|
||||
}
|
||||
|
||||
// validate allowed source file types
|
||||
$conf = Loco_data_Settings::get();
|
||||
$ext = strtolower( $srcfile->extension() );
|
||||
$allow = array_merge( array('php','js'), $conf->php_alias, $conf->jsx_alias );
|
||||
if( ! in_array($ext,$allow,true) ){
|
||||
throw new InvalidArgumentException('File extension disallowed, '.$ext );
|
||||
}
|
||||
|
||||
// get file type from registered file extensions:
|
||||
$type = $conf->ext2type( $ext );
|
||||
|
||||
$this->set('type', $type );
|
||||
$this->set('line', (int) $refline );
|
||||
$this->set('path', $srcfile->getRelativePath( loco_constant('WP_CONTENT_DIR') ) );
|
||||
|
||||
// source code will be HTML-tokenized into multiple lines
|
||||
$code = array();
|
||||
|
||||
// observe the same size limits for source highlighting as for string extraction as tokenizing will use the same amount of juice
|
||||
$maxbytes = wp_convert_hr_to_bytes( $conf->max_php_size );
|
||||
|
||||
// tokenizers require gettext utilities, easiest just to ping the extraction library
|
||||
if( ! class_exists('Loco_gettext_Extraction',true) ){
|
||||
throw new RuntimeException('Failed to load tokenizers'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// PHP is the most likely format.
|
||||
if( 'php' === $type && ( $srcfile->size() <= $maxbytes ) && loco_check_extension('tokenizer') ) {
|
||||
$tokens = new LocoPHPTokens( token_get_all( $srcfile->getContents() ) );
|
||||
}
|
||||
else if( 'js' === $type ){
|
||||
$tokens = new LocoJsTokens( $srcfile->getContents() );
|
||||
}
|
||||
else {
|
||||
$tokens = null;
|
||||
}
|
||||
|
||||
// highlighting on back end because tokenizer provides more control than highlight.js
|
||||
if( $tokens instanceof LocoTokensInterface ){
|
||||
$thisline = 1;
|
||||
while( $tok = $tokens->advance() ){
|
||||
if( is_array($tok) ){
|
||||
// line numbers added in PHP 5.2.2 - WordPress minimum is 5.2.4
|
||||
list( $t, $str, $startline ) = $tok;
|
||||
$clss = token_name($t);
|
||||
// tokens can span multiple lines (whitespace/html/comments)
|
||||
$lines = preg_split('/\\R/', $str );
|
||||
}
|
||||
else {
|
||||
// scalar symbol will always start on the line that the previous token ended on
|
||||
$clss = 'T_NONE';
|
||||
$lines = array( $tok );
|
||||
$startline = $thisline;
|
||||
}
|
||||
// token can span multiple lines, so include only bytes on required line[s]
|
||||
foreach( $lines as $i => $line ){
|
||||
$thisline = $startline + $i;
|
||||
$html = '<code class="'.$clss.'">'.htmlentities($line,ENT_COMPAT,'UTF-8').'</code>';
|
||||
// append highlighted token to current line
|
||||
$j = $thisline - 1;
|
||||
if( isset($code[$j]) ){
|
||||
$code[$j] .= $html;
|
||||
}
|
||||
else {
|
||||
$code[$j] = $html;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// permit limited other file types, but without back end highlighting
|
||||
else if( 'js' === $type || 'twig' === $type || 'php' === $type ){
|
||||
foreach( preg_split( '/\\R/u', $srcfile->getContents() ) as $line ){
|
||||
$code[] = '<code>'.htmlentities($line,ENT_COMPAT,'UTF-8').'</code>';
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Loco_error_Exception( sprintf('%s source view not supported', $type) ); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if( ! isset($code[$refline-1]) ){
|
||||
throw new Loco_error_Exception( sprintf('Line %u not in source file', $refline) );
|
||||
}
|
||||
|
||||
$this->set( 'code', $code );
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
|
||||
}
|