/var/www/html_sp/wp-content/plugins/loco-translate/src/gettext/Metadata.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
<?php

loco_require_lib
('compiled/gettext.php');

/**
 * Holds metadata about a PO file, cached as Transient
 * TODO Non-PO files (MO/PHP) are sparse. We need to obtain the 100% mark from the PO sibling, and adjust completion.
 */
class Loco_gettext_Metadata extends Loco_data_Transient {

    
/**
     * Generate abbreviated stats from parsed array data  
     * @param array $po in form returned from parser, including header message
     * @return array in form ['t' => total, 'p' => progress, 'f' => fuzzy ];
     */
    
public static function stats( array $po ){
        
$t $p $f 0;
        
/* @var $r array */
        
foreach( $po as $i => $r ){
            
// skip header
            
if( === $i && empty($r['source']) && empty($r['context']) ){
                continue;
            }
            
// plural form
            // TODO how should plural forms affect stats? should all forms be complete before 100% can be achieved? should offsets add to total??
            
if( isset($r['parent']) && is_int($r['parent']) ){
                continue;
            }
            
// singular form
            
$t++;
            if( 
'' !== $r['target'] ){
                
$p++;
                if( isset(
$r['flag']) /*&& LOCO_FLAG_FUZZY === $r['flag']*/ ){
                    
$f++;
                }
            }
        }
        return 
compact('t','p','f');        
    }


    
/**
     * {@inheritdoc}
     */
    
public function getKey(){
        return 
'po_'.md5$this['rpath'] );
    }


    
/**
     * Load metadata from file, using cache if enabled.
     * Note that this does not throw exception, check "valid" key
     * @return Loco_gettext_Metadata
     */
    
public static function loadLoco_fs_File $po$nocache false ){
        
$bytes $po->size();
        
$mtime $po->modified();
        
// quick construct of a new metadata object. enough to query and validate cache
        
$meta = new Loco_gettext_Metadata( [
            
'rpath' => $po->getRelativePathloco_constant('WP_CONTENT_DIR') ),
        ] );
        
// pull from cache if exists and has not been modified
        
if( $nocache || ! $meta->fetch() || $bytes !== $meta['bytes'] || $mtime !== $meta['mtime'] ){
            
// not available from cache, or cache is invalidated
            
$meta['bytes'] = $bytes;
            
$meta['mtime'] = $mtime;
            
// parse what is hopefully a PO file to get stats
            
try {
                
$data Loco_gettext_Data::load($po)->getArrayCopy();
                
$meta['valid'] = true;
                
$meta['stats'] = self::stats($data);
            }
            catch( 
Exception $e ){
                
$meta['valid'] = false;
                
$meta['error'] = $e->getMessage();
            }
        }
        
// show cached debug notice as if file was being parsed 
        
else if( $meta->offsetExists('error') ){
            
Loco_error_AdminNotices::debug($meta['error'].': '.$meta['rpath']);
        }
        
// persist on shutdown with a useful TTL and keepalive
        // Maximum lifespan: 10 days. Refreshed if accessed a day after being cached.
        
$meta->setLifespan(864000)->keepAlive(86400)->persistLazily();
        
        return 
$meta;
    }


    
/**
     * Construct metadata from previously parsed PO data
     * @return Loco_gettext_Metadata 
     */
    
public static function createLoco_fs_File $fileLoco_gettext_Data $data ){
        return new 
Loco_gettext_Metadata(  [
            
'valid' => true,
            
'bytes' => $file->size(),
            
'mtime' => $file->modified(),
            
'stats' => self::stats$data->getArrayCopy() ),
        ] );
    }


    
/**
     * Get progress stats as simple array with keys, t=total, p=progress, f:flagged.
     * Note that untranslated strings are never flagged, hence "f" includes all in "p"  
     * @return array in form ['t' => total, 'p' => progress, 'f' => fuzzy ];
     */
    
public function getStats(){
        if( isset(
$this['stats']) ){
            return 
$this['stats'];
        }
        
// fallback to empty stats
        
return [ 't' => 0'p' => 0'f' => ];
    }


    
/**
     * Get total number of messages, not including header and excluding plural forms
     * @return int
     */
    
public function getTotal(){
        
$stats $this->getStats();
        return 
$stats['t'];
    }


    
/**
     * Get number of fuzzy messages, not including header
     * @return int
     */
    
public function countFuzzy(){
        
$stats $this->getStats();
        return 
$stats['f'];
    }


    
/**
     * Get progress as a string percentage (minus % symbol)
     * @return string
     */
    
public function getPercent(){
        
$stats $this->getStats();
        
$n max0$stats['p'] - $stats['f'] );
        
$t max$n$stats['t'] );
        return 
loco_string_percent$n$t );
    }


    
/**
     * Get number of strings either untranslated or fuzzy.
     * @return int
     */
    
public function countIncomplete(){
        
$stats $this->getStats();
        return 
max0,  $stats['t'] - ( $stats['p'] - $stats['f'] ) );
    }


    
/**
     * Get number of strings completely untranslated (excludes fuzzy).
     * @return int
     */
    
public function countUntranslated(){
        
$stats $this->getStats();
        return 
max0,  $stats['t'] - $stats['p'] );
    }


    
/**
     * Echo progress bar using compiled function
     * @return void
     */
    
public function printProgress(){
        
$stats $this->getStats();
        
$flagged $stats['f'];
        
$translated $stats['p'];
        
$untranslated $stats['t'] - $translated;
        
        
loco_print_progress$translated$untranslated$flagged );
    }


    
/**
     * Get wordy summary of total strings
     * @return string
     */
    
public function getTotalSummary(){
        
$total $this->getTotal();
        
// translators: Where %s is any number of strings
        
return sprintf_n('%s string','%s strings',$total,'loco-translate'), number_format_i18n($total) );
    }


    
/**
     * Get wordy summary including translation stats
     * @return string
     */
    
public function getProgressSummary(){
        
$extra = [];
        
// translators: Shows percentage translated at top of editor
        
$stext sprintf__('%s%% translated','loco-translate'), $this->getPercent() ).', '.$this->getTotalSummary();
        if( 
$num $this->countFuzzy() ){
            
// translators: Shows number of fuzzy strings at top of editor
            
$extra[] = sprintf__('%s fuzzy','loco-translate'), number_format($num) );
        }
        if( 
$num $this->countUntranslated() ){
            
// translators: Shows number of untranslated strings at top of editor
            
$extra[] = sprintf__('%s untranslated','loco-translate'), number_format($num) );
        }
        if( 
$extra ){
            
$stext .= ' ('.implode(', '$extra).')';
        }
        return 
$stext;
    }


    
/**
     * @param bool $absolute
     * @return string
     */
    
public function getPath$absolute ){
        
$path $this['rpath'];
        if( 
$absolute && ! Loco_fs_File::abs($path) ){
            
$path trailingslashitloco_constant('WP_CONTENT_DIR') ).$path;
        }
        return 
$path;
    }

}