Setup code for changing languages

This commit is contained in:
Andrew Collington 2022-07-17 02:43:40 +01:00
parent 57afb1982c
commit 5eff1f173e
5 changed files with 315 additions and 229 deletions

View file

@ -67,6 +67,16 @@ class Interface extends React.Component {
return v ? !!v[2] : false; return v ? !!v[2] : false;
}; };
txt = (text, ...args) => {
if (this.props.language !== null && this.props.language.hasOwnProperty(text) && this.props.language[text]) {
text = this.props.language[text];
}
args.forEach((arg, i) => {
text = text.replaceAll(`{${i}}`, arg);
});
return text;
};
render() { render() {
const { opstate, realtimeRefresh, ...otherProps } = this.props; const { opstate, realtimeRefresh, ...otherProps } = this.props;
return ( return (
@ -78,6 +88,7 @@ class Interface extends React.Component {
resetting={this.state.resetting} resetting={this.state.resetting}
realtimeHandler={this.realtimeHandler} realtimeHandler={this.realtimeHandler}
resetHandler={this.resetHandler} resetHandler={this.resetHandler}
txt={this.txt}
/> />
</header> </header>
<Footer version={this.props.opstate.version.gui} /> <Footer version={this.props.opstate.version.gui} />
@ -91,29 +102,33 @@ function MainNavigation(props) {
return ( return (
<nav className="main-nav"> <nav className="main-nav">
<Tabs> <Tabs>
<div label="Overview" tabId="overview" tabIndex={1}> <div label={props.txt("Overview")} tabId="overview" tabIndex={1}>
<OverviewCounts <OverviewCounts
overview={props.opstate.overview} overview={props.opstate.overview}
highlight={props.highlight} highlight={props.highlight}
useCharts={props.useCharts} useCharts={props.useCharts}
txt={props.txt}
/> />
<div id="info" className="tab-content-overview-info"> <div id="info" className="tab-content-overview-info">
<GeneralInfo <GeneralInfo
start={props.opstate.overview && props.opstate.overview.readable.start_time || null} start={props.opstate.overview && props.opstate.overview.readable.start_time || null}
reset={props.opstate.overview && props.opstate.overview.readable.last_restart_time || null} reset={props.opstate.overview && props.opstate.overview.readable.last_restart_time || null}
version={props.opstate.version} version={props.opstate.version}
txt={props.txt}
/> />
<Directives <Directives
directives={props.opstate.directives} directives={props.opstate.directives}
txt={props.txt}
/> />
<Functions <Functions
functions={props.opstate.functions} functions={props.opstate.functions}
txt={props.txt}
/> />
</div> </div>
</div> </div>
{ {
props.allow.filelist && props.allow.filelist &&
<div label="Cached" tabId="cached" tabIndex={2}> <div label={props.txt("Cached")} tabId="cached" tabIndex={2}>
<CachedFiles <CachedFiles
perPageLimit={props.perPageLimit} perPageLimit={props.perPageLimit}
allFiles={props.opstate.files} allFiles={props.opstate.files}
@ -121,32 +136,35 @@ function MainNavigation(props) {
debounceRate={props.debounceRate} debounceRate={props.debounceRate}
allow={{fileList: props.allow.filelist, invalidate: props.allow.invalidate}} allow={{fileList: props.allow.filelist, invalidate: props.allow.invalidate}}
realtime={props.realtime} realtime={props.realtime}
txt={props.txt}
/> />
</div> </div>
} }
{ {
(props.allow.filelist && props.opstate.blacklist.length && (props.allow.filelist && props.opstate.blacklist.length &&
<div label="Ignored" tabId="ignored" tabIndex={3}> <div label={props.txt("Ignored")} tabId="ignored" tabIndex={3}>
<IgnoredFiles <IgnoredFiles
perPageLimit={props.perPageLimit} perPageLimit={props.perPageLimit}
allFiles={props.opstate.blacklist} allFiles={props.opstate.blacklist}
allow={{fileList: props.allow.filelist }} allow={{fileList: props.allow.filelist }}
txt={props.txt}
/> />
</div>) </div>)
} }
{ {
(props.allow.filelist && props.opstate.preload.length && (props.allow.filelist && props.opstate.preload.length &&
<div label="Preloaded" tabId="preloaded" tabIndex={4}> <div label={props.txt("Preloaded")} tabId="preloaded" tabIndex={4}>
<PreloadedFiles <PreloadedFiles
perPageLimit={props.perPageLimit} perPageLimit={props.perPageLimit}
allFiles={props.opstate.preload} allFiles={props.opstate.preload}
allow={{fileList: props.allow.filelist }} allow={{fileList: props.allow.filelist }}
txt={props.txt}
/> />
</div>) </div>)
} }
{ {
props.allow.reset && props.allow.reset &&
<div label="Reset cache" tabId="resetCache" <div label={props.txt("Reset cache")} tabId="resetCache"
className={`nav-tab-link-reset${props.resetting ? ' is-resetting pulse' : ''}`} className={`nav-tab-link-reset${props.resetting ? ' is-resetting pulse' : ''}`}
handler={props.resetHandler} handler={props.resetHandler}
tabIndex={5} tabIndex={5}
@ -154,7 +172,7 @@ function MainNavigation(props) {
} }
{ {
props.allow.realtime && props.allow.realtime &&
<div label={`${props.realtime ? 'Disable' : 'Enable'} real-time update`} tabId="toggleRealtime" <div label={props.txt(`${props.realtime ? 'Disable' : 'Enable'} real-time update`)} tabId="toggleRealtime"
className={`nav-tab-link-realtime${props.realtime ? ' live-update pulse' : ''}`} className={`nav-tab-link-realtime${props.realtime ? ' live-update pulse' : ''}`}
handler={props.realtimeHandler} handler={props.realtimeHandler}
tabIndex={6} tabIndex={6}
@ -256,16 +274,16 @@ function OverviewCounts(props) {
if (props.overview === false) { if (props.overview === false) {
return ( return (
<p class="file-cache-only"> <p class="file-cache-only">
You have <i>opcache.file_cache_only</i> turned on. As a result, the memory information is not available. Statistics and file list may also not be returned by <i>opcache_get_statistics()</i>. {props.txt(`You have <i>opcache.file_cache_only</i> turned on. As a result, the memory information is not available. Statistics and file list may also not be returned by <i>opcache_get_statistics()</i>.`)}
</p> </p>
); );
} }
const graphList = [ const graphList = [
{id: 'memoryUsageCanvas', title: 'memory', show: props.highlight.memory, value: props.overview.used_memory_percentage}, {id: 'memoryUsageCanvas', title: props.txt('memory'), show: props.highlight.memory, value: props.overview.used_memory_percentage},
{id: 'hitRateCanvas', title: 'hit rate', show: props.highlight.hits, value: props.overview.hit_rate_percentage}, {id: 'hitRateCanvas', title: props.txt('hit rate'), show: props.highlight.hits, value: props.overview.hit_rate_percentage},
{id: 'keyUsageCanvas', title: 'keys', show: props.highlight.keys, value: props.overview.used_key_percentage}, {id: 'keyUsageCanvas', title: props.txt('keys'), show: props.highlight.keys, value: props.overview.used_key_percentage},
{id: 'jitUsageCanvas', title: 'jit buffer', show: props.highlight.jit, value: props.overview.jit_buffer_used_percentage} {id: 'jitUsageCanvas', title: props.txt('jit buffer'), show: props.highlight.jit, value: props.overview.jit_buffer_used_percentage}
]; ];
return ( return (
@ -291,6 +309,7 @@ function OverviewCounts(props) {
jitBuffer={props.overview.readable.jit_buffer_size || null} jitBuffer={props.overview.readable.jit_buffer_size || null}
jitBufferFree={props.overview.readable.jit_buffer_free || null} jitBufferFree={props.overview.readable.jit_buffer_free || null}
jitBufferFreePercentage={props.overview.jit_buffer_used_percentage || null} jitBufferFreePercentage={props.overview.jit_buffer_used_percentage || null}
txt={props.txt}
/> />
<StatisticsPanel <StatisticsPanel
num_cached_scripts={props.overview.readable.num_cached_scripts} num_cached_scripts={props.overview.readable.num_cached_scripts}
@ -299,6 +318,7 @@ function OverviewCounts(props) {
blacklist_miss={props.overview.readable.blacklist_miss} blacklist_miss={props.overview.readable.blacklist_miss}
num_cached_keys={props.overview.readable.num_cached_keys} num_cached_keys={props.overview.readable.num_cached_keys}
max_cached_keys={props.overview.readable.max_cached_keys} max_cached_keys={props.overview.readable.max_cached_keys}
txt={props.txt}
/> />
{props.overview.readable.interned && {props.overview.readable.interned &&
<InternedStringsPanel <InternedStringsPanel
@ -306,6 +326,7 @@ function OverviewCounts(props) {
strings_used_memory={props.overview.readable.interned.strings_used_memory} strings_used_memory={props.overview.readable.interned.strings_used_memory}
strings_free_memory={props.overview.readable.interned.strings_free_memory} strings_free_memory={props.overview.readable.interned.strings_free_memory}
number_of_strings={props.overview.readable.interned.number_of_strings} number_of_strings={props.overview.readable.interned.number_of_strings}
txt={props.txt}
/> />
} }
</div> </div>
@ -317,15 +338,15 @@ function GeneralInfo(props) {
return ( return (
<table className="tables general-info-table"> <table className="tables general-info-table">
<thead> <thead>
<tr><th colSpan="2">General info</th></tr> <tr><th colSpan="2">{props.txt('General info')}</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td>Zend OPcache</td><td>{props.version.version}</td></tr> <tr><td>Zend OPcache</td><td>{props.version.version}</td></tr>
<tr><td>PHP</td><td>{props.version.php}</td></tr> <tr><td>PHP</td><td>{props.version.php}</td></tr>
<tr><td>Host</td><td>{props.version.host}</td></tr> <tr><td>{props.txt('Host')}</td><td>{props.version.host}</td></tr>
<tr><td>Server Software</td><td>{props.version.server}</td></tr> <tr><td>{props.txt('Server Software')}</td><td>{props.version.server}</td></tr>
{ props.start ? <tr><td>Start time</td><td>{props.start}</td></tr> : null } { props.start ? <tr><td>{props.txt('Start time')}</td><td>{props.start}</td></tr> : null }
{ props.reset ? <tr><td>Last reset</td><td>{props.reset}</td></tr> : null } { props.reset ? <tr><td>{props.txt('Last reset')}</td><td>{props.reset}</td></tr> : null }
</tbody> </tbody>
</table> </table>
); );
@ -352,9 +373,9 @@ function Directives(props) {
}); });
let vShow; let vShow;
if (directive.v === true || directive.v === false) { if (directive.v === true || directive.v === false) {
vShow = React.createElement('i', {}, directive.v.toString()); vShow = React.createElement('i', {}, props.txt(directive.v.toString()));
} else if (directive.v === '') { } else if (directive.v === '') {
vShow = React.createElement('i', {}, 'no value'); vShow = React.createElement('i', {}, props.txt('no value'));
} else { } else {
if (Array.isArray(directive.v)) { if (Array.isArray(directive.v)) {
vShow = directiveList(directive); vShow = directiveList(directive);
@ -364,7 +385,7 @@ function Directives(props) {
} }
return ( return (
<tr key={directive.k}> <tr key={directive.k}>
<td title={'View ' + directive.k + ' manual entry'}><a href={'https://php.net/manual/en/opcache.configuration.php#ini.' <td title={props.txt('View {0} manual entry', directive.k)}><a href={'https://php.net/manual/en/opcache.configuration.php#ini.'
+ (directive.k).replace(/_/g,'-')} target="_blank">{dShow}</a></td> + (directive.k).replace(/_/g,'-')} target="_blank">{dShow}</a></td>
<td>{vShow}</td> <td>{vShow}</td>
</tr> </tr>
@ -373,7 +394,7 @@ function Directives(props) {
return ( return (
<table className="tables directives-table"> <table className="tables directives-table">
<thead><tr><th colSpan="2">Directives</th></tr></thead> <thead><tr><th colSpan="2">{props.txt('Directives')}</th></tr></thead>
<tbody>{directiveNodes}</tbody> <tbody>{directiveNodes}</tbody>
</table> </table>
); );
@ -383,10 +404,10 @@ function Functions(props) {
return ( return (
<div id="functions"> <div id="functions">
<table className="tables"> <table className="tables">
<thead><tr><th>Available functions</th></tr></thead> <thead><tr><th>{props.txt('Available functions')}</th></tr></thead>
<tbody> <tbody>
{props.functions.map(f => {props.functions.map(f =>
<tr key={f}><td><a href={"https://php.net/"+f} title="View manual page" target="_blank">{f}</a></td></tr> <tr key={f}><td><a href={"https://php.net/"+f} title={props.txt('View manual page')} target="_blank">{f}</a></td></tr>
)} )}
</tbody> </tbody>
</table> </table>
@ -619,13 +640,13 @@ function MemoryUsagePanel(props) {
<div className="widget-panel"> <div className="widget-panel">
<h3 className="widget-header">memory usage</h3> <h3 className="widget-header">memory usage</h3>
<div className="widget-value widget-info"> <div className="widget-value widget-info">
<p><b>total memory:</b> {props.total}</p> <p><b>{props.txt('total memory')}:</b> {props.total}</p>
<p><b>used memory:</b> {props.used}</p> <p><b>{props.txt('used memory')}:</b> {props.used}</p>
<p><b>free memory:</b> {props.free}</p> <p><b>{props.txt('free memory')}:</b> {props.free}</p>
{ props.preload && <p><b>preload memory:</b> {props.preload}</p> } { props.preload && <p><b>{props.txt('preload memory')}:</b> {props.preload}</p> }
<p><b>wasted memory:</b> {props.wasted} ({props.wastedPercent}%)</p> <p><b>{props.txt('wasted memory')}:</b> {props.wasted} ({props.wastedPercent}%)</p>
{ props.jitBuffer && <p><b>jit buffer:</b> {props.jitBuffer}</p> } { props.jitBuffer && <p><b>{props.txt('jit buffer')}:</b> {props.jitBuffer}</p> }
{ props.jitBufferFree && <p><b>jit buffer free:</b> {props.jitBufferFree} ({100 - props.jitBufferFreePercentage}%)</p> } { props.jitBufferFree && <p><b>{props.txt('jit buffer free')}:</b> {props.jitBufferFree} ({100 - props.jitBufferFreePercentage}%)</p> }
</div> </div>
</div> </div>
); );
@ -635,14 +656,14 @@ function MemoryUsagePanel(props) {
function StatisticsPanel(props) { function StatisticsPanel(props) {
return ( return (
<div className="widget-panel"> <div className="widget-panel">
<h3 className="widget-header">opcache statistics</h3> <h3 className="widget-header">{props.txt('opcache statistics')}</h3>
<div className="widget-value widget-info"> <div className="widget-value widget-info">
<p><b>number of cached files:</b> {props.num_cached_scripts}</p> <p><b>{props.txt('number of cached')} files:</b> {props.num_cached_scripts}</p>
<p><b>number of hits:</b> {props.hits}</p> <p><b>{props.txt('number of hits')}:</b> {props.hits}</p>
<p><b>number of misses:</b> {props.misses}</p> <p><b>{props.txt('number of misses')}:</b> {props.misses}</p>
<p><b>blacklist misses:</b> {props.blacklist_miss}</p> <p><b>{props.txt('blacklist misses')}:</b> {props.blacklist_miss}</p>
<p><b>number of cached keys:</b> {props.num_cached_keys}</p> <p><b>{props.txt('number of cached keys')}:</b> {props.num_cached_keys}</p>
<p><b>max cached keys:</b> {props.max_cached_keys}</p> <p><b>{props.txt('max cached keys')}:</b> {props.max_cached_keys}</p>
</div> </div>
</div> </div>
); );
@ -652,12 +673,12 @@ function StatisticsPanel(props) {
function InternedStringsPanel(props) { function InternedStringsPanel(props) {
return ( return (
<div className="widget-panel"> <div className="widget-panel">
<h3 className="widget-header">interned strings usage</h3> <h3 className="widget-header">{props.txt('interned strings usage')}</h3>
<div className="widget-value widget-info"> <div className="widget-value widget-info">
<p><b>buffer size:</b> {props.buffer_size}</p> <p><b>{props.txt('buffer size')}:</b> {props.buffer_size}</p>
<p><b>used memory:</b> {props.strings_used_memory}</p> <p><b>{props.txt('used memory')}:</b> {props.strings_used_memory}</p>
<p><b>free memory:</b> {props.strings_free_memory}</p> <p><b>{props.txt('free memory')}:</b> {props.strings_free_memory}</p>
<p><b>number of strings:</b> {props.number_of_strings}</p> <p><b>{props.txt('number of strings')}:</b> {props.number_of_strings}</p>
</div> </div>
</div> </div>
); );
@ -732,7 +753,7 @@ class CachedFiles extends React.Component {
} }
if (this.props.allFiles.length === 0) { if (this.props.allFiles.length === 0) {
return <p>No files have been cached or you have <i>opcache.file_cache_only</i> turned on</p>; return <p>{this.props.txt('No files have been cached or you have <i>opcache.file_cache_only</i> turned on')}</p>;
} }
const { searchTerm, currentPage } = this.state; const { searchTerm, currentPage } = this.state;
@ -752,18 +773,19 @@ class CachedFiles extends React.Component {
); );
const allFilesTotal = this.props.allFiles.length; const allFilesTotal = this.props.allFiles.length;
const showingTotal = filesInSearch.length; const showingTotal = filesInSearch.length;
const showing = showingTotal !== allFilesTotal ? ", {1} showing due to filter '{2}'" : "";
return ( return (
<div> <div>
<form action="#"> <form action="#">
<label htmlFor="frmFilter">Start typing to filter on script path</label><br/> <label htmlFor="frmFilter">{this.props.txt('Start typing to filter on script path')}</label><br/>
<input type="text" name="filter" id="frmFilter" className="file-filter" onChange={e => {this.setSearchTerm(e.target.value)}} /> <input type="text" name="filter" id="frmFilter" className="file-filter" onChange={e => {this.setSearchTerm(e.target.value)}} />
</form> </form>
<h3>{allFilesTotal} files cached{showingTotal !== allFilesTotal && `, ${showingTotal} showing due to filter '${this.state.searchTerm}'`}</h3> <h3>{this.props.txt(`{0} files cached${showing}`, allFilesTotal, showingTotal, this.state.searchTerm)}</h3>
{ this.props.allow.invalidate && this.state.searchTerm && showingTotal !== allFilesTotal && { this.props.allow.invalidate && this.state.searchTerm && showingTotal !== allFilesTotal &&
<p><a href={`?invalidate_searched=${encodeURIComponent(this.state.searchTerm)}`} onClick={this.handleInvalidate}>Invalidate all matching files</a></p> <p><a href={`?invalidate_searched=${encodeURIComponent(this.state.searchTerm)}`} onClick={this.handleInvalidate}>{this.props.txt('Invalidate all matching files')}</a></p>
} }
<div className="paginate-filter"> <div className="paginate-filter">
@ -773,18 +795,19 @@ class CachedFiles extends React.Component {
pageNeighbours={2} pageNeighbours={2}
onPageChanged={this.onPageChanged} onPageChanged={this.onPageChanged}
refresh={this.state.refreshPagination} refresh={this.state.refreshPagination}
txt={this.props.txt}
/>} />}
<nav className="filter" aria-label="Sort order"> <nav className="filter" aria-label={this.props.txt('Sort order')}>
<select name="sortBy" onChange={this.changeSort} value={this.state.sortBy}> <select name="sortBy" onChange={this.changeSort} value={this.state.sortBy}>
<option value="last_used_timestamp">Last used</option> <option value="last_used_timestamp">{this.props.txt('Last used')}</option>
<option value="last_modified">Last modified</option> <option value="last_modified">{this.props.txt('Last modified')}</option>
<option value="full_path">Path</option> <option value="full_path">{this.props.txt('Path')}</option>
<option value="hits">Number of hits</option> <option value="hits">{this.props.txt('Number of hits')}</option>
<option value="memory_consumption">Memory consumption</option> <option value="memory_consumption">{this.props.txt('Memory consumption')}</option>
</select> </select>
<select name="sortDir" onChange={this.changeSort} value={this.state.sortDir}> <select name="sortDir" onChange={this.changeSort} value={this.state.sortDir}>
<option value="desc">Descending</option> <option value="desc">{this.props.txt('Descending')}</option>
<option value="asc">Ascending</option> <option value="asc">{this.props.txt('Ascending')}</option>
</select> </select>
</nav> </nav>
</div> </div>
@ -792,7 +815,7 @@ class CachedFiles extends React.Component {
<table className="tables cached-list-table"> <table className="tables cached-list-table">
<thead> <thead>
<tr> <tr>
<th>Script</th> <th>{this.props.txt('Script')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -801,6 +824,7 @@ class CachedFiles extends React.Component {
key={file.full_path} key={file.full_path}
canInvalidate={this.props.allow.invalidate} canInvalidate={this.props.allow.invalidate}
realtime={this.props.realtime} realtime={this.props.realtime}
txt={this.props.txt}
{...file} {...file}
/> />
})} })}
@ -831,15 +855,15 @@ class CachedFile extends React.Component {
<td> <td>
<span className="file-pathname">{this.props.full_path}</span> <span className="file-pathname">{this.props.full_path}</span>
<span className="file-metainfo"> <span className="file-metainfo">
<b>hits: </b><span>{this.props.readable.hits}, </span> <b>{this.props.txt('hits')}: </b><span>{this.props.readable.hits}, </span>
<b>memory: </b><span>{this.props.readable.memory_consumption}, </span> <b>{this.props.txt('memory')}: </b><span>{this.props.readable.memory_consumption}, </span>
{ this.props.last_modified && <><b>last modified: </b><span>{this.props.last_modified}, </span></> } { this.props.last_modified && <><b>{this.props.txt('last modified')}: </b><span>{this.props.last_modified}, </span></> }
<b>last used: </b><span>{this.props.last_used}</span> <b>{this.props.txt('last used')}: </b><span>{this.props.last_used}</span>
</span> </span>
{ !this.props.timestamp && <span className="invalid file-metainfo"> - has been invalidated</span> } { !this.props.timestamp && <span className="invalid file-metainfo"> - {this.props.txt('has been invalidated')}</span> }
{ this.props.canInvalidate && <span>,&nbsp;<a className="file-metainfo" { this.props.canInvalidate && <span>,&nbsp;<a className="file-metainfo"
href={'?invalidate=' + this.props.full_path} data-file={this.props.full_path} href={'?invalidate=' + this.props.full_path} data-file={this.props.full_path}
onClick={this.handleInvalidate}>force file invalidation</a></span> } onClick={this.handleInvalidate}>{this.props.txt('force file invalidation')}</a></span> }
</td> </td>
</tr> </tr>
); );
@ -869,7 +893,7 @@ class IgnoredFiles extends React.Component {
} }
if (this.props.allFiles.length === 0) { if (this.props.allFiles.length === 0) {
return <p>No files have been ignored via <i>opcache.blacklist_filename</i></p>; return <p>{this.props.txt('No files have been ignored via <i>opcache.blacklist_filename</i>')}</p>;
} }
const { currentPage } = this.state; const { currentPage } = this.state;
@ -882,7 +906,7 @@ class IgnoredFiles extends React.Component {
return ( return (
<div> <div>
<h3>{allFilesTotal} ignore file locations</h3> <h3>{this.props.txt('{0} ignore file locations', allFilesTotal)}</h3>
{this.doPagination && <Pagination {this.doPagination && <Pagination
totalRecords={allFilesTotal} totalRecords={allFilesTotal}
@ -890,10 +914,11 @@ class IgnoredFiles extends React.Component {
pageNeighbours={2} pageNeighbours={2}
onPageChanged={this.onPageChanged} onPageChanged={this.onPageChanged}
refresh={this.state.refreshPagination} refresh={this.state.refreshPagination}
txt={this.props.txt}
/>} />}
<table className="tables ignored-list-table"> <table className="tables ignored-list-table">
<thead><tr><th>Path</th></tr></thead> <thead><tr><th>{this.props.txt('Path')}</th></tr></thead>
<tbody> <tbody>
{filesInPage.map((file, index) => { {filesInPage.map((file, index) => {
return <tr key={file}><td>{file}</td></tr> return <tr key={file}><td>{file}</td></tr>
@ -928,7 +953,7 @@ class PreloadedFiles extends React.Component {
} }
if (this.props.allFiles.length === 0) { if (this.props.allFiles.length === 0) {
return <p>No files have been preloaded <i>opcache.preload</i></p>; return <p>{this.props.txt('No files have been preloaded <i>opcache.preload</i>')}</p>;
} }
const { currentPage } = this.state; const { currentPage } = this.state;
@ -941,7 +966,7 @@ class PreloadedFiles extends React.Component {
return ( return (
<div> <div>
<h3>{allFilesTotal} preloaded files</h3> <h3>{this.props.txt('{0} preloaded files', allFilesTotal)}</h3>
{this.doPagination && <Pagination {this.doPagination && <Pagination
totalRecords={allFilesTotal} totalRecords={allFilesTotal}
@ -949,10 +974,11 @@ class PreloadedFiles extends React.Component {
pageNeighbours={2} pageNeighbours={2}
onPageChanged={this.onPageChanged} onPageChanged={this.onPageChanged}
refresh={this.state.refreshPagination} refresh={this.state.refreshPagination}
txt={this.props.txt}
/>} />}
<table className="tables preload-list-table"> <table className="tables preload-list-table">
<thead><tr><th>Path</th></tr></thead> <thead><tr><th>{this.props.txt('Path')}</th></tr></thead>
<tbody> <tbody>
{filesInPage.map((file, index) => { {filesInPage.map((file, index) => {
return <tr key={file}><td>{file}</td></tr> return <tr key={file}><td>{file}</td></tr>
@ -1086,15 +1112,15 @@ class Pagination extends React.Component {
return ( return (
<React.Fragment key={index}> <React.Fragment key={index}>
<li className="page-item arrow"> <li className="page-item arrow">
<a className="page-link" href="#" aria-label="Previous" onClick={this.handleJumpLeft}> <a className="page-link" href="#" aria-label={this.props.txt('Previous')} onClick={this.handleJumpLeft}>
<span aria-hidden="true"></span> <span aria-hidden="true"></span>
<span className="sr-only">Jump back</span> <span className="sr-only">{this.props.txt('Jump back')}</span>
</a> </a>
</li> </li>
<li className="page-item arrow"> <li className="page-item arrow">
<a className="page-link" href="#" aria-label="Previous" onClick={this.handleMoveLeft}> <a className="page-link" href="#" aria-label={this.props.txt('Previous')} onClick={this.handleMoveLeft}>
<span aria-hidden="true"></span> <span aria-hidden="true"></span>
<span className="sr-only">Previous page</span> <span className="sr-only">{this.props.txt('Previous page')}</span>
</a> </a>
</li> </li>
</React.Fragment> </React.Fragment>
@ -1104,15 +1130,15 @@ class Pagination extends React.Component {
return ( return (
<React.Fragment key={index}> <React.Fragment key={index}>
<li className="page-item arrow"> <li className="page-item arrow">
<a className="page-link" href="#" aria-label="Next" onClick={this.handleMoveRight}> <a className="page-link" href="#" aria-label={this.props.txt('Next')} onClick={this.handleMoveRight}>
<span aria-hidden="true"></span> <span aria-hidden="true"></span>
<span className="sr-only">Next page</span> <span className="sr-only">{this.props.txt('Next page')}</span>
</a> </a>
</li> </li>
<li className="page-item arrow"> <li className="page-item arrow">
<a className="page-link" href="#" aria-label="Next" onClick={this.handleJumpRight}> <a className="page-link" href="#" aria-label={this.props.txt('Next')} onClick={this.handleJumpRight}>
<span aria-hidden="true"></span> <span aria-hidden="true"></span>
<span className="sr-only">Jump forward</span> <span className="sr-only">{this.props.txt('Jump forward')}</span>
</a> </a>
</li> </li>
</React.Fragment> </React.Fragment>

View file

@ -29,8 +29,8 @@ $jsOutput = trim(file_get_contents(__DIR__ . '/interface.js'));
$cssOutput = trim(file_get_contents(__DIR__ . '/interface.css')); $cssOutput = trim(file_get_contents(__DIR__ . '/interface.css'));
$phpOutput = trim(implode('', array_slice(file($parentPath . '/src/Opcache/Service.php'), 3))); $phpOutput = trim(implode('', array_slice(file($parentPath . '/src/Opcache/Service.php'), 3)));
$output = str_replace( $output = str_replace(
['{{JS_OUTPUT}}', '{{CSS_OUTPUT}}', '{{PHP_OUTPUT}}'], ['{{JS_OUTPUT}}', '{{CSS_OUTPUT}}', '{{PHP_OUTPUT}}', '{{LANGUAGE_PACK}}'],
[$jsOutput, $cssOutput, $phpOutput], [$jsOutput, $cssOutput, $phpOutput, 'null'],
$template $template
); );
if ($makeJsLocal) { if ($makeJsLocal) {

View file

@ -39,7 +39,8 @@ $options = [
'keys' => true, // show the keys used chart/big number 'keys' => true, // show the keys used chart/big number
'jit' => true // show the jit buffer chart/big number 'jit' => true // show the jit buffer chart/big number
], ],
'language_pack' => null // json structure of all text strings used, or null for default // json structure of all text strings used, or null for default
'language_pack' => {{LANGUAGE_PACK}}
]; ];
/* /*
@ -101,7 +102,8 @@ $opcache = (new Service($options))->handle();
highlight: <?= json_encode($opcache->getOption('highlight')); ?>, highlight: <?= json_encode($opcache->getOption('highlight')); ?>,
debounceRate: <?= $opcache->getOption('debounce_rate'); ?>, debounceRate: <?= $opcache->getOption('debounce_rate'); ?>,
perPageLimit: <?= json_encode($opcache->getOption('per_page')); ?>, perPageLimit: <?= json_encode($opcache->getOption('per_page')); ?>,
realtimeRefresh: <?= json_encode($opcache->getOption('refresh_time')); ?> realtimeRefresh: <?= json_encode($opcache->getOption('refresh_time')); ?>,
language: <?= json_encode($opcache->getOption('language_pack')); ?>,
}), document.getElementById('interface')); }), document.getElementById('interface'));
</script> </script>

350
index.php
View file

@ -20,24 +20,27 @@ namespace Amnuts\Opcache;
*/ */
$options = [ $options = [
'allow_filelist' => true, // show/hide the files tab 'allow_filelist' => true, // show/hide the files tab
'allow_invalidate' => true, // give a link to invalidate files 'allow_invalidate' => true, // give a link to invalidate files
'allow_reset' => true, // give option to reset the whole cache 'allow_reset' => true, // give option to reset the whole cache
'allow_realtime' => true, // give option to enable/disable real-time updates 'allow_realtime' => true, // give option to enable/disable real-time updates
'refresh_time' => 5, // how often the data will refresh, in seconds 'refresh_time' => 5, // how often the data will refresh, in seconds
'size_precision' => 2, // Digits after decimal point 'size_precision' => 2, // Digits after decimal point
'size_space' => false, // have '1MB' or '1 MB' when showing sizes 'size_space' => false, // have '1MB' or '1 MB' when showing sizes
'charts' => true, // show gauge chart or just big numbers 'charts' => true, // show gauge chart or just big numbers
'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering 'debounce_rate' => 250, // milliseconds after key press to send keyup event when filtering
'per_page' => 200, // How many results per page to show in the file list, false for no pagination 'per_page' => 200, // How many results per page to show in the file list, false for no pagination
'cookie_name' => 'opcachegui', // name of cookie 'cookie_name' => 'opcachegui', // name of cookie
'cookie_ttl' => 365, // days to store cookie 'cookie_ttl' => 365, // days to store cookie
'datetime_format' => 'D, d M Y H:i:s O', // Show datetime in this format
'highlight' => [ 'highlight' => [
'memory' => true, // show the memory chart/big number 'memory' => true, // show the memory chart/big number
'hits' => true, // show the hit rate chart/big number 'hits' => true, // show the hit rate chart/big number
'keys' => true, // show the keys used chart/big number 'keys' => true, // show the keys used chart/big number
'jit' => true // show the jit buffer chart/big number 'jit' => true // show the jit buffer chart/big number
] ],
// json structure of all text strings used, or null for default
'language_pack' => null
]; ];
/* /*
@ -68,6 +71,12 @@ class Service
protected $data; protected $data;
protected $options; protected $options;
protected $optimizationLevels; protected $optimizationLevels;
protected $jitModes;
protected $jitModeMapping = [
'tracing' => 1254,
'on' => 1254,
'function' => 1205
];
protected $defaults = [ protected $defaults = [
'allow_filelist' => true, // show/hide the files tab 'allow_filelist' => true, // show/hide the files tab
'allow_invalidate' => true, // give a link to invalidate files 'allow_invalidate' => true, // give a link to invalidate files
@ -87,51 +96,8 @@ class Service
'hits' => true, // show the hit rate chart/big number 'hits' => true, // show the hit rate chart/big number
'keys' => true, // show the keys used chart/big number 'keys' => true, // show the keys used chart/big number
'jit' => true // show the jit buffer chart/big number 'jit' => true // show the jit buffer chart/big number
]
];
protected $jitModes = [
[
'flag' => 'CPU-specific optimization',
'value' => [
'Disable CPU-specific optimization',
'Enable use of AVX, if the CPU supports it'
]
], ],
[ 'language_pack' => null // json structure of all text strings used, or null for default
'flag' => 'Register allocation',
'value' => [
'Do not perform register allocation',
'Perform block-local register allocation',
'Perform global register allocation'
]
],
[
'flag' => 'Trigger',
'value' => [
'Compile all functions on script load',
'Compile functions on first execution',
'Profile functions on first request and compile the hottest functions afterwards',
'Profile on the fly and compile hot functions',
'Currently unused',
'Use tracing JIT. Profile on the fly and compile traces for hot code segments'
]
],
[
'flag' => 'Optimization level',
'value' => [
'No JIT',
'Minimal JIT (call standard VM handlers)',
'Inline VM handlers',
'Use type inference',
'Use call graph',
'Optimize whole script'
]
]
];
protected $jitModeMapping = [
'tracing' => 1254,
'on' => 1254,
'function' => 1205
]; ];
/** /**
@ -141,29 +107,89 @@ class Service
*/ */
public function __construct(array $options = []) public function __construct(array $options = [])
{ {
$this->optimizationLevels = [
1 << 0 => 'CSE, STRING construction',
1 << 1 => 'Constant conversion and jumps',
1 << 2 => '++, +=, series of jumps',
1 << 3 => 'INIT_FCALL_BY_NAME -> DO_FCALL',
1 << 4 => 'CFG based optimization',
1 << 5 => 'DFA based optimization',
1 << 6 => 'CALL GRAPH optimization',
1 << 7 => 'SCCP (constant propagation)',
1 << 8 => 'TMP VAR usage',
1 << 9 => 'NOP removal',
1 << 10 => 'Merge equal constants',
1 << 11 => 'Adjust used stack',
1 << 12 => 'Remove unused variables',
1 << 13 => 'DCE (dead code elimination)',
1 << 14 => '(unsafe) Collect constants',
1 << 15 => 'Inline functions'
];
$this->options = array_merge($this->defaults, $options); $this->options = array_merge($this->defaults, $options);
$this->tz = new DateTimeZone(date_default_timezone_get()); $this->tz = new DateTimeZone(date_default_timezone_get());
if (is_string($this->options['language_pack'])) {
$this->options['language_pack'] = json_decode($this->options['language_pack'], true);
}
$this->optimizationLevels = [
1 << 0 => $this->txt('CSE, STRING construction'),
1 << 1 => $this->txt('Constant conversion and jumps'),
1 << 2 => $this->txt('++, +=, series of jumps'),
1 << 3 => $this->txt('INIT_FCALL_BY_NAME -> DO_FCALL'),
1 << 4 => $this->txt('CFG based optimization'),
1 << 5 => $this->txt('DFA based optimization'),
1 << 6 => $this->txt('CALL GRAPH optimization'),
1 << 7 => $this->txt('SCCP (constant propagation)'),
1 << 8 => $this->txt('TMP VAR usage'),
1 << 9 => $this->txt('NOP removal'),
1 << 10 => $this->txt('Merge equal constants'),
1 << 11 => $this->txt('Adjust used stack'),
1 << 12 => $this->txt('Remove unused variables'),
1 << 13 => $this->txt('DCE (dead code elimination)'),
1 << 14 => $this->txt('(unsafe) Collect constants'),
1 << 15 => $this->txt('Inline functions'),
];
$this->jitModes = [
[
'flag' => $this->txt('CPU-specific optimization'),
'value' => [
$this->txt('Disable CPU-specific optimization'),
$this->txt('Enable use of AVX, if the CPU supports it')
]
],
[
'flag' => $this->txt('Register allocation'),
'value' => [
$this->txt('Do not perform register allocation'),
$this->txt('Perform block-local register allocation'),
$this->txt('Perform global register allocation')
]
],
[
'flag' => $this->txt('Trigger'),
'value' => [
$this->txt('Compile all functions on script load'),
$this->txt('Compile functions on first execution'),
$this->txt('Profile functions on first request and compile the hottest functions afterwards'),
$this->txt('Profile on the fly and compile hot functions'),
$this->txt('Currently unused'),
$this->txt('Use tracing JIT. Profile on the fly and compile traces for hot code segments')
]
],
[
'flag' => $this->txt('Optimization level'),
'value' => [
$this->txt('No JIT'),
$this->txt('Minimal JIT (call standard VM handlers)'),
$this->txt('Inline VM handlers'),
$this->txt('Use type inference'),
$this->txt('Use call graph'),
$this->txt('Optimize whole script')
]
]
];
$this->data = $this->compileState(); $this->data = $this->compileState();
} }
/**
* @return string
*/
public function txt(): string
{
$args = func_get_args();
$text = array_shift($args);
if ((($lang = $this->getOption('language_pack')) !== null) && !empty($lang[$text])) {
$text = $lang[$text];
}
foreach ($args as $i => $arg) {
$text = str_replace('{' . $i . '}', $arg, $text);
}
return $text;
}
/** /**
* @return $this * @return $this
* @throws Exception * @throws Exception
@ -575,6 +601,17 @@ class Interface extends React.Component {
return v ? !!v[2] : false; return v ? !!v[2] : false;
}); });
_defineProperty(this, "txt", (text, ...args) => {
if (this.props.language !== null && this.props.language.hasOwnProperty(text) && this.props.language[text]) {
text = this.props.language[text];
}
args.forEach((arg, i) => {
text = text.replaceAll(`{${i}}`, arg);
});
return text;
});
this.state = { this.state = {
realtime: this.getCookie(), realtime: this.getCookie(),
resetting: false, resetting: false,
@ -599,7 +636,8 @@ class Interface extends React.Component {
realtime: this.state.realtime, realtime: this.state.realtime,
resetting: this.state.resetting, resetting: this.state.resetting,
realtimeHandler: this.realtimeHandler, realtimeHandler: this.realtimeHandler,
resetHandler: this.resetHandler resetHandler: this.resetHandler,
txt: this.txt
}))), /*#__PURE__*/React.createElement(Footer, { }))), /*#__PURE__*/React.createElement(Footer, {
version: this.props.opstate.version.gui version: this.props.opstate.version.gui
})); }));
@ -611,26 +649,30 @@ function MainNavigation(props) {
return /*#__PURE__*/React.createElement("nav", { return /*#__PURE__*/React.createElement("nav", {
className: "main-nav" className: "main-nav"
}, /*#__PURE__*/React.createElement(Tabs, null, /*#__PURE__*/React.createElement("div", { }, /*#__PURE__*/React.createElement(Tabs, null, /*#__PURE__*/React.createElement("div", {
label: "Overview", label: props.txt("Overview"),
tabId: "overview", tabId: "overview",
tabIndex: 1 tabIndex: 1
}, /*#__PURE__*/React.createElement(OverviewCounts, { }, /*#__PURE__*/React.createElement(OverviewCounts, {
overview: props.opstate.overview, overview: props.opstate.overview,
highlight: props.highlight, highlight: props.highlight,
useCharts: props.useCharts useCharts: props.useCharts,
txt: props.txt
}), /*#__PURE__*/React.createElement("div", { }), /*#__PURE__*/React.createElement("div", {
id: "info", id: "info",
className: "tab-content-overview-info" className: "tab-content-overview-info"
}, /*#__PURE__*/React.createElement(GeneralInfo, { }, /*#__PURE__*/React.createElement(GeneralInfo, {
start: props.opstate.overview && props.opstate.overview.readable.start_time || null, start: props.opstate.overview && props.opstate.overview.readable.start_time || null,
reset: props.opstate.overview && props.opstate.overview.readable.last_restart_time || null, reset: props.opstate.overview && props.opstate.overview.readable.last_restart_time || null,
version: props.opstate.version version: props.opstate.version,
txt: props.txt
}), /*#__PURE__*/React.createElement(Directives, { }), /*#__PURE__*/React.createElement(Directives, {
directives: props.opstate.directives directives: props.opstate.directives,
txt: props.txt
}), /*#__PURE__*/React.createElement(Functions, { }), /*#__PURE__*/React.createElement(Functions, {
functions: props.opstate.functions functions: props.opstate.functions,
txt: props.txt
}))), props.allow.filelist && /*#__PURE__*/React.createElement("div", { }))), props.allow.filelist && /*#__PURE__*/React.createElement("div", {
label: "Cached", label: props.txt("Cached"),
tabId: "cached", tabId: "cached",
tabIndex: 2 tabIndex: 2
}, /*#__PURE__*/React.createElement(CachedFiles, { }, /*#__PURE__*/React.createElement(CachedFiles, {
@ -642,9 +684,10 @@ function MainNavigation(props) {
fileList: props.allow.filelist, fileList: props.allow.filelist,
invalidate: props.allow.invalidate invalidate: props.allow.invalidate
}, },
realtime: props.realtime realtime: props.realtime,
txt: props.txt
})), props.allow.filelist && props.opstate.blacklist.length && /*#__PURE__*/React.createElement("div", { })), props.allow.filelist && props.opstate.blacklist.length && /*#__PURE__*/React.createElement("div", {
label: "Ignored", label: props.txt("Ignored"),
tabId: "ignored", tabId: "ignored",
tabIndex: 3 tabIndex: 3
}, /*#__PURE__*/React.createElement(IgnoredFiles, { }, /*#__PURE__*/React.createElement(IgnoredFiles, {
@ -652,9 +695,10 @@ function MainNavigation(props) {
allFiles: props.opstate.blacklist, allFiles: props.opstate.blacklist,
allow: { allow: {
fileList: props.allow.filelist fileList: props.allow.filelist
} },
txt: props.txt
})), props.allow.filelist && props.opstate.preload.length && /*#__PURE__*/React.createElement("div", { })), props.allow.filelist && props.opstate.preload.length && /*#__PURE__*/React.createElement("div", {
label: "Preloaded", label: props.txt("Preloaded"),
tabId: "preloaded", tabId: "preloaded",
tabIndex: 4 tabIndex: 4
}, /*#__PURE__*/React.createElement(PreloadedFiles, { }, /*#__PURE__*/React.createElement(PreloadedFiles, {
@ -662,15 +706,16 @@ function MainNavigation(props) {
allFiles: props.opstate.preload, allFiles: props.opstate.preload,
allow: { allow: {
fileList: props.allow.filelist fileList: props.allow.filelist
} },
txt: props.txt
})), props.allow.reset && /*#__PURE__*/React.createElement("div", { })), props.allow.reset && /*#__PURE__*/React.createElement("div", {
label: "Reset cache", label: props.txt("Reset cache"),
tabId: "resetCache", tabId: "resetCache",
className: `nav-tab-link-reset${props.resetting ? ' is-resetting pulse' : ''}`, className: `nav-tab-link-reset${props.resetting ? ' is-resetting pulse' : ''}`,
handler: props.resetHandler, handler: props.resetHandler,
tabIndex: 5 tabIndex: 5
}), props.allow.realtime && /*#__PURE__*/React.createElement("div", { }), props.allow.realtime && /*#__PURE__*/React.createElement("div", {
label: `${props.realtime ? 'Disable' : 'Enable'} real-time update`, label: props.txt(`${props.realtime ? 'Disable' : 'Enable'} real-time update`),
tabId: "toggleRealtime", tabId: "toggleRealtime",
className: `nav-tab-link-realtime${props.realtime ? ' live-update pulse' : ''}`, className: `nav-tab-link-realtime${props.realtime ? ' live-update pulse' : ''}`,
handler: props.realtimeHandler, handler: props.realtimeHandler,
@ -781,27 +826,27 @@ function OverviewCounts(props) {
if (props.overview === false) { if (props.overview === false) {
return /*#__PURE__*/React.createElement("p", { return /*#__PURE__*/React.createElement("p", {
class: "file-cache-only" class: "file-cache-only"
}, "You have ", /*#__PURE__*/React.createElement("i", null, "opcache.file_cache_only"), " turned on. As a result, the memory information is not available. Statistics and file list may also not be returned by ", /*#__PURE__*/React.createElement("i", null, "opcache_get_statistics()"), "."); }, props.txt(`You have <i>opcache.file_cache_only</i> turned on. As a result, the memory information is not available. Statistics and file list may also not be returned by <i>opcache_get_statistics()</i>.`));
} }
const graphList = [{ const graphList = [{
id: 'memoryUsageCanvas', id: 'memoryUsageCanvas',
title: 'memory', title: props.txt('memory'),
show: props.highlight.memory, show: props.highlight.memory,
value: props.overview.used_memory_percentage value: props.overview.used_memory_percentage
}, { }, {
id: 'hitRateCanvas', id: 'hitRateCanvas',
title: 'hit rate', title: props.txt('hit rate'),
show: props.highlight.hits, show: props.highlight.hits,
value: props.overview.hit_rate_percentage value: props.overview.hit_rate_percentage
}, { }, {
id: 'keyUsageCanvas', id: 'keyUsageCanvas',
title: 'keys', title: props.txt('keys'),
show: props.highlight.keys, show: props.highlight.keys,
value: props.overview.used_key_percentage value: props.overview.used_key_percentage
}, { }, {
id: 'jitUsageCanvas', id: 'jitUsageCanvas',
title: 'jit buffer', title: props.txt('jit buffer'),
show: props.highlight.jit, show: props.highlight.jit,
value: props.overview.jit_buffer_used_percentage value: props.overview.jit_buffer_used_percentage
}]; }];
@ -832,19 +877,22 @@ function OverviewCounts(props) {
wastedPercent: props.overview.wasted_percentage, wastedPercent: props.overview.wasted_percentage,
jitBuffer: props.overview.readable.jit_buffer_size || null, jitBuffer: props.overview.readable.jit_buffer_size || null,
jitBufferFree: props.overview.readable.jit_buffer_free || null, jitBufferFree: props.overview.readable.jit_buffer_free || null,
jitBufferFreePercentage: props.overview.jit_buffer_used_percentage || null jitBufferFreePercentage: props.overview.jit_buffer_used_percentage || null,
txt: props.txt
}), /*#__PURE__*/React.createElement(StatisticsPanel, { }), /*#__PURE__*/React.createElement(StatisticsPanel, {
num_cached_scripts: props.overview.readable.num_cached_scripts, num_cached_scripts: props.overview.readable.num_cached_scripts,
hits: props.overview.readable.hits, hits: props.overview.readable.hits,
misses: props.overview.readable.misses, misses: props.overview.readable.misses,
blacklist_miss: props.overview.readable.blacklist_miss, blacklist_miss: props.overview.readable.blacklist_miss,
num_cached_keys: props.overview.readable.num_cached_keys, num_cached_keys: props.overview.readable.num_cached_keys,
max_cached_keys: props.overview.readable.max_cached_keys max_cached_keys: props.overview.readable.max_cached_keys,
txt: props.txt
}), props.overview.readable.interned && /*#__PURE__*/React.createElement(InternedStringsPanel, { }), props.overview.readable.interned && /*#__PURE__*/React.createElement(InternedStringsPanel, {
buffer_size: props.overview.readable.interned.buffer_size, buffer_size: props.overview.readable.interned.buffer_size,
strings_used_memory: props.overview.readable.interned.strings_used_memory, strings_used_memory: props.overview.readable.interned.strings_used_memory,
strings_free_memory: props.overview.readable.interned.strings_free_memory, strings_free_memory: props.overview.readable.interned.strings_free_memory,
number_of_strings: props.overview.readable.interned.number_of_strings number_of_strings: props.overview.readable.interned.number_of_strings,
txt: props.txt
})); }));
} }
@ -853,7 +901,7 @@ function GeneralInfo(props) {
className: "tables general-info-table" className: "tables general-info-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", { }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", {
colSpan: "2" colSpan: "2"
}, "General info"))), /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Zend OPcache"), /*#__PURE__*/React.createElement("td", null, props.version.version)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "PHP"), /*#__PURE__*/React.createElement("td", null, props.version.php)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Host"), /*#__PURE__*/React.createElement("td", null, props.version.host)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Server Software"), /*#__PURE__*/React.createElement("td", null, props.version.server)), props.start ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Start time"), /*#__PURE__*/React.createElement("td", null, props.start)) : null, props.reset ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Last reset"), /*#__PURE__*/React.createElement("td", null, props.reset)) : null)); }, props.txt('General info')))), /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Zend OPcache"), /*#__PURE__*/React.createElement("td", null, props.version.version)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "PHP"), /*#__PURE__*/React.createElement("td", null, props.version.php)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, props.txt('Host')), /*#__PURE__*/React.createElement("td", null, props.version.host)), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, props.txt('Server Software')), /*#__PURE__*/React.createElement("td", null, props.version.server)), props.start ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, props.txt('Start time')), /*#__PURE__*/React.createElement("td", null, props.start)) : null, props.reset ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, props.txt('Last reset')), /*#__PURE__*/React.createElement("td", null, props.reset)) : null));
} }
function Directives(props) { function Directives(props) {
@ -882,9 +930,9 @@ function Directives(props) {
let vShow; let vShow;
if (directive.v === true || directive.v === false) { if (directive.v === true || directive.v === false) {
vShow = React.createElement('i', {}, directive.v.toString()); vShow = React.createElement('i', {}, props.txt(directive.v.toString()));
} else if (directive.v === '') { } else if (directive.v === '') {
vShow = React.createElement('i', {}, 'no value'); vShow = React.createElement('i', {}, props.txt('no value'));
} else { } else {
if (Array.isArray(directive.v)) { if (Array.isArray(directive.v)) {
vShow = directiveList(directive); vShow = directiveList(directive);
@ -896,7 +944,7 @@ function Directives(props) {
return /*#__PURE__*/React.createElement("tr", { return /*#__PURE__*/React.createElement("tr", {
key: directive.k key: directive.k
}, /*#__PURE__*/React.createElement("td", { }, /*#__PURE__*/React.createElement("td", {
title: 'View ' + directive.k + ' manual entry' title: props.txt('View {0} manual entry', directive.k)
}, /*#__PURE__*/React.createElement("a", { }, /*#__PURE__*/React.createElement("a", {
href: 'https://php.net/manual/en/opcache.configuration.php#ini.' + directive.k.replace(/_/g, '-'), href: 'https://php.net/manual/en/opcache.configuration.php#ini.' + directive.k.replace(/_/g, '-'),
target: "_blank" target: "_blank"
@ -906,7 +954,7 @@ function Directives(props) {
className: "tables directives-table" className: "tables directives-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", { }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", {
colSpan: "2" colSpan: "2"
}, "Directives"))), /*#__PURE__*/React.createElement("tbody", null, directiveNodes)); }, props.txt('Directives')))), /*#__PURE__*/React.createElement("tbody", null, directiveNodes));
} }
function Functions(props) { function Functions(props) {
@ -914,11 +962,11 @@ function Functions(props) {
id: "functions" id: "functions"
}, /*#__PURE__*/React.createElement("table", { }, /*#__PURE__*/React.createElement("table", {
className: "tables" className: "tables"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "Available functions"))), /*#__PURE__*/React.createElement("tbody", null, props.functions.map(f => /*#__PURE__*/React.createElement("tr", { }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, props.txt('Available functions')))), /*#__PURE__*/React.createElement("tbody", null, props.functions.map(f => /*#__PURE__*/React.createElement("tr", {
key: f key: f
}, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("a", { }, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("a", {
href: "https://php.net/" + f, href: "https://php.net/" + f,
title: "View manual page", title: props.txt('View manual page'),
target: "_blank" target: "_blank"
}, f))))))); }, f)))))));
} }
@ -1149,7 +1197,7 @@ function MemoryUsagePanel(props) {
className: "widget-header" className: "widget-header"
}, "memory usage"), /*#__PURE__*/React.createElement("div", { }, "memory usage"), /*#__PURE__*/React.createElement("div", {
className: "widget-value widget-info" className: "widget-value widget-info"
}, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "total memory:"), " ", props.total), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "used memory:"), " ", props.used), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "free memory:"), " ", props.free), props.preload && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "preload memory:"), " ", props.preload), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "wasted memory:"), " ", props.wasted, " (", props.wastedPercent, "%)"), props.jitBuffer && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "jit buffer:"), " ", props.jitBuffer), props.jitBufferFree && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "jit buffer free:"), " ", props.jitBufferFree, " (", 100 - props.jitBufferFreePercentage, "%)"))); }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('total memory'), ":"), " ", props.total), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('used memory'), ":"), " ", props.used), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('free memory'), ":"), " ", props.free), props.preload && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('preload memory'), ":"), " ", props.preload), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('wasted memory'), ":"), " ", props.wasted, " (", props.wastedPercent, "%)"), props.jitBuffer && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('jit buffer'), ":"), " ", props.jitBuffer), props.jitBufferFree && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('jit buffer free'), ":"), " ", props.jitBufferFree, " (", 100 - props.jitBufferFreePercentage, "%)")));
} }
function StatisticsPanel(props) { function StatisticsPanel(props) {
@ -1157,9 +1205,9 @@ function StatisticsPanel(props) {
className: "widget-panel" className: "widget-panel"
}, /*#__PURE__*/React.createElement("h3", { }, /*#__PURE__*/React.createElement("h3", {
className: "widget-header" className: "widget-header"
}, "opcache statistics"), /*#__PURE__*/React.createElement("div", { }, props.txt('opcache statistics')), /*#__PURE__*/React.createElement("div", {
className: "widget-value widget-info" className: "widget-value widget-info"
}, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "number of cached files:"), " ", props.num_cached_scripts), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "number of hits:"), " ", props.hits), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "number of misses:"), " ", props.misses), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "blacklist misses:"), " ", props.blacklist_miss), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "number of cached keys:"), " ", props.num_cached_keys), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "max cached keys:"), " ", props.max_cached_keys))); }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('number of cached'), " files:"), " ", props.num_cached_scripts), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('number of hits'), ":"), " ", props.hits), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('number of misses'), ":"), " ", props.misses), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('blacklist misses'), ":"), " ", props.blacklist_miss), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('number of cached keys'), ":"), " ", props.num_cached_keys), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('max cached keys'), ":"), " ", props.max_cached_keys)));
} }
function InternedStringsPanel(props) { function InternedStringsPanel(props) {
@ -1167,9 +1215,9 @@ function InternedStringsPanel(props) {
className: "widget-panel" className: "widget-panel"
}, /*#__PURE__*/React.createElement("h3", { }, /*#__PURE__*/React.createElement("h3", {
className: "widget-header" className: "widget-header"
}, "interned strings usage"), /*#__PURE__*/React.createElement("div", { }, props.txt('interned strings usage')), /*#__PURE__*/React.createElement("div", {
className: "widget-value widget-info" className: "widget-value widget-info"
}, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "buffer size:"), " ", props.buffer_size), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "used memory:"), " ", props.strings_used_memory), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "free memory:"), " ", props.strings_free_memory), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, "number of strings:"), " ", props.number_of_strings))); }, /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('buffer size'), ":"), " ", props.buffer_size), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('used memory'), ":"), " ", props.strings_used_memory), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('free memory'), ":"), " ", props.strings_free_memory), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("b", null, props.txt('number of strings'), ":"), " ", props.number_of_strings)));
} }
class CachedFiles extends React.Component { class CachedFiles extends React.Component {
@ -1247,7 +1295,7 @@ class CachedFiles extends React.Component {
} }
if (this.props.allFiles.length === 0) { if (this.props.allFiles.length === 0) {
return /*#__PURE__*/React.createElement("p", null, "No files have been cached or you have ", /*#__PURE__*/React.createElement("i", null, "opcache.file_cache_only"), " turned on"); return /*#__PURE__*/React.createElement("p", null, this.props.txt('No files have been cached or you have <i>opcache.file_cache_only</i> turned on'));
} }
const { const {
@ -1262,11 +1310,12 @@ class CachedFiles extends React.Component {
const filesInPage = this.doPagination ? filesInSearch.slice(offset, offset + this.props.perPageLimit) : filesInSearch; const filesInPage = this.doPagination ? filesInSearch.slice(offset, offset + this.props.perPageLimit) : filesInSearch;
const allFilesTotal = this.props.allFiles.length; const allFilesTotal = this.props.allFiles.length;
const showingTotal = filesInSearch.length; const showingTotal = filesInSearch.length;
const showing = showingTotal !== allFilesTotal ? ", {1} showing due to filter '{2}'" : "";
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("form", { return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("form", {
action: "#" action: "#"
}, /*#__PURE__*/React.createElement("label", { }, /*#__PURE__*/React.createElement("label", {
htmlFor: "frmFilter" htmlFor: "frmFilter"
}, "Start typing to filter on script path"), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("input", { }, this.props.txt('Start typing to filter on script path')), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("input", {
type: "text", type: "text",
name: "filter", name: "filter",
id: "frmFilter", id: "frmFilter",
@ -1274,49 +1323,51 @@ class CachedFiles extends React.Component {
onChange: e => { onChange: e => {
this.setSearchTerm(e.target.value); this.setSearchTerm(e.target.value);
} }
})), /*#__PURE__*/React.createElement("h3", null, allFilesTotal, " files cached", showingTotal !== allFilesTotal && `, ${showingTotal} showing due to filter '${this.state.searchTerm}'`), this.props.allow.invalidate && this.state.searchTerm && showingTotal !== allFilesTotal && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("a", { })), /*#__PURE__*/React.createElement("h3", null, this.props.txt(`{0} files cached${showing}`, allFilesTotal, showingTotal, this.state.searchTerm)), this.props.allow.invalidate && this.state.searchTerm && showingTotal !== allFilesTotal && /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement("a", {
href: `?invalidate_searched=${encodeURIComponent(this.state.searchTerm)}`, href: `?invalidate_searched=${encodeURIComponent(this.state.searchTerm)}`,
onClick: this.handleInvalidate onClick: this.handleInvalidate
}, "Invalidate all matching files")), /*#__PURE__*/React.createElement("div", { }, this.props.txt('Invalidate all matching files'))), /*#__PURE__*/React.createElement("div", {
className: "paginate-filter" className: "paginate-filter"
}, this.doPagination && /*#__PURE__*/React.createElement(Pagination, { }, this.doPagination && /*#__PURE__*/React.createElement(Pagination, {
totalRecords: filesInSearch.length, totalRecords: filesInSearch.length,
pageLimit: this.props.perPageLimit, pageLimit: this.props.perPageLimit,
pageNeighbours: 2, pageNeighbours: 2,
onPageChanged: this.onPageChanged, onPageChanged: this.onPageChanged,
refresh: this.state.refreshPagination refresh: this.state.refreshPagination,
txt: this.props.txt
}), /*#__PURE__*/React.createElement("nav", { }), /*#__PURE__*/React.createElement("nav", {
className: "filter", className: "filter",
"aria-label": "Sort order" "aria-label": this.props.txt('Sort order')
}, /*#__PURE__*/React.createElement("select", { }, /*#__PURE__*/React.createElement("select", {
name: "sortBy", name: "sortBy",
onChange: this.changeSort, onChange: this.changeSort,
value: this.state.sortBy value: this.state.sortBy
}, /*#__PURE__*/React.createElement("option", { }, /*#__PURE__*/React.createElement("option", {
value: "last_used_timestamp" value: "last_used_timestamp"
}, "Last used"), /*#__PURE__*/React.createElement("option", { }, this.props.txt('Last used')), /*#__PURE__*/React.createElement("option", {
value: "last_modified" value: "last_modified"
}, "Last modified"), /*#__PURE__*/React.createElement("option", { }, this.props.txt('Last modified')), /*#__PURE__*/React.createElement("option", {
value: "full_path" value: "full_path"
}, "Path"), /*#__PURE__*/React.createElement("option", { }, this.props.txt('Path')), /*#__PURE__*/React.createElement("option", {
value: "hits" value: "hits"
}, "Number of hits"), /*#__PURE__*/React.createElement("option", { }, this.props.txt('Number of hits')), /*#__PURE__*/React.createElement("option", {
value: "memory_consumption" value: "memory_consumption"
}, "Memory consumption")), /*#__PURE__*/React.createElement("select", { }, this.props.txt('Memory consumption'))), /*#__PURE__*/React.createElement("select", {
name: "sortDir", name: "sortDir",
onChange: this.changeSort, onChange: this.changeSort,
value: this.state.sortDir value: this.state.sortDir
}, /*#__PURE__*/React.createElement("option", { }, /*#__PURE__*/React.createElement("option", {
value: "desc" value: "desc"
}, "Descending"), /*#__PURE__*/React.createElement("option", { }, this.props.txt('Descending')), /*#__PURE__*/React.createElement("option", {
value: "asc" value: "asc"
}, "Ascending")))), /*#__PURE__*/React.createElement("table", { }, this.props.txt('Ascending'))))), /*#__PURE__*/React.createElement("table", {
className: "tables cached-list-table" className: "tables cached-list-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "Script"))), /*#__PURE__*/React.createElement("tbody", null, filesInPage.map((file, index) => { }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, this.props.txt('Script')))), /*#__PURE__*/React.createElement("tbody", null, filesInPage.map((file, index) => {
return /*#__PURE__*/React.createElement(CachedFile, _extends({ return /*#__PURE__*/React.createElement(CachedFile, _extends({
key: file.full_path, key: file.full_path,
canInvalidate: this.props.allow.invalidate, canInvalidate: this.props.allow.invalidate,
realtime: this.props.realtime realtime: this.props.realtime,
txt: this.props.txt
}, file)); }, file));
})))); }))));
} }
@ -1351,14 +1402,14 @@ class CachedFile extends React.Component {
className: "file-pathname" className: "file-pathname"
}, this.props.full_path), /*#__PURE__*/React.createElement("span", { }, this.props.full_path), /*#__PURE__*/React.createElement("span", {
className: "file-metainfo" className: "file-metainfo"
}, /*#__PURE__*/React.createElement("b", null, "hits: "), /*#__PURE__*/React.createElement("span", null, this.props.readable.hits, ", "), /*#__PURE__*/React.createElement("b", null, "memory: "), /*#__PURE__*/React.createElement("span", null, this.props.readable.memory_consumption, ", "), this.props.last_modified && /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("b", null, "last modified: "), /*#__PURE__*/React.createElement("span", null, this.props.last_modified, ", ")), /*#__PURE__*/React.createElement("b", null, "last used: "), /*#__PURE__*/React.createElement("span", null, this.props.last_used)), !this.props.timestamp && /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("b", null, this.props.txt('hits'), ": "), /*#__PURE__*/React.createElement("span", null, this.props.readable.hits, ", "), /*#__PURE__*/React.createElement("b", null, this.props.txt('memory'), ": "), /*#__PURE__*/React.createElement("span", null, this.props.readable.memory_consumption, ", "), this.props.last_modified && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("b", null, this.props.txt('last modified'), ": "), /*#__PURE__*/React.createElement("span", null, this.props.last_modified, ", ")), /*#__PURE__*/React.createElement("b", null, this.props.txt('last used'), ": "), /*#__PURE__*/React.createElement("span", null, this.props.last_used)), !this.props.timestamp && /*#__PURE__*/React.createElement("span", {
className: "invalid file-metainfo" className: "invalid file-metainfo"
}, " - has been invalidated"), this.props.canInvalidate && /*#__PURE__*/React.createElement("span", null, ",\xA0", /*#__PURE__*/React.createElement("a", { }, " - ", this.props.txt('has been invalidated')), this.props.canInvalidate && /*#__PURE__*/React.createElement("span", null, ",\xA0", /*#__PURE__*/React.createElement("a", {
className: "file-metainfo", className: "file-metainfo",
href: '?invalidate=' + this.props.full_path, href: '?invalidate=' + this.props.full_path,
"data-file": this.props.full_path, "data-file": this.props.full_path,
onClick: this.handleInvalidate onClick: this.handleInvalidate
}, "force file invalidation")))); }, this.props.txt('force file invalidation')))));
} }
} }
@ -1386,7 +1437,7 @@ class IgnoredFiles extends React.Component {
} }
if (this.props.allFiles.length === 0) { if (this.props.allFiles.length === 0) {
return /*#__PURE__*/React.createElement("p", null, "No files have been ignored via ", /*#__PURE__*/React.createElement("i", null, "opcache.blacklist_filename")); return /*#__PURE__*/React.createElement("p", null, this.props.txt('No files have been ignored via <i>opcache.blacklist_filename</i>'));
} }
const { const {
@ -1395,15 +1446,16 @@ class IgnoredFiles extends React.Component {
const offset = (currentPage - 1) * this.props.perPageLimit; const offset = (currentPage - 1) * this.props.perPageLimit;
const filesInPage = this.doPagination ? this.props.allFiles.slice(offset, offset + this.props.perPageLimit) : this.props.allFiles; const filesInPage = this.doPagination ? this.props.allFiles.slice(offset, offset + this.props.perPageLimit) : this.props.allFiles;
const allFilesTotal = this.props.allFiles.length; const allFilesTotal = this.props.allFiles.length;
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h3", null, allFilesTotal, " ignore file locations"), this.doPagination && /*#__PURE__*/React.createElement(Pagination, { return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h3", null, this.props.txt('{0} ignore file locations', allFilesTotal)), this.doPagination && /*#__PURE__*/React.createElement(Pagination, {
totalRecords: allFilesTotal, totalRecords: allFilesTotal,
pageLimit: this.props.perPageLimit, pageLimit: this.props.perPageLimit,
pageNeighbours: 2, pageNeighbours: 2,
onPageChanged: this.onPageChanged, onPageChanged: this.onPageChanged,
refresh: this.state.refreshPagination refresh: this.state.refreshPagination,
txt: this.props.txt
}), /*#__PURE__*/React.createElement("table", { }), /*#__PURE__*/React.createElement("table", {
className: "tables ignored-list-table" className: "tables ignored-list-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "Path"))), /*#__PURE__*/React.createElement("tbody", null, filesInPage.map((file, index) => { }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, this.props.txt('Path')))), /*#__PURE__*/React.createElement("tbody", null, filesInPage.map((file, index) => {
return /*#__PURE__*/React.createElement("tr", { return /*#__PURE__*/React.createElement("tr", {
key: file key: file
}, /*#__PURE__*/React.createElement("td", null, file)); }, /*#__PURE__*/React.createElement("td", null, file));
@ -1435,7 +1487,7 @@ class PreloadedFiles extends React.Component {
} }
if (this.props.allFiles.length === 0) { if (this.props.allFiles.length === 0) {
return /*#__PURE__*/React.createElement("p", null, "No files have been preloaded ", /*#__PURE__*/React.createElement("i", null, "opcache.preload")); return /*#__PURE__*/React.createElement("p", null, this.props.txt('No files have been preloaded <i>opcache.preload</i>'));
} }
const { const {
@ -1444,15 +1496,16 @@ class PreloadedFiles extends React.Component {
const offset = (currentPage - 1) * this.props.perPageLimit; const offset = (currentPage - 1) * this.props.perPageLimit;
const filesInPage = this.doPagination ? this.props.allFiles.slice(offset, offset + this.props.perPageLimit) : this.props.allFiles; const filesInPage = this.doPagination ? this.props.allFiles.slice(offset, offset + this.props.perPageLimit) : this.props.allFiles;
const allFilesTotal = this.props.allFiles.length; const allFilesTotal = this.props.allFiles.length;
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h3", null, allFilesTotal, " preloaded files"), this.doPagination && /*#__PURE__*/React.createElement(Pagination, { return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h3", null, this.props.txt('{0} preloaded files', allFilesTotal)), this.doPagination && /*#__PURE__*/React.createElement(Pagination, {
totalRecords: allFilesTotal, totalRecords: allFilesTotal,
pageLimit: this.props.perPageLimit, pageLimit: this.props.perPageLimit,
pageNeighbours: 2, pageNeighbours: 2,
onPageChanged: this.onPageChanged, onPageChanged: this.onPageChanged,
refresh: this.state.refreshPagination refresh: this.state.refreshPagination,
txt: this.props.txt
}), /*#__PURE__*/React.createElement("table", { }), /*#__PURE__*/React.createElement("table", {
className: "tables preload-list-table" className: "tables preload-list-table"
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, "Path"))), /*#__PURE__*/React.createElement("tbody", null, filesInPage.map((file, index) => { }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null, this.props.txt('Path')))), /*#__PURE__*/React.createElement("tbody", null, filesInPage.map((file, index) => {
return /*#__PURE__*/React.createElement("tr", { return /*#__PURE__*/React.createElement("tr", {
key: file key: file
}, /*#__PURE__*/React.createElement("td", null, file)); }, /*#__PURE__*/React.createElement("td", null, file));
@ -1595,24 +1648,24 @@ class Pagination extends React.Component {
}, /*#__PURE__*/React.createElement("a", { }, /*#__PURE__*/React.createElement("a", {
className: "page-link", className: "page-link",
href: "#", href: "#",
"aria-label": "Previous", "aria-label": this.props.txt('Previous'),
onClick: this.handleJumpLeft onClick: this.handleJumpLeft
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
"aria-hidden": "true" "aria-hidden": "true"
}, "\u219E"), /*#__PURE__*/React.createElement("span", { }, "\u219E"), /*#__PURE__*/React.createElement("span", {
className: "sr-only" className: "sr-only"
}, "Jump back"))), /*#__PURE__*/React.createElement("li", { }, this.props.txt('Jump back')))), /*#__PURE__*/React.createElement("li", {
className: "page-item arrow" className: "page-item arrow"
}, /*#__PURE__*/React.createElement("a", { }, /*#__PURE__*/React.createElement("a", {
className: "page-link", className: "page-link",
href: "#", href: "#",
"aria-label": "Previous", "aria-label": this.props.txt('Previous'),
onClick: this.handleMoveLeft onClick: this.handleMoveLeft
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
"aria-hidden": "true" "aria-hidden": "true"
}, "\u21E0"), /*#__PURE__*/React.createElement("span", { }, "\u21E0"), /*#__PURE__*/React.createElement("span", {
className: "sr-only" className: "sr-only"
}, "Previous page")))); }, this.props.txt('Previous page')))));
} }
if (page === "RIGHT") { if (page === "RIGHT") {
@ -1623,24 +1676,24 @@ class Pagination extends React.Component {
}, /*#__PURE__*/React.createElement("a", { }, /*#__PURE__*/React.createElement("a", {
className: "page-link", className: "page-link",
href: "#", href: "#",
"aria-label": "Next", "aria-label": this.props.txt('Next'),
onClick: this.handleMoveRight onClick: this.handleMoveRight
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
"aria-hidden": "true" "aria-hidden": "true"
}, "\u21E2"), /*#__PURE__*/React.createElement("span", { }, "\u21E2"), /*#__PURE__*/React.createElement("span", {
className: "sr-only" className: "sr-only"
}, "Next page"))), /*#__PURE__*/React.createElement("li", { }, this.props.txt('Next page')))), /*#__PURE__*/React.createElement("li", {
className: "page-item arrow" className: "page-item arrow"
}, /*#__PURE__*/React.createElement("a", { }, /*#__PURE__*/React.createElement("a", {
className: "page-link", className: "page-link",
href: "#", href: "#",
"aria-label": "Next", "aria-label": this.props.txt('Next'),
onClick: this.handleJumpRight onClick: this.handleJumpRight
}, /*#__PURE__*/React.createElement("span", { }, /*#__PURE__*/React.createElement("span", {
"aria-hidden": "true" "aria-hidden": "true"
}, "\u21A0"), /*#__PURE__*/React.createElement("span", { }, "\u21A0"), /*#__PURE__*/React.createElement("span", {
className: "sr-only" className: "sr-only"
}, "Jump forward")))); }, this.props.txt('Jump forward')))));
} }
return /*#__PURE__*/React.createElement("li", { return /*#__PURE__*/React.createElement("li", {
@ -1708,7 +1761,8 @@ function debounce(func, wait, immediate) {
highlight: <?= json_encode($opcache->getOption('highlight')); ?>, highlight: <?= json_encode($opcache->getOption('highlight')); ?>,
debounceRate: <?= $opcache->getOption('debounce_rate'); ?>, debounceRate: <?= $opcache->getOption('debounce_rate'); ?>,
perPageLimit: <?= json_encode($opcache->getOption('per_page')); ?>, perPageLimit: <?= json_encode($opcache->getOption('per_page')); ?>,
realtimeRefresh: <?= json_encode($opcache->getOption('refresh_time')); ?> realtimeRefresh: <?= json_encode($opcache->getOption('refresh_time')); ?>,
language: <?= json_encode($opcache->getOption('language_pack')); ?>,
}), document.getElementById('interface')); }), document.getElementById('interface'));
</script> </script>

View file

@ -50,6 +50,12 @@ class Service
*/ */
public function __construct(array $options = []) public function __construct(array $options = [])
{ {
$this->options = array_merge($this->defaults, $options);
$this->tz = new DateTimeZone(date_default_timezone_get());
if (is_string($this->options['language_pack'])) {
$this->options['language_pack'] = json_decode($this->options['language_pack'], true);
}
$this->optimizationLevels = [ $this->optimizationLevels = [
1 << 0 => $this->txt('CSE, STRING construction'), 1 << 0 => $this->txt('CSE, STRING construction'),
1 << 1 => $this->txt('Constant conversion and jumps'), 1 << 1 => $this->txt('Constant conversion and jumps'),
@ -107,8 +113,6 @@ class Service
] ]
] ]
]; ];
$this->options = array_merge($this->defaults, $options);
$this->tz = new DateTimeZone(date_default_timezone_get());
$this->data = $this->compileState(); $this->data = $this->compileState();
} }
@ -120,7 +124,7 @@ class Service
{ {
$args = func_get_args(); $args = func_get_args();
$text = array_shift($args); $text = array_shift($args);
if ((($lang = $this->getOption('language')) !== null) && !empty($lang[$text])) { if ((($lang = $this->getOption('language_pack')) !== null) && !empty($lang[$text])) {
$text = $lang[$text]; $text = $lang[$text];
} }
foreach ($args as $i => $arg) { foreach ($args as $i => $arg) {