Fix: FFmpeg Binaries Path now accepts directory-only paths (auto-appends /ffmpeg)

This commit is contained in:
Forkless
2026-05-11 21:57:24 +02:00
parent fac0699997
commit 7470ddd832
36 changed files with 976 additions and 126 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"schema_version": 1,
"agents": []
}
+18
View File
@@ -2,6 +2,24 @@
All notable changes to the Piperless WordPress plugin. All notable changes to the Piperless WordPress plugin.
## [1.1.0] — 2026-05-10
### Added
- **Opus audio format** — new "Audio Format" selector (MP3 / Opus) in the Piper tab. Opus encodes with `libopus` (`-application voip`) for better quality at lower bitrates. Separate bitrate selector for Opus: 24k (standard), 16k (compact), 12k (minimal). Cache key includes format so switching regenerates files.
- **Gutenberg sidebar format support** — preview player uses `<source>` with explicit `type="audio/ogg"` for Opus files. Format tracked in `_piperless_audio_format` post meta and returned in REST responses.
- **ffprobe-based duration detection** — for MP3 and Opus files, uses `find_ffprobe()` (same directory as resolved ffmpeg) to read exact duration. Falls back to WAV header calculation.
- **Cache entry deletion clears post meta** — deleting an entry now removes all related meta fields from the owning post.
- **Server-side cache sorting** — Size and Created columns now sort the entire dataset before pagination, not just the current page.
- **Professional pagination** — Previous/Next/First/Last buttons, smart page numbers with ellipsis, "X items" count, placed at both top and bottom of the cache browser.
### Changed
- **FFmpeg Binaries Path** — field renamed from "FFmpeg Binary Path" to reflect that the directory is used for the full toolchain (ffmpeg, ffprobe). Description updated to mention MP3/Opus.
- **Cache scanning includes `.opus`** — all cache methods (`get_entries`, `clear`, `delete`, `stats`, `clear_orphans`) now handle `.opus` alongside `.mp3` and `.wav`.
- **Opus cache badge** — blue badge (#1565c0) in the cache browser Format column.
- **Translations** — all 8 locales at 117/117 strings.
## [1.0.0] — 2026-05-09 ## [1.0.0] — 2026-05-09
### Added ### Added
+5
View File
@@ -255,6 +255,11 @@
color: #50575e; color: #50575e;
} }
.piperless-cache-badge--opus {
background: #e3f2fd;
color: #1565c0;
}
.piperless-cache-badge--orphan { .piperless-cache-badge--orphan {
background: #fcf0f1; background: #fcf0f1;
color: #b32d2e; color: #b32d2e;
+66 -32
View File
@@ -214,6 +214,54 @@
let cacheSortKey = 'created'; let cacheSortKey = 'created';
let cacheSortAsc = false; let cacheSortAsc = false;
/**
* Build WordPress-style pagination bar with Previous / Next buttons
* and page numbers. Renders a full .tablenav div.
*
* @param {number} current Current page.
* @param {number} totalPages Total pages.
* @param {number} totalItems Total items.
* @return {string} HTML string, or empty string if only one page.
*/
function buildPaginationHtml( current, totalPages, totalItems ) {
if ( totalPages <= 1 ) return '';
var html = '<div class="tablenav top" style="display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-bottom:8px;">';
html += '<div class="tablenav-pages" style="display:flex;align-items:center;gap:4px;">';
html += '<span class="displaying-num" style="margin-right:8px;">' + totalItems + ' items</span>';
// First page button.
html += '<a href="#" class="first-page button piperless-cache-page' + ( current === 1 ? ' disabled' : '' ) + '" data-page="1" aria-label="First page">&laquo;</a>';
// Previous button.
html += '<a href="#" class="prev-page button piperless-cache-page' + ( current === 1 ? ' disabled' : '' ) + '" data-page="' + ( current - 1 ) + '" aria-label="Previous page">&lsaquo;</a>';
// Page numbers.
html += '<span class="paging-input" style="display:flex;align-items:center;gap:2px;">';
for ( var i = 1; i <= totalPages; i++ ) {
if ( Math.abs( i - current ) <= 2 || i === 1 || i === totalPages ) {
if ( i === current ) {
html += '<span class="tablenav-paging-text"><strong>' + i + '</strong></span>';
} else {
html += '<a href="#" class="piperless-cache-page" data-page="' + i + '" style="text-decoration:none;padding:0 4px;">' + i + '</a>';
}
} else if ( i === 2 && current > 4 ) {
html += '<span class="tablenav-paging-text">&hellip;</span>';
} else if ( i === totalPages - 1 && current < totalPages - 3 ) {
html += '<span class="tablenav-paging-text">&hellip;</span>';
}
}
html += '</span>';
// Next button.
html += '<a href="#" class="next-page button piperless-cache-page' + ( current === totalPages ? ' disabled' : '' ) + '" data-page="' + ( current + 1 ) + '" aria-label="Next page">&rsaquo;</a>';
// Last page button.
html += '<a href="#" class="last-page button piperless-cache-page' + ( current === totalPages ? ' disabled' : '' ) + '" data-page="' + totalPages + '" aria-label="Last page">&raquo;</a>';
html += '</div></div>';
return html;
}
function loadCacheBrowser( page ) { function loadCacheBrowser( page ) {
const $browser = $( '#piperless-cache-browser' ); const $browser = $( '#piperless-cache-browser' );
$browser.html( '<p>' + 'Loading…' + '</p>' ); $browser.html( '<p>' + 'Loading…' + '</p>' );
@@ -223,6 +271,8 @@
nonce: admin.nonce, nonce: admin.nonce,
page: page || 1, page: page || 1,
per_page: 15, per_page: 15,
sort_by: cacheSortKey,
sort_order: cacheSortAsc ? 'asc' : 'desc',
} ).done( function ( resp ) { } ).done( function ( resp ) {
if ( ! resp.success || ! resp.data ) { if ( ! resp.success || ! resp.data ) {
$browser.html( '<p>Failed to load cache entries.</p>' ); $browser.html( '<p>Failed to load cache entries.</p>' );
@@ -236,6 +286,12 @@
if ( d.total === 0 ) { if ( d.total === 0 ) {
html = '<p>No cached audio files.</p>'; html = '<p>No cached audio files.</p>';
} else { } else {
// ── Pagination bar (top) ──
var paginationHtml = buildPaginationHtml( cachePage, d.pages, d.total );
if ( paginationHtml ) {
html += paginationHtml;
}
html += '<table class="wp-list-table widefat fixed striped">'; html += '<table class="wp-list-table widefat fixed striped">';
html += '<thead><tr>'; html += '<thead><tr>';
html += '<th><input type="checkbox" class="piperless-select-all"></th>'; html += '<th><input type="checkbox" class="piperless-select-all"></th>';
@@ -245,23 +301,7 @@
html += '<th>Format</th><th>Model</th><th>Shortcode</th><th>Status</th><th>Actions</th>'; html += '<th>Format</th><th>Model</th><th>Shortcode</th><th>Status</th><th>Actions</th>';
html += '</tr></thead><tbody>'; html += '</tr></thead><tbody>';
// Apply client-side sort if active. d.entries.forEach( function ( entry ) {
let entries = d.entries;
if ( cacheSortKey === 'size' ) {
entries = entries.slice().sort( function ( a, b ) {
return cacheSortAsc
? ( a.size_bytes || 0 ) - ( b.size_bytes || 0 )
: ( b.size_bytes || 0 ) - ( a.size_bytes || 0 );
} );
} else if ( cacheSortKey === 'created' ) {
entries = entries.slice().sort( function ( a, b ) {
const da = a.created || '';
const db = b.created || '';
return cacheSortAsc ? da.localeCompare( db ) : db.localeCompare( da );
} );
}
entries.forEach( function ( entry ) {
const sizeKB = ( entry.size_bytes / 1024 ).toFixed( 1 ); const sizeKB = ( entry.size_bytes / 1024 ).toFixed( 1 );
const postIdCell = entry.post_id const postIdCell = entry.post_id
? '<a href="' + entry.edit_url + '">#' + entry.post_id + '</a>' ? '<a href="' + entry.edit_url + '">#' + entry.post_id + '</a>'
@@ -272,9 +312,12 @@
const bitrateSuffix = entry.bitrate ? ' &middot; ' + entry.bitrate : ''; const bitrateSuffix = entry.bitrate ? ' &middot; ' + entry.bitrate : '';
const formatBadge = entry.orphaned const formatBadge = entry.orphaned
? '<span class="piperless-cache-badge piperless-cache-badge--orphan">—</span>' ? '<span class="piperless-cache-badge piperless-cache-badge--orphan">—</span>'
: ( entry.has_mp3 : ( entry.has_opus
? '<span class="piperless-cache-badge piperless-cache-badge--ok">MP3' + bitrateSuffix + '</span>' ? '<span class="piperless-cache-badge piperless-cache-badge--opus">Opus' + bitrateSuffix + '</span>'
: '<span class="piperless-cache-badge piperless-cache-badge--wav">WAV only</span>' : ( entry.has_mp3
? '<span class="piperless-cache-badge piperless-cache-badge--ok">MP3' + bitrateSuffix + '</span>'
: '<span class="piperless-cache-badge piperless-cache-badge--wav">WAV only</span>'
)
); );
const statusBadge = entry.enabled const statusBadge = entry.enabled
? '<span class="piperless-cache-badge piperless-cache-badge--ok">Enabled</span>' ? '<span class="piperless-cache-badge piperless-cache-badge--ok">Enabled</span>'
@@ -300,18 +343,9 @@
html += '</tbody></table>'; html += '</tbody></table>';
// Pagination. // ── Pagination bar (bottom) ──
if ( d.pages > 1 ) { if ( paginationHtml ) {
html += '<div class="tablenav"><div class="tablenav-pages">'; html += paginationHtml;
html += '<span class="displaying-num">' + d.total + ' items</span>';
for ( let i = 1; i <= d.pages; i++ ) {
if ( i === cachePage ) {
html += '<span class="page-numbers current">' + i + '</span>';
} else {
html += '<a href="#" class="page-numbers piperless-cache-page" data-page="' + i + '">' + i + '</a>';
}
}
html += '</div></div>';
} }
} }
+11 -3
View File
@@ -53,6 +53,7 @@
const [ generating, setGenerating ] = useState( false ); const [ generating, setGenerating ] = useState( false );
const [ audioUrl, setAudioUrl ] = useState( null ); const [ audioUrl, setAudioUrl ] = useState( null );
const [ audioFormat, setAudioFormat ] = useState( 'mp3' );
const [ audioDuration, setAudioDuration ] = useState( null ); const [ audioDuration, setAudioDuration ] = useState( null );
const [ models, setModels ] = useState( [] ); const [ models, setModels ] = useState( [] );
const [ voices, setVoices ] = useState( [] ); const [ voices, setVoices ] = useState( [] );
@@ -70,6 +71,7 @@
.then( function ( data ) { .then( function ( data ) {
if ( data.has_audio ) { if ( data.has_audio ) {
setAudioUrl( data.url ); setAudioUrl( data.url );
setAudioFormat( data.format || 'mp3' );
setAudioDuration( data.duration ); setAudioDuration( data.duration );
} }
} ) } )
@@ -108,6 +110,7 @@
} ) } )
.then( function ( data ) { .then( function ( data ) {
setAudioUrl( data.url ); setAudioUrl( data.url );
setAudioFormat( data.format || 'mp3' );
setAudioDuration( data.duration ); setAudioDuration( data.duration );
setGenerating( false ); setGenerating( false );
createNotice( 'success', piperlessEditor.i18n.success, { createNotice( 'success', piperlessEditor.i18n.success, {
@@ -243,7 +246,7 @@
placeholder: '1.0', placeholder: '1.0',
value: postMeta._piperless_length_scale || '', value: postMeta._piperless_length_scale || '',
onChange: function ( val ) { updateMeta( '_piperless_length_scale', val ); }, onChange: function ( val ) { updateMeta( '_piperless_length_scale', val ); },
} ) } ),
), ),
// ── Display Settings ──────────────────────────────────────── // ── Display Settings ────────────────────────────────────────
createElement( createElement(
@@ -283,9 +286,14 @@
? createElement( 'div', null, ? createElement( 'div', null,
createElement( 'audio', { createElement( 'audio', {
controls: true, controls: true,
src: audioUrl,
style: { width: '100%', marginBottom: '8px' }, style: { width: '100%', marginBottom: '8px' },
}, piperlessEditor.i18n.noAudio ), },
createElement( 'source', {
src: audioUrl,
type: audioFormat === 'opus' ? 'audio/ogg' : 'audio/mpeg',
} ),
piperlessEditor.i18n.noAudio
),
audioDuration && createElement( 'p', { audioDuration && createElement( 'p', {
style: { color: '#757575', fontSize: '12px' }, style: { color: '#757575', fontSize: '12px' },
}, piperlessEditor.i18n.duration + ' ' + formatDuration( audioDuration ) ) }, piperlessEditor.i18n.duration + ' ' + formatDuration( audioDuration ) )
+96 -37
View File
@@ -79,11 +79,14 @@ class Cache_Manager {
* @param string $quality Quality tier. * @param string $quality Quality tier.
* @return string SHA-256 hash. * @return string SHA-256 hash.
*/ */
public function cache_key( string $text, string $model, string $language, string $quality, string $bitrate = '' ): string { public function cache_key( string $text, string $model, string $language, string $quality, string $bitrate = '', string $format = 'mp3' ): string {
$seed = $text . '|' . $model . '|' . $language . '|' . $quality; $seed = $text . '|' . $model . '|' . $language . '|' . $quality;
if ( '' !== $bitrate ) { if ( '' !== $bitrate ) {
$seed .= '|br:' . $bitrate; $seed .= '|br:' . $bitrate;
} }
if ( '' !== $format ) {
$seed .= '|fmt:' . $format;
}
return hash( 'sha256', $seed ); return hash( 'sha256', $seed );
} }
@@ -94,7 +97,12 @@ class Cache_Manager {
* @return bool * @return bool
*/ */
public function exists( string $cache_key ): bool { public function exists( string $cache_key ): bool {
return file_exists( $this->file_path( $cache_key ) ); $settings = get_option( 'piperless_settings', [] );
$format = $settings['piper_audio_format'] ?? 'mp3';
return file_exists( $this->file_path( $cache_key, $format ) )
|| file_exists( $this->file_path( $cache_key, 'mp3' ) )
|| file_exists( $this->file_path( $cache_key, 'opus' ) )
|| file_exists( $this->cache_dir . '/' . $cache_key . '.wav' );
} }
/** /**
@@ -103,8 +111,8 @@ class Cache_Manager {
* @param string $cache_key Cache key. * @param string $cache_key Cache key.
* @return string * @return string
*/ */
public function file_path( string $cache_key ): string { public function file_path( string $cache_key, string $format = 'mp3' ): string {
return $this->cache_dir . '/' . $cache_key . '.mp3'; return $this->cache_dir . '/' . $cache_key . '.' . $format;
} }
/** /**
@@ -127,9 +135,13 @@ class Cache_Manager {
public function put( string $cache_key, string $data ): bool { public function put( string $cache_key, string $data ): bool {
$settings = get_option( 'piperless_settings', [] ); $settings = get_option( 'piperless_settings', [] );
$ffmpeg = $this->find_ffmpeg(); $ffmpeg = $this->find_ffmpeg();
$format = $settings['piper_audio_format'] ?? 'mp3';
$bitrate = ( 'opus' === $format )
? ( $settings['piper_opus_bitrate'] ?? '24k' )
: ( $settings['piper_mp3_bitrate'] ?? '32k' );
if ( null !== $ffmpeg ) { if ( null !== $ffmpeg ) {
// Write WAV to temp, convert to MP3, store MP3. // Write WAV to temp, convert to selected format.
$wav_tmp = tempnam( sys_get_temp_dir(), 'piperless_' ) . '.wav'; $wav_tmp = tempnam( sys_get_temp_dir(), 'piperless_' ) . '.wav';
error_clear_last(); error_clear_last();
@@ -139,30 +151,41 @@ class Cache_Manager {
return false; return false;
} }
$mp3_path = $this->file_path( $cache_key ); $out_path = $this->file_path( $cache_key, $format );
$bitrate = $settings['piper_mp3_bitrate'] ?? '32k';
$cmd = sprintf( if ( 'opus' === $format ) {
'%s -i %s -codec:a libmp3lame -b:a %s -ac 1 -y %s 2>&1', $cmd = sprintf(
escapeshellarg( $ffmpeg ), '%s -i %s -c:a libopus -b:a %s -ac 1 -application voip -y %s 2>&1',
escapeshellarg( $wav_tmp ), escapeshellarg( $ffmpeg ),
escapeshellarg( $bitrate ), escapeshellarg( $wav_tmp ),
escapeshellarg( $mp3_path ) escapeshellarg( $bitrate ),
); escapeshellarg( $out_path )
);
} else {
$cmd = sprintf(
'%s -i %s -codec:a libmp3lame -b:a %s -ac 1 -y %s 2>&1',
escapeshellarg( $ffmpeg ),
escapeshellarg( $wav_tmp ),
escapeshellarg( $bitrate ),
escapeshellarg( $out_path )
);
}
$output = []; $output = [];
$ret = 0; $ret = 0;
exec( $cmd, $output, $ret ); exec( $cmd, $output, $ret );
@unlink( $wav_tmp ); @unlink( $wav_tmp );
if ( 0 === $ret && file_exists( $mp3_path ) && filesize( $mp3_path ) > 0 ) { if ( 0 === $ret && file_exists( $out_path ) && filesize( $out_path ) > 0 ) {
$this->logger->info( 'Cached MP3: {key} ({size} bytes)', [ $format_label = strtoupper( $format );
$this->logger->info( "Cached {$format_label}: {key} ({size} bytes)", [
'key' => $cache_key, 'key' => $cache_key,
'size' => filesize( $mp3_path ), 'size' => filesize( $out_path ),
] ); ] );
return true; return true;
} }
$this->logger->error( 'ffmpeg conversion failed for {key}, code {code}', [ $this->logger->error( "ffmpeg {$format} conversion failed for {key}, code {code}", [
'key' => $cache_key, 'key' => $cache_key,
'code' => $ret, 'code' => $ret,
] ); ] );
@@ -215,7 +238,7 @@ class Cache_Manager {
$deleted = false; $deleted = false;
// Delete MP3. // Delete MP3.
$mp3_path = $this->file_path( $cache_key ); $mp3_path = $this->file_path( $cache_key, 'mp3' );
if ( file_exists( $mp3_path ) ) { if ( file_exists( $mp3_path ) ) {
if ( @unlink( $mp3_path ) ) { if ( @unlink( $mp3_path ) ) {
$deleted = true; $deleted = true;
@@ -224,6 +247,14 @@ class Cache_Manager {
} }
} }
// Delete Opus.
$opus_path = $this->file_path( $cache_key, 'opus' );
if ( file_exists( $opus_path ) ) {
if ( @unlink( $opus_path ) ) {
$deleted = true;
}
}
// Also delete legacy WAV. // Also delete legacy WAV.
$wav_path = $this->cache_dir . '/' . $cache_key . '.wav'; $wav_path = $this->cache_dir . '/' . $cache_key . '.wav';
if ( file_exists( $wav_path ) ) { if ( file_exists( $wav_path ) ) {
@@ -263,6 +294,14 @@ class Cache_Manager {
} }
} }
// Delete Opus files.
$opus_files = glob( $this->cache_dir . '/*.opus' );
if ( false !== $opus_files ) {
foreach ( $opus_files as $file ) {
if ( @unlink( $file ) ) { $count++; }
}
}
// Also clean up any legacy WAV files. // Also clean up any legacy WAV files.
$wav_files = glob( $this->cache_dir . '/*.wav' ); $wav_files = glob( $this->cache_dir . '/*.wav' );
if ( false !== $wav_files ) { if ( false !== $wav_files ) {
@@ -314,16 +353,12 @@ class Cache_Manager {
// "orphaned audio" in the user-facing sense. // "orphaned audio" in the user-facing sense.
$preview_patterns = [ 'model_preview_*', 'piperless_test_preview*' ]; $preview_patterns = [ 'model_preview_*', 'piperless_test_preview*' ];
foreach ( $preview_patterns as $pattern ) { foreach ( $preview_patterns as $pattern ) {
$preview_files = glob( $this->cache_dir . '/' . $pattern . '.mp3' ); foreach ( [ '.mp3', '.opus', '.wav' ] as $ext ) {
if ( false !== $preview_files ) { $matches = glob( $this->cache_dir . '/' . $pattern . $ext );
foreach ( $preview_files as $file ) { if ( false !== $matches ) {
@unlink( $file ); foreach ( $matches as $file ) {
} @unlink( $file );
} }
$preview_wavs = glob( $this->cache_dir . '/' . $pattern . '.wav' );
if ( false !== $preview_wavs ) {
foreach ( $preview_wavs as $file ) {
@unlink( $file );
} }
} }
} }
@@ -347,12 +382,13 @@ class Cache_Manager {
$all_files = array_merge( $all_files = array_merge(
(array) glob( $this->cache_dir . '/*.mp3' ), (array) glob( $this->cache_dir . '/*.mp3' ),
(array) glob( $this->cache_dir . '/*.opus' ),
(array) glob( $this->cache_dir . '/*.wav' ) (array) glob( $this->cache_dir . '/*.wav' )
); );
foreach ( $all_files as $file ) { foreach ( $all_files as $file ) {
$key = basename( $file ); $key = basename( $file );
$key = str_replace( [ '.mp3', '.wav' ], '', $key ); $key = str_replace( [ '.mp3', '.opus', '.wav' ], '', $key );
if ( str_starts_with( $key, 'model_preview_' ) || str_starts_with( $key, 'piperless_test_preview' ) ) { if ( str_starts_with( $key, 'model_preview_' ) || str_starts_with( $key, 'piperless_test_preview' ) ) {
continue; continue;
} }
@@ -384,7 +420,7 @@ class Cache_Manager {
* *
* @return string|null * @return string|null
*/ */
private function find_ffmpeg(): ?string { public function find_ffmpeg(): ?string {
static $cached = null; static $cached = null;
static $resolved_path = null; static $resolved_path = null;
@@ -400,6 +436,10 @@ class Cache_Manager {
$custom = $settings['piper_ffmpeg_binary'] ?? ''; $custom = $settings['piper_ffmpeg_binary'] ?? '';
if ( '' !== $custom ) { if ( '' !== $custom ) {
// Support both full binary path and directory-only path.
if ( @is_dir( $custom ) ) {
$custom = rtrim( $custom, '/' ) . '/ffmpeg';
}
if ( @file_exists( $custom ) && @is_executable( $custom ) ) { if ( @file_exists( $custom ) && @is_executable( $custom ) ) {
$cached = true; $cached = true;
$resolved_path = $custom; $resolved_path = $custom;
@@ -440,7 +480,7 @@ class Cache_Manager {
* @param int $per_page Entries per page. * @param int $per_page Entries per page.
* @return array{entries:array,total:int,pages:int} * @return array{entries:array,total:int,pages:int}
*/ */
public function get_entries( int $page = 1, int $per_page = 20 ): array { public function get_entries( int $page = 1, int $per_page = 20, string $sort_by = 'created', bool $sort_asc = false ): array {
if ( ! is_dir( $this->cache_dir ) ) { if ( ! is_dir( $this->cache_dir ) ) {
return [ 'entries' => [], 'total' => 0, 'pages' => 0 ]; return [ 'entries' => [], 'total' => 0, 'pages' => 0 ];
} }
@@ -480,9 +520,10 @@ class Cache_Manager {
) )
); );
// Scan both MP3 and legacy WAV files. // Scan MP3, Opus, and legacy WAV files.
$all_files = array_merge( $all_files = array_merge(
(array) glob( $this->cache_dir . '/*.mp3' ), (array) glob( $this->cache_dir . '/*.mp3' ),
(array) glob( $this->cache_dir . '/*.opus' ),
(array) glob( $this->cache_dir . '/*.wav' ) (array) glob( $this->cache_dir . '/*.wav' )
); );
@@ -513,9 +554,10 @@ class Cache_Manager {
$size_bytes = filesize( $path ); $size_bytes = filesize( $path );
$is_mp3 = ( 'mp3' === $ext ); $is_mp3 = ( 'mp3' === $ext );
// Check for the companion format. // Check for companion formats.
$has_mp3 = $is_mp3 || file_exists( $this->cache_dir . '/' . $key . '.mp3' ); $has_mp3 = $is_mp3 || file_exists( $this->cache_dir . '/' . $key . '.mp3' );
$has_wav = ( ! $is_mp3 ) || file_exists( $this->cache_dir . '/' . $key . '.wav' ); $has_opus = ( 'opus' === $ext ) || file_exists( $this->cache_dir . '/' . $key . '.opus' );
$has_wav = file_exists( $this->cache_dir . '/' . $key . '.wav' );
// Check if this entry is the active audio for its post. // Check if this entry is the active audio for its post.
$enabled = false; $enabled = false;
@@ -533,7 +575,9 @@ class Cache_Manager {
'filename' => basename( $path ), 'filename' => basename( $path ),
'size_bytes' => $size_bytes, 'size_bytes' => $size_bytes,
'has_mp3' => $has_mp3, 'has_mp3' => $has_mp3,
'bitrate' => $has_mp3 ? ( $settings['piper_mp3_bitrate'] ?? '32k' ) : '', 'has_opus' => $has_opus,
'bitrate' => $has_opus ? ( $settings['piper_opus_bitrate'] ?? '24k' )
: ( $has_mp3 ? ( $settings['piper_mp3_bitrate'] ?? '32k' ) : '' ),
'created' => $mtime ? gmdate( 'Y-m-d H:i', $mtime ) : '', 'created' => $mtime ? gmdate( 'Y-m-d H:i', $mtime ) : '',
'enabled' => $enabled, 'enabled' => $enabled,
'model' => $model, 'model' => $model,
@@ -545,6 +589,21 @@ class Cache_Manager {
]; ];
} }
// ── Sort before pagination ──────────────────────────────
if ( 'size' === $sort_by ) {
usort( $entries, function ( $a, $b ) use ( $sort_asc ) {
return $sort_asc
? ( ( $a['size_bytes'] ?? 0 ) <=> ( $b['size_bytes'] ?? 0 ) )
: ( ( $b['size_bytes'] ?? 0 ) <=> ( $a['size_bytes'] ?? 0 ) );
} );
} else {
usort( $entries, function ( $a, $b ) use ( $sort_asc ) {
return $sort_asc
? ( $a['created'] ?? '' ) <=> ( $b['created'] ?? '' )
: ( $b['created'] ?? '' ) <=> ( $a['created'] ?? '' );
} );
}
$total = count( $entries ); $total = count( $entries );
$pages = (int) ceil( $total / max( 1, $per_page ) ); $pages = (int) ceil( $total / max( 1, $per_page ) );
$page = max( 1, min( $page, max( 1, $pages ) ) ); $page = max( 1, min( $page, max( 1, $pages ) ) );
+15 -5
View File
@@ -365,6 +365,7 @@ class Gutenberg {
return rest_ensure_response( [ return rest_ensure_response( [
'url' => $result['url'], 'url' => $result['url'],
'duration' => get_post_meta( $post_id, '_piperless_duration', true ), 'duration' => get_post_meta( $post_id, '_piperless_duration', true ),
'format' => get_post_meta( $post_id, '_piperless_audio_format', true ) ?: 'mp3',
] ); ] );
} }
@@ -504,16 +505,25 @@ class Gutenberg {
set_transient( $rate_key, $rate_count + 1, 60 ); set_transient( $rate_key, $rate_count + 1, 60 );
// Try MP3 first (canonical format). // Try configured format first, then MP3, then Opus, fall back to WAV.
$mp3_path = $this->cache->file_path( $cache_key ); $settings = get_option( 'piperless_settings', [] );
$audio_format = $settings['piper_audio_format'] ?? 'mp3';
if ( file_exists( $mp3_path ) ) { // Try the configured format.
return $this->stream_file( $mp3_path, 'audio/mpeg' ); $format_path = $this->cache->file_path( $cache_key, $audio_format );
if ( file_exists( $format_path ) ) {
return $this->stream_file( $format_path, 'opus' === $audio_format ? 'audio/ogg' : 'audio/mpeg' );
}
// Try the other format.
$alt_format = ( 'opus' === $audio_format ) ? 'mp3' : 'opus';
$alt_path = $this->cache->file_path( $cache_key, $alt_format );
if ( file_exists( $alt_path ) ) {
return $this->stream_file( $alt_path, 'opus' === $alt_format ? 'audio/ogg' : 'audio/mpeg' );
} }
// Fall back to legacy WAV. // Fall back to legacy WAV.
$wav_path = $this->cache->dir() . '/' . $cache_key . '.wav'; $wav_path = $this->cache->dir() . '/' . $cache_key . '.wav';
if ( ! file_exists( $wav_path ) ) { if ( ! file_exists( $wav_path ) ) {
return new \WP_Error( 'not_found', __( 'Audio file not found.', 'piperless' ), [ 'status' => 404 ] ); return new \WP_Error( 'not_found', __( 'Audio file not found.', 'piperless' ), [ 'status' => 404 ] );
} }
+56 -3
View File
@@ -184,8 +184,8 @@ class Settings {
], ],
], $this->page_slug_piper ); ], $this->page_slug_piper );
$this->add_field( 'piper_ffmpeg_binary', __( 'FFmpeg Binary Path', 'piperless' ), 'text', 'piperless_piper_section', [ $this->add_field( 'piper_ffmpeg_binary', __( 'FFmpeg Binaries Path', 'piperless' ), 'text', 'piperless_piper_section', [
'description' => __( 'Absolute path to ffmpeg for MP3 conversion. Auto-detected from common paths if left empty.', 'piperless' ), 'description' => __( 'Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.', 'piperless' ),
], $this->page_slug_piper ); ], $this->page_slug_piper );
$this->add_field( 'piper_mp3_bitrate', __( 'MP3 Bitrate', 'piperless' ), 'select', 'piperless_piper_section', [ $this->add_field( 'piper_mp3_bitrate', __( 'MP3 Bitrate', 'piperless' ), 'select', 'piperless_piper_section', [
@@ -196,6 +196,23 @@ class Settings {
], ],
], $this->page_slug_piper ); ], $this->page_slug_piper );
$this->add_field( 'piper_audio_format', __( 'Audio Format', 'piperless' ), 'select', 'piperless_piper_section', [
'description' => __( 'Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.', 'piperless' ),
'options' => [
'mp3' => 'MP3',
'opus' => 'Opus',
],
], $this->page_slug_piper );
$this->add_field( 'piper_opus_bitrate', __( 'Opus Bitrate', 'piperless' ), 'select', 'piperless_piper_section', [
'description' => __( 'Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.', 'piperless' ),
'options' => [
'24k' => __( '24 kbps (standard)', 'piperless' ),
'16k' => __( '16 kbps (compact)', 'piperless' ),
'12k' => __( '12 kbps (minimal)', 'piperless' ),
],
], $this->page_slug_piper );
$this->add_field( 'piper_sentence_silence', __( 'Sentence Silence', 'piperless' ), 'text', 'piperless_piper_section', [ $this->add_field( 'piper_sentence_silence', __( 'Sentence Silence', 'piperless' ), 'text', 'piperless_piper_section', [
'description' => __( 'Adds silence after each sentence, in seconds (e.g. 0.2, 0.5). Leave empty for Piper default. Applies to Standard mode only.', 'piperless' ), 'description' => __( 'Adds silence after each sentence, in seconds (e.g. 0.2, 0.5). Leave empty for Piper default. Applies to Standard mode only.', 'piperless' ),
], $this->page_slug_piper ); ], $this->page_slug_piper );
@@ -453,6 +470,10 @@ class Settings {
$clean['default_quality'] = sanitize_text_field( $input['default_quality'] ?? 'medium' ); $clean['default_quality'] = sanitize_text_field( $input['default_quality'] ?? 'medium' );
$clean['piper_ffmpeg_binary'] = sanitize_text_field( $input['piper_ffmpeg_binary'] ?? '' ); $clean['piper_ffmpeg_binary'] = sanitize_text_field( $input['piper_ffmpeg_binary'] ?? '' );
$clean['piper_mp3_bitrate'] = sanitize_text_field( $input['piper_mp3_bitrate'] ?? '32k' ); $clean['piper_mp3_bitrate'] = sanitize_text_field( $input['piper_mp3_bitrate'] ?? '32k' );
$clean['piper_audio_format'] = in_array( $input['piper_audio_format'] ?? 'mp3', [ 'mp3', 'opus' ], true )
? $input['piper_audio_format'] : 'mp3';
$clean['piper_opus_bitrate'] = in_array( $input['piper_opus_bitrate'] ?? '24k', [ '24k', '16k', '12k' ], true )
? $input['piper_opus_bitrate'] : '24k';
$clean['piper_sentence_silence'] = sanitize_text_field( $input['piper_sentence_silence'] ?? '' ); $clean['piper_sentence_silence'] = sanitize_text_field( $input['piper_sentence_silence'] ?? '' );
$clean['piper_length_scale'] = sanitize_text_field( $input['piper_length_scale'] ?? '' ); $clean['piper_length_scale'] = sanitize_text_field( $input['piper_length_scale'] ?? '' );
$clean['player_style'] = sanitize_text_field( $input['player_style'] ?? 'classic' ); $clean['player_style'] = sanitize_text_field( $input['player_style'] ?? 'classic' );
@@ -863,8 +884,10 @@ class Settings {
$page = max( 1, (int) ( $_POST['page'] ?? 1 ) ); $page = max( 1, (int) ( $_POST['page'] ?? 1 ) );
$per_page = max( 5, min( 50, (int) ( $_POST['per_page'] ?? 20 ) ) ); $per_page = max( 5, min( 50, (int) ( $_POST['per_page'] ?? 20 ) ) );
$sort_by = in_array( $_POST['sort_by'] ?? 'created', [ 'created', 'size' ], true ) ? $_POST['sort_by'] : 'created';
$sort_asc = ( 'asc' === ( $_POST['sort_order'] ?? 'desc' ) );
wp_send_json_success( $this->cache->get_entries( $page, $per_page ) ); wp_send_json_success( $this->cache->get_entries( $page, $per_page, $sort_by, $sort_asc ) );
} }
/** /**
@@ -884,6 +907,36 @@ class Settings {
} }
$deleted = $this->cache->delete_entry( $key ); $deleted = $this->cache->delete_entry( $key );
// Clear post meta if this entry was linked to a post.
if ( $deleted ) {
global $wpdb;
$rows = $wpdb->get_results( $wpdb->prepare(
"SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s",
'_piperless_cache_key'
) );
foreach ( $rows as $row ) {
$keys = maybe_unserialize( $row->meta_value );
$owns = false;
if ( is_array( $keys ) ) {
$owns = array_key_exists( $key, $keys );
} elseif ( is_string( $keys ) ) {
$owns = ( $keys === $key );
}
if ( $owns ) {
delete_post_meta( (int) $row->post_id, '_piperless_audio_url' );
delete_post_meta( (int) $row->post_id, '_piperless_cache_key' );
delete_post_meta( (int) $row->post_id, '_piperless_duration' );
delete_post_meta( (int) $row->post_id, '_piperless_model_name' );
delete_post_meta( (int) $row->post_id, '_piperless_generated_at' );
delete_post_meta( (int) $row->post_id, '_piperless_audio_format' );
break;
}
}
}
wp_send_json_success( [ 'deleted' => $deleted ] ); wp_send_json_success( [ 'deleted' => $deleted ] );
} }
+106 -5
View File
@@ -132,9 +132,11 @@ class Transcriber {
return $this->error( __( 'No text content available for this post.', 'piperless' ) ); return $this->error( __( 'No text content available for this post.', 'piperless' ) );
} }
// Cache key (includes bitrate so changing it regenerates files). // Cache key (includes bitrate and format so changing them regenerates files).
$bitrate = get_option( 'piperless_settings', [] )['piper_mp3_bitrate'] ?? '32k'; $settings_cache = get_option( 'piperless_settings', [] );
$cache_key = $this->cache->cache_key( $text, $model, $language, $quality, $bitrate ); $bitrate = $settings_cache['piper_mp3_bitrate'] ?? '32k';
$audio_format = $settings_cache['piper_audio_format'] ?? 'mp3';
$cache_key = $this->cache->cache_key( $text, $model, $language, $quality, $bitrate, $audio_format );
// Store cache key in post meta before generation so it is tracked. // Store cache key in post meta before generation so it is tracked.
$model_basename = basename( $model, '.onnx' ); $model_basename = basename( $model, '.onnx' );
@@ -211,11 +213,14 @@ class Transcriber {
$duration = get_post_meta( $post_id, '_piperless_duration', true ); $duration = get_post_meta( $post_id, '_piperless_duration', true );
$cache_key = get_post_meta( $post_id, '_piperless_cache_key', true ); $cache_key = get_post_meta( $post_id, '_piperless_cache_key', true );
$format = get_post_meta( $post_id, '_piperless_audio_format', true );
return [ return [
'has_audio' => ! empty( $url ), 'has_audio' => ! empty( $url ),
'url' => $url ?: null, 'url' => $url ?: null,
'duration' => $duration ? (float) $duration : null, 'duration' => $duration ? (float) $duration : null,
'cache_key' => $cache_key ?: null, 'cache_key' => $cache_key ?: null,
'format' => $format ?: 'mp3',
]; ];
} }
@@ -376,6 +381,10 @@ class Transcriber {
update_post_meta( $post_id, '_piperless_duration', $duration ); update_post_meta( $post_id, '_piperless_duration', $duration );
update_post_meta( $post_id, '_piperless_generated_at', current_time( 'mysql', true ) ); update_post_meta( $post_id, '_piperless_generated_at', current_time( 'mysql', true ) );
// Store the audio format for the sidebar preview player.
$settings = get_option( 'piperless_settings', [] );
update_post_meta( $post_id, '_piperless_audio_format', $settings['piper_audio_format'] ?? 'mp3' );
if ( '' !== $model_basename ) { if ( '' !== $model_basename ) {
update_post_meta( $post_id, '_piperless_model_name', $model_basename ); update_post_meta( $post_id, '_piperless_model_name', $model_basename );
} }
@@ -388,15 +397,37 @@ class Transcriber {
* @return float Duration in seconds. * @return float Duration in seconds.
*/ */
public function wav_duration( string $cache_key ): float { public function wav_duration( string $cache_key ): float {
$file_path = $this->cache->file_path( $cache_key ); // Try compressed formats first via ffprobe.
$settings = get_option( 'piperless_settings', [] );
$format = $settings['piper_audio_format'] ?? 'mp3';
$path = $this->cache->file_path( $cache_key, $format );
if ( file_exists( $path ) ) {
$dur = $this->ffprobe_duration( $path );
if ( $dur > 0.0 ) {
return $dur;
}
}
// Fall back to WAV header reading.
$file_path = $this->cache->file_path( $cache_key, 'mp3' );
if ( ! file_exists( $file_path ) ) {
$file_path = $this->cache->file_path( $cache_key, 'opus' );
}
if ( ! file_exists( $file_path ) ) { if ( ! file_exists( $file_path ) ) {
// Try legacy WAV path.
$file_path = $this->cache->dir() . '/' . $cache_key . '.wav'; $file_path = $this->cache->dir() . '/' . $cache_key . '.wav';
} }
if ( ! file_exists( $file_path ) ) { if ( ! file_exists( $file_path ) ) {
return 0.0; return 0.0;
} }
// If not WAV, try ffprobe.
if ( ! str_ends_with( $file_path, '.wav' ) ) {
$dur = $this->ffprobe_duration( $file_path );
if ( $dur > 0.0 ) {
return $dur;
}
}
$fp = @fopen( $file_path, 'rb' ); $fp = @fopen( $file_path, 'rb' );
if ( false === $fp ) { if ( false === $fp ) {
return 0.0; return 0.0;
@@ -455,4 +486,74 @@ class Transcriber {
'error' => $message, 'error' => $message,
]; ];
} }
/**
* Get audio duration using ffprobe.
*
* @param string $file_path Absolute path to the audio file.
* @return float Duration in seconds, or 0.0 on failure.
*/
private function ffprobe_duration( string $file_path ): float {
$ffprobe = $this->find_ffprobe();
if ( null === $ffprobe ) {
return 0.0;
}
$cmd = sprintf(
'%s -v error -show_entries format=duration -of csv=p=0 %s 2>&1',
escapeshellarg( $ffprobe ),
escapeshellarg( $file_path )
);
$output = [];
$ret = 0;
exec( $cmd, $output, $ret );
if ( 0 !== $ret || empty( $output ) ) {
return 0.0;
}
return (float) trim( $output[0] );
}
/**
* Find ffprobe binary on the system.
*
* @return string|null Absolute path, or null.
*/
private function find_ffprobe(): ?string {
static $cached = null;
static $resolved = null;
if ( null !== $cached ) {
return $resolved;
}
$cached = true;
// Use the same directory as ffmpeg — wherever it was resolved,
// ffprobe is likely right next to it.
$ffmpeg_path = $this->cache->find_ffmpeg();
if ( null !== $ffmpeg_path ) {
$candidate = dirname( $ffmpeg_path ) . '/ffprobe';
if ( @is_executable( $candidate ) ) {
$resolved = $candidate;
return $resolved;
}
}
// Fallback: common paths extended via filter.
$candidates = apply_filters(
'piperless_ffprobe_paths',
[ '/usr/bin/ffprobe', '/usr/local/bin/ffprobe', '/opt/bin/ffprobe' ]
);
foreach ( $candidates as $candidate ) {
if ( @is_executable( $candidate ) ) {
$resolved = $candidate;
return $resolved;
}
}
return null;
}
} }
+20 -5
View File
@@ -2,9 +2,9 @@
"_meta": { "_meta": {
"locale": "de_DE", "locale": "de_DE",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-09", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "Cache-Verwaltung", "Cache Management": "Cache-Verwaltung",
"Cache flushed.": "Cache geleert.", "Cache flushed.": "Cache geleert.",
"Choose a visual theme for the audio player.": "Wähle ein visuelles Thema für den Audioplayer.", "Choose a visual theme for the audio player.": "Wähle ein visuelles Thema für den Audioplayer.",
"Chunk Silence": "Pausenlänge",
"Chunked — pre-split text at sentence boundaries for better pacing": "Segmentiert — Text vorab an Satzgrenzen aufteilen",
"Classic": "Klassisch", "Classic": "Klassisch",
"Clear Log": "Log löschen", "Clear Log": "Log löschen",
"Clear Orphaned Audio": "Verwaiste Audiodateien löschen", "Clear Orphaned Audio": "Verwaiste Audiodateien löschen",
@@ -95,12 +97,16 @@
"Post not found.": "Beitrag nicht gefunden.", "Post not found.": "Beitrag nicht gefunden.",
"Preview how the selected player style looks with a sample audio clip.": "Vorschau, wie der gewählte Player-Stil mit einem Beispiel-Audioclip aussieht.", "Preview how the selected player style looks with a sample audio clip.": "Vorschau, wie der gewählte Player-Stil mit einem Beispiel-Audioclip aussieht.",
"Quality tier override": "Qualitätsstufen-Überschreibung", "Quality tier override": "Qualitätsstufen-Überschreibung",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "Roh-Modus sendet Text direkt an Piper. Segmentiert-Modus teilt Text zunächst in Sätze auf.",
"Raw — send text as-is to Piper": "Roh — Text unverändert an Piper senden",
"Refresh Log": "Protokoll aktualisieren", "Refresh Log": "Protokoll aktualisieren",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Sekunden Stille zwischen Satzblöcken im Segmentiert-Modus. Standard: 2.0. Bereich: 0.55.0.",
"Show Duration": "Dauer anzeigen", "Show Duration": "Dauer anzeigen",
"Skip Embedded Content": "Eingebettete Inhalte überspringen", "Skip Embedded Content": "Eingebettete Inhalte überspringen",
"Styling": "Styling", "Styling": "Styling",
"Test Connection": "Verbindung testen", "Test Connection": "Verbindung testen",
"Testing…": "Teste…", "Testing…": "Teste…",
"Text Processing": "Textverarbeitung",
"This will delete cache files not referenced by any post.": "Dies löscht Cache-Dateien, die keinem Beitrag zugeordnet sind.", "This will delete cache files not referenced by any post.": "Dies löscht Cache-Dateien, die keinem Beitrag zugeordnet sind.",
"Too many requests. Please try again later.": "Zu viele Anfragen. Bitte versuche es später erneut.", "Too many requests. Please try again later.": "Zu viele Anfragen. Bitte versuche es später erneut.",
"Unsupported post type.": "Nicht unterstützter Beitragstyp.", "Unsupported post type.": "Nicht unterstützter Beitragstyp.",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Beim Zurückfallen auf den Beitragstext (kein Auszug) Text aus eingebetteten Blöcken wie YouTube, Twitter und Drittanbieter-Einbettungen überspringen.", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Beim Zurückfallen auf den Beitragstext (kein Auszug) Text aus eingebetteten Blöcken wie YouTube, Twitter und Drittanbieter-Einbettungen überspringen.",
"Where to insert the audio player relative to the post content.": "Wo der Audioplayer relativ zum Beitragsinhalt eingefügt werden soll.", "Where to insert the audio player relative to the post content.": "Wo der Audioplayer relativ zum Beitragsinhalt eingefügt werden soll.",
"You do not have permission to edit this post.": "Du hast keine Berechtigung, diesen Beitrag zu bearbeiten.", "You do not have permission to edit this post.": "Du hast keine Berechtigung, diesen Beitrag zu bearbeiten.",
"Your browser does not support the audio element.": "Dein Browser unterstützt das Audio-Element nicht." "Your browser does not support the audio element.": "Dein Browser unterstützt das Audio-Element nicht.",
"Audio Format": "Audioformat",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "Ausgabe-Audioformat. MP3 wird universell unterstützt. Opus bietet bessere Qualität bei gleicher Bitrate, hat aber eingeschränktere Browser-Unterstützung.",
"Opus Bitrate": "Opus-Bitrate",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Bitrate für Opus-Kodierung. Opus erreicht gute Qualität bei viel niedrigeren Bitraten als MP3. Mono-Ausgabe.",
"24 kbps (standard)": "24 kbps (Standard)",
"16 kbps (compact)": "16 kbps (Kompakt)",
"12 kbps (minimal)": "12 kbps (Minimal)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "Absoluter Pfad zu den ffmpeg-Tools für MP3/Opus-Konvertierung. Automatische Erkennung aus üblichen Pfaden, wenn leer.",
"FFmpeg Binaries Path": "FFmpeg-Binärpfad"
} }
} }
Binary file not shown.
+52 -1
View File
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Piperless 1.0.0\n" "Project-Id-Version: Piperless 1.0.0\n"
"Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n" "Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n" "POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2026-05-09 00:00+0000\n" "PO-Revision-Date: 2026-05-10 00:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: German <LL@li.org>\n" "Language-Team: German <LL@li.org>\n"
"Language: de_DE\n" "Language: de_DE\n"
@@ -76,6 +76,14 @@ msgstr "Cache geleert."
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "Wähle ein visuelles Thema für den Audioplayer." msgstr "Wähle ein visuelles Thema für den Audioplayer."
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "Pausenlänge"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Segmentiert — Text vorab an Satzgrenzen aufteilen"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "Klassisch" msgstr "Klassisch"
@@ -364,10 +372,22 @@ msgstr "Vorschau, wie der gewählte Player-Stil mit einem Beispiel-Audioclip aus
msgid "Quality tier override" msgid "Quality tier override"
msgstr "Qualitätsstufen-Überschreibung" msgstr "Qualitätsstufen-Überschreibung"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "Roh-Modus sendet Text direkt an Piper. Segmentiert-Modus teilt Text zunächst in Sätze auf."
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Roh — Text unverändert an Piper senden"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "Protokoll aktualisieren" msgstr "Protokoll aktualisieren"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Sekunden Stille zwischen Satzblöcken im Segmentiert-Modus. Standard: 2.0. Bereich: 0.55.0."
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "Dauer anzeigen" msgstr "Dauer anzeigen"
@@ -388,6 +408,10 @@ msgstr "Verbindung testen"
msgid "Testing…" msgid "Testing…"
msgstr "Teste…" msgstr "Teste…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "Textverarbeitung"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "Dies löscht Cache-Dateien, die keinem Beitrag zugeordnet sind." msgstr "Dies löscht Cache-Dateien, die keinem Beitrag zugeordnet sind."
@@ -424,3 +448,30 @@ msgstr "Du hast keine Berechtigung, diesen Beitrag zu bearbeiten."
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "Dein Browser unterstützt das Audio-Element nicht." msgstr "Dein Browser unterstützt das Audio-Element nicht."
msgid "Audio Format"
msgstr "Audioformat"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "Ausgabe-Audioformat. MP3 wird universell unterstützt. Opus bietet bessere Qualität bei gleicher Bitrate, hat aber eingeschränktere Browser-Unterstützung."
msgid "Opus Bitrate"
msgstr "Opus-Bitrate"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Bitrate für Opus-Kodierung. Opus erreicht gute Qualität bei viel niedrigeren Bitraten als MP3. Mono-Ausgabe."
msgid "24 kbps (standard)"
msgstr "24 kbps (Standard)"
msgid "16 kbps (compact)"
msgstr "16 kbps (Kompakt)"
msgid "12 kbps (minimal)"
msgstr "12 kbps (Minimal)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "Absoluter Pfad zu den ffmpeg-Tools für MP3/Opus-Konvertierung. Automatische Erkennung aus üblichen Pfaden, wenn leer."
msgid "FFmpeg Binaries Path"
msgstr "FFmpeg-Binärpfad"
+20 -5
View File
@@ -2,9 +2,9 @@
"_meta": { "_meta": {
"locale": "es_ES", "locale": "es_ES",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-09", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "Gestión de caché", "Cache Management": "Gestión de caché",
"Cache flushed.": "Caché vaciada.", "Cache flushed.": "Caché vaciada.",
"Choose a visual theme for the audio player.": "Elige un tema visual para el reproductor de audio.", "Choose a visual theme for the audio player.": "Elige un tema visual para el reproductor de audio.",
"Chunk Silence": "Silencio entre frases",
"Chunked — pre-split text at sentence boundaries for better pacing": "Segmentado — dividir texto en oraciones",
"Classic": "Clásico", "Classic": "Clásico",
"Clear Log": "Limpiar registro", "Clear Log": "Limpiar registro",
"Clear Orphaned Audio": "Eliminar audio huérfano", "Clear Orphaned Audio": "Eliminar audio huérfano",
@@ -95,12 +97,16 @@
"Post not found.": "Entrada no encontrada.", "Post not found.": "Entrada no encontrada.",
"Preview how the selected player style looks with a sample audio clip.": "Vista previa de cómo se ve el estilo de reproductor seleccionado con un clip de audio de muestra.", "Preview how the selected player style looks with a sample audio clip.": "Vista previa de cómo se ve el estilo de reproductor seleccionado con un clip de audio de muestra.",
"Quality tier override": "Anulación de nivel de calidad", "Quality tier override": "Anulación de nivel de calidad",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "El modo Crudo envía el texto directamente a Piper. El modo Segmentado divide el texto en oraciones.",
"Raw — send text as-is to Piper": "Crudo — enviar texto tal cual a Piper",
"Refresh Log": "Actualizar registro", "Refresh Log": "Actualizar registro",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Segundos de silencio insertados entre bloques de oraciones en modo Segmentado. Predeterminado: 2.0. Rango: 0.55.0.",
"Show Duration": "Mostrar duración", "Show Duration": "Mostrar duración",
"Skip Embedded Content": "Omitir contenido incrustado", "Skip Embedded Content": "Omitir contenido incrustado",
"Styling": "Estilo", "Styling": "Estilo",
"Test Connection": "Probar conexión", "Test Connection": "Probar conexión",
"Testing…": "Probando…", "Testing…": "Probando…",
"Text Processing": "Procesamiento de texto",
"This will delete cache files not referenced by any post.": "Esto eliminará los archivos de caché no referenciados por ninguna entrada.", "This will delete cache files not referenced by any post.": "Esto eliminará los archivos de caché no referenciados por ninguna entrada.",
"Too many requests. Please try again later.": "Demasiadas solicitudes. Por favor inténtalo de nuevo más tarde.", "Too many requests. Please try again later.": "Demasiadas solicitudes. Por favor inténtalo de nuevo más tarde.",
"Unsupported post type.": "Tipo de entrada no soportado.", "Unsupported post type.": "Tipo de entrada no soportado.",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Al recurrir al cuerpo del artículo (sin extracto), omitir el texto de bloques incrustados como YouTube, Twitter e integraciones de terceros.", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Al recurrir al cuerpo del artículo (sin extracto), omitir el texto de bloques incrustados como YouTube, Twitter e integraciones de terceros.",
"Where to insert the audio player relative to the post content.": "Dónde insertar el reproductor de audio en relación con el contenido de la entrada.", "Where to insert the audio player relative to the post content.": "Dónde insertar el reproductor de audio en relación con el contenido de la entrada.",
"You do not have permission to edit this post.": "No tienes permiso para editar este artículo.", "You do not have permission to edit this post.": "No tienes permiso para editar este artículo.",
"Your browser does not support the audio element.": "Tu navegador no soporta el elemento de audio." "Your browser does not support the audio element.": "Tu navegador no soporta el elemento de audio.",
"Audio Format": "Formato de audio",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "Formato de audio de salida. MP3 es compatible universalmente. Opus ofrece mejor calidad a la misma tasa de bits pero tiene un soporte de navegador más limitado.",
"Opus Bitrate": "Bitrate de Opus",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Bitrate para codificación Opus. Opus logra buena calidad a tasas de bits mucho más bajas que MP3. Salida mono.",
"24 kbps (standard)": "24 kbps (estándar)",
"16 kbps (compact)": "16 kbps (compacto)",
"12 kbps (minimal)": "12 kbps (mínimo)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "Ruta absoluta a las herramientas ffmpeg para conversión MP3/Opus. Se detecta automáticamente si se deja vacío.",
"FFmpeg Binaries Path": "Ruta de binarios FFmpeg"
} }
} }
Binary file not shown.
+52 -1
View File
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Piperless 1.0.0\n" "Project-Id-Version: Piperless 1.0.0\n"
"Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n" "Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n" "POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2026-05-09 00:00+0000\n" "PO-Revision-Date: 2026-05-10 00:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Spanish <LL@li.org>\n" "Language-Team: Spanish <LL@li.org>\n"
"Language: es_ES\n" "Language: es_ES\n"
@@ -76,6 +76,14 @@ msgstr "Caché vaciada."
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "Elige un tema visual para el reproductor de audio." msgstr "Elige un tema visual para el reproductor de audio."
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "Silencio entre frases"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Segmentado — dividir texto en oraciones"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "Clásico" msgstr "Clásico"
@@ -364,10 +372,22 @@ msgstr "Vista previa de cómo se ve el estilo de reproductor seleccionado con un
msgid "Quality tier override" msgid "Quality tier override"
msgstr "Anulación de nivel de calidad" msgstr "Anulación de nivel de calidad"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "El modo Crudo envía el texto directamente a Piper. El modo Segmentado divide el texto en oraciones."
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Crudo — enviar texto tal cual a Piper"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "Actualizar registro" msgstr "Actualizar registro"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Segundos de silencio insertados entre bloques de oraciones en modo Segmentado. Predeterminado: 2.0. Rango: 0.55.0."
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "Mostrar duración" msgstr "Mostrar duración"
@@ -388,6 +408,10 @@ msgstr "Probar conexión"
msgid "Testing…" msgid "Testing…"
msgstr "Probando…" msgstr "Probando…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "Procesamiento de texto"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "Esto eliminará los archivos de caché no referenciados por ninguna entrada." msgstr "Esto eliminará los archivos de caché no referenciados por ninguna entrada."
@@ -424,3 +448,30 @@ msgstr "No tienes permiso para editar este artículo."
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "Tu navegador no soporta el elemento de audio." msgstr "Tu navegador no soporta el elemento de audio."
msgid "Audio Format"
msgstr "Formato de audio"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "Formato de audio de salida. MP3 es compatible universalmente. Opus ofrece mejor calidad a la misma tasa de bits pero tiene un soporte de navegador más limitado."
msgid "Opus Bitrate"
msgstr "Bitrate de Opus"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Bitrate para codificación Opus. Opus logra buena calidad a tasas de bits mucho más bajas que MP3. Salida mono."
msgid "24 kbps (standard)"
msgstr "24 kbps (estándar)"
msgid "16 kbps (compact)"
msgstr "16 kbps (compacto)"
msgid "12 kbps (minimal)"
msgstr "12 kbps (mínimo)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "Ruta absoluta a las herramientas ffmpeg para conversión MP3/Opus. Se detecta automáticamente si se deja vacío."
msgid "FFmpeg Binaries Path"
msgstr "Ruta de binarios FFmpeg"
+20 -5
View File
@@ -2,9 +2,9 @@
"_meta": { "_meta": {
"locale": "fr_FR", "locale": "fr_FR",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-09", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "Gestion du cache", "Cache Management": "Gestion du cache",
"Cache flushed.": "Cache vidé.", "Cache flushed.": "Cache vidé.",
"Choose a visual theme for the audio player.": "Choisissez un thème visuel pour le lecteur audio.", "Choose a visual theme for the audio player.": "Choisissez un thème visuel pour le lecteur audio.",
"Chunk Silence": "Silence entre phrases",
"Chunked — pre-split text at sentence boundaries for better pacing": "Segmenté — prédécouper le texte aux limites de phrase",
"Classic": "Classique", "Classic": "Classique",
"Clear Log": "Effacer le journal", "Clear Log": "Effacer le journal",
"Clear Orphaned Audio": "Supprimer les audios orphelins", "Clear Orphaned Audio": "Supprimer les audios orphelins",
@@ -95,12 +97,16 @@
"Post not found.": "Article introuvable.", "Post not found.": "Article introuvable.",
"Preview how the selected player style looks with a sample audio clip.": "Aperçu du style de lecteur sélectionné avec un extrait audio d'exemple.", "Preview how the selected player style looks with a sample audio clip.": "Aperçu du style de lecteur sélectionné avec un extrait audio d'exemple.",
"Quality tier override": "Remplacement du niveau de qualité", "Quality tier override": "Remplacement du niveau de qualité",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "Le mode Brut envoie le texte directement à Piper. Le mode Segmenté divise d'abord le texte en phrases.",
"Raw — send text as-is to Piper": "Brut — envoyer le texte tel quel à Piper",
"Refresh Log": "Actualiser le journal", "Refresh Log": "Actualiser le journal",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Secondes de silence insérées entre les blocs de phrases en mode Segmenté. Défaut : 2.0. Plage : 0.55.0.",
"Show Duration": "Afficher la durée", "Show Duration": "Afficher la durée",
"Skip Embedded Content": "Ignorer le contenu intégré", "Skip Embedded Content": "Ignorer le contenu intégré",
"Styling": "Style", "Styling": "Style",
"Test Connection": "Tester la connexion", "Test Connection": "Tester la connexion",
"Testing…": "Test en cours…", "Testing…": "Test en cours…",
"Text Processing": "Traitement du texte",
"This will delete cache files not referenced by any post.": "Cela supprimera les fichiers cache non référencés par un article.", "This will delete cache files not referenced by any post.": "Cela supprimera les fichiers cache non référencés par un article.",
"Too many requests. Please try again later.": "Trop de requêtes. Veuillez réessayer plus tard.", "Too many requests. Please try again later.": "Trop de requêtes. Veuillez réessayer plus tard.",
"Unsupported post type.": "Type d'article non pris en charge.", "Unsupported post type.": "Type d'article non pris en charge.",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Lors du repli sur le corps de l'article (pas d'extrait), ignorer le texte des blocs intégrés comme YouTube, Twitter et les intégrations tierces.", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Lors du repli sur le corps de l'article (pas d'extrait), ignorer le texte des blocs intégrés comme YouTube, Twitter et les intégrations tierces.",
"Where to insert the audio player relative to the post content.": "Où insérer le lecteur audio par rapport au contenu de l'article.", "Where to insert the audio player relative to the post content.": "Où insérer le lecteur audio par rapport au contenu de l'article.",
"You do not have permission to edit this post.": "Vous n'avez pas l'autorisation de modifier cet article.", "You do not have permission to edit this post.": "Vous n'avez pas l'autorisation de modifier cet article.",
"Your browser does not support the audio element.": "Votre navigateur ne prend pas en charge l'élément audio." "Your browser does not support the audio element.": "Votre navigateur ne prend pas en charge l'élément audio.",
"Audio Format": "Format audio",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "Format audio de sortie. Le MP3 est universellement pris en charge. L'Opus offre une meilleure qualité au même débit mais a une compatibilité navigateur plus limitée.",
"Opus Bitrate": "Débit Opus",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Débit pour l'encodage Opus. Opus atteint une bonne qualité à des débits bien inférieurs au MP3. Sortie mono.",
"24 kbps (standard)": "24 kbps (standard)",
"16 kbps (compact)": "16 kbps (compact)",
"12 kbps (minimal)": "12 kbps (minimal)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "Chemin absolu vers les outils ffmpeg pour la conversion MP3/Opus. Auto-détecté depuis les chemins courants si laissé vide.",
"FFmpeg Binaries Path": "Chemin des binaires FFmpeg"
} }
} }
Binary file not shown.
+52 -1
View File
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Piperless 1.0.0\n" "Project-Id-Version: Piperless 1.0.0\n"
"Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n" "Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n" "POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2026-05-09 00:00+0000\n" "PO-Revision-Date: 2026-05-10 00:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: French <LL@li.org>\n" "Language-Team: French <LL@li.org>\n"
"Language: fr_FR\n" "Language: fr_FR\n"
@@ -76,6 +76,14 @@ msgstr "Cache vidé."
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "Choisissez un thème visuel pour le lecteur audio." msgstr "Choisissez un thème visuel pour le lecteur audio."
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "Silence entre phrases"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Segmenté — prédécouper le texte aux limites de phrase"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "Classique" msgstr "Classique"
@@ -364,10 +372,22 @@ msgstr "Aperçu du style de lecteur sélectionné avec un extrait audio d'exempl
msgid "Quality tier override" msgid "Quality tier override"
msgstr "Remplacement du niveau de qualité" msgstr "Remplacement du niveau de qualité"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "Le mode Brut envoie le texte directement à Piper. Le mode Segmenté divise d'abord le texte en phrases."
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Brut — envoyer le texte tel quel à Piper"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "Actualiser le journal" msgstr "Actualiser le journal"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Secondes de silence insérées entre les blocs de phrases en mode Segmenté. Défaut : 2.0. Plage : 0.55.0."
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "Afficher la durée" msgstr "Afficher la durée"
@@ -388,6 +408,10 @@ msgstr "Tester la connexion"
msgid "Testing…" msgid "Testing…"
msgstr "Test en cours…" msgstr "Test en cours…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "Traitement du texte"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "Cela supprimera les fichiers cache non référencés par un article." msgstr "Cela supprimera les fichiers cache non référencés par un article."
@@ -424,3 +448,30 @@ msgstr "Vous n'avez pas l'autorisation de modifier cet article."
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "Votre navigateur ne prend pas en charge l'élément audio." msgstr "Votre navigateur ne prend pas en charge l'élément audio."
msgid "Audio Format"
msgstr "Format audio"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "Format audio de sortie. Le MP3 est universellement pris en charge. L'Opus offre une meilleure qualité au même débit mais a une compatibilité navigateur plus limitée."
msgid "Opus Bitrate"
msgstr "Débit Opus"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Débit pour l'encodage Opus. Opus atteint une bonne qualité à des débits bien inférieurs au MP3. Sortie mono."
msgid "24 kbps (standard)"
msgstr "24 kbps (standard)"
msgid "16 kbps (compact)"
msgstr "16 kbps (compact)"
msgid "12 kbps (minimal)"
msgstr "12 kbps (minimal)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "Chemin absolu vers les outils ffmpeg pour la conversion MP3/Opus. Auto-détecté depuis les chemins courants si laissé vide."
msgid "FFmpeg Binaries Path"
msgstr "Chemin des binaires FFmpeg"
+18 -3
View File
@@ -3,8 +3,8 @@
"locale": "it_IT", "locale": "it_IT",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-10", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "Gestione cache", "Cache Management": "Gestione cache",
"Cache flushed.": "Cache svuotata.", "Cache flushed.": "Cache svuotata.",
"Choose a visual theme for the audio player.": "Scegli un tema visivo per il lettore audio.", "Choose a visual theme for the audio player.": "Scegli un tema visivo per il lettore audio.",
"Chunk Silence": "Silenzio tra frasi",
"Chunked — pre-split text at sentence boundaries for better pacing": "Segmentato — pre-dividi il testo ai confini delle frasi",
"Classic": "Classico", "Classic": "Classico",
"Clear Log": "Cancella log", "Clear Log": "Cancella log",
"Clear Orphaned Audio": "Rimuovi audio orfani", "Clear Orphaned Audio": "Rimuovi audio orfani",
@@ -95,12 +97,16 @@
"Post not found.": "Post non trovato.", "Post not found.": "Post non trovato.",
"Preview how the selected player style looks with a sample audio clip.": "Anteprima di come appare lo stile del player selezionato con un clip audio di esempio.", "Preview how the selected player style looks with a sample audio clip.": "Anteprima di come appare lo stile del player selezionato con un clip audio di esempio.",
"Quality tier override": "Override del livello di qualità", "Quality tier override": "Override del livello di qualità",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "La modalità Greggio passa il testo direttamente a Piper. La modalità Segmentato divide prima il testo in frasi.",
"Raw — send text as-is to Piper": "Greggio — invia il testo così com'è a Piper",
"Refresh Log": "Aggiorna log", "Refresh Log": "Aggiorna log",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Secondi di silenzio inseriti tra i blocchi di frasi in modalità Segmentato. Predefinito: 2.0. Intervallo: 0.55.0.",
"Show Duration": "Mostra durata", "Show Duration": "Mostra durata",
"Skip Embedded Content": "Salta contenuti incorporati", "Skip Embedded Content": "Salta contenuti incorporati",
"Styling": "Stile", "Styling": "Stile",
"Test Connection": "Test connessione", "Test Connection": "Test connessione",
"Testing…": "Test in corso…", "Testing…": "Test in corso…",
"Text Processing": "Elaborazione del testo",
"This will delete cache files not referenced by any post.": "Questo eliminerà i file di cache non referenziati da alcun post.", "This will delete cache files not referenced by any post.": "Questo eliminerà i file di cache non referenziati da alcun post.",
"Too many requests. Please try again later.": "Troppe richieste. Riprova più tardi.", "Too many requests. Please try again later.": "Troppe richieste. Riprova più tardi.",
"Unsupported post type.": "Tipo di post non supportato.", "Unsupported post type.": "Tipo di post non supportato.",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Quando si utilizza il corpo del post come fallback (nessun estratto), salta il testo da blocchi incorporati come YouTube, Twitter e embed di terze parti.", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Quando si utilizza il corpo del post come fallback (nessun estratto), salta il testo da blocchi incorporati come YouTube, Twitter e embed di terze parti.",
"Where to insert the audio player relative to the post content.": "Dove inserire il player audio rispetto al contenuto del post.", "Where to insert the audio player relative to the post content.": "Dove inserire il player audio rispetto al contenuto del post.",
"You do not have permission to edit this post.": "Non hai il permesso di modificare questo post.", "You do not have permission to edit this post.": "Non hai il permesso di modificare questo post.",
"Your browser does not support the audio element.": "Il tuo browser non supporta l'elemento audio." "Your browser does not support the audio element.": "Il tuo browser non supporta l'elemento audio.",
"Audio Format": "Formato audio",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "Formato audio in uscita. L'MP3 è universalmente supportato. L'Opus offre una qualità migliore allo stesso bitrate ma ha un supporto browser più limitato.",
"Opus Bitrate": "Bitrate Opus",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Bitrate per la codifica Opus. Opus raggiunge una buona qualità a bitrate molto più bassi dell'MP3. Uscita mono.",
"24 kbps (standard)": "24 kbps (standard)",
"16 kbps (compact)": "16 kbps (compatto)",
"12 kbps (minimal)": "12 kbps (minimo)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "Percorso assoluto agli strumenti ffmpeg per la conversione MP3/Opus. Rilevato automaticamente se lasciato vuoto.",
"FFmpeg Binaries Path": "Percorso binari FFmpeg"
} }
} }
Binary file not shown.
+51
View File
@@ -76,6 +76,14 @@ msgstr "Cache svuotata."
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "Scegli un tema visivo per il lettore audio." msgstr "Scegli un tema visivo per il lettore audio."
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "Silenzio tra frasi"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Segmentato — pre-dividi il testo ai confini delle frasi"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "Classico" msgstr "Classico"
@@ -364,10 +372,22 @@ msgstr "Anteprima di come appare lo stile del player selezionato con un clip aud
msgid "Quality tier override" msgid "Quality tier override"
msgstr "Override del livello di qualità" msgstr "Override del livello di qualità"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "La modalità Greggio passa il testo direttamente a Piper. La modalità Segmentato divide prima il testo in frasi."
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Greggio — invia il testo così com'è a Piper"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "Aggiorna log" msgstr "Aggiorna log"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Secondi di silenzio inseriti tra i blocchi di frasi in modalità Segmentato. Predefinito: 2.0. Intervallo: 0.55.0."
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "Mostra durata" msgstr "Mostra durata"
@@ -388,6 +408,10 @@ msgstr "Test connessione"
msgid "Testing…" msgid "Testing…"
msgstr "Test in corso…" msgstr "Test in corso…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "Elaborazione del testo"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "Questo eliminerà i file di cache non referenziati da alcun post." msgstr "Questo eliminerà i file di cache non referenziati da alcun post."
@@ -424,3 +448,30 @@ msgstr "Non hai il permesso di modificare questo post."
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "Il tuo browser non supporta l'elemento audio." msgstr "Il tuo browser non supporta l'elemento audio."
msgid "Audio Format"
msgstr "Formato audio"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "Formato audio in uscita. L'MP3 è universalmente supportato. L'Opus offre una qualità migliore allo stesso bitrate ma ha un supporto browser più limitato."
msgid "Opus Bitrate"
msgstr "Bitrate Opus"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Bitrate per la codifica Opus. Opus raggiunge una buona qualità a bitrate molto più bassi dell'MP3. Uscita mono."
msgid "24 kbps (standard)"
msgstr "24 kbps (standard)"
msgid "16 kbps (compact)"
msgstr "16 kbps (compatto)"
msgid "12 kbps (minimal)"
msgstr "12 kbps (minimo)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "Percorso assoluto agli strumenti ffmpeg per la conversione MP3/Opus. Rilevato automaticamente se lasciato vuoto."
msgid "FFmpeg Binaries Path"
msgstr "Percorso binari FFmpeg"
+18 -3
View File
@@ -3,8 +3,8 @@
"locale": "ja", "locale": "ja",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-10", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "キャッシュ管理", "Cache Management": "キャッシュ管理",
"Cache flushed.": "キャッシュをフラッシュしました。", "Cache flushed.": "キャッシュをフラッシュしました。",
"Choose a visual theme for the audio player.": "オーディオプレーヤーのビジュアルテーマを選択してください。", "Choose a visual theme for the audio player.": "オーディオプレーヤーのビジュアルテーマを選択してください。",
"Chunk Silence": "チャンク間の無音",
"Chunked — pre-split text at sentence boundaries for better pacing": "Chunked — 文の区切りでテキストを分割",
"Classic": "クラシック", "Classic": "クラシック",
"Clear Log": "ログをクリア", "Clear Log": "ログをクリア",
"Clear Orphaned Audio": "孤立したオーディオをクリア", "Clear Orphaned Audio": "孤立したオーディオをクリア",
@@ -95,12 +97,16 @@
"Post not found.": "投稿が見つかりません。", "Post not found.": "投稿が見つかりません。",
"Preview how the selected player style looks with a sample audio clip.": "選択したプレイヤースタイルがサンプルオーディオクリップでどのように見えるかプレビューします。", "Preview how the selected player style looks with a sample audio clip.": "選択したプレイヤースタイルがサンプルオーディオクリップでどのように見えるかプレビューします。",
"Quality tier override": "品質ティアの上書き", "Quality tier override": "品質ティアの上書き",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "Rawモードはテキストを直接Piperに渡します。Chunkedモードは最初にテキストを文に分割します。",
"Raw — send text as-is to Piper": "Raw — テキストをそのままPiperに送信",
"Refresh Log": "ログの更新", "Refresh Log": "ログの更新",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Chunkedモードで文チャンク間に挿入される無音の秒数。デフォルト: 2.0。範囲: 0.55.0。",
"Show Duration": "再生時間を表示", "Show Duration": "再生時間を表示",
"Skip Embedded Content": "埋め込みコンテンツをスキップ", "Skip Embedded Content": "埋め込みコンテンツをスキップ",
"Styling": "スタイリング", "Styling": "スタイリング",
"Test Connection": "接続テスト", "Test Connection": "接続テスト",
"Testing…": "テスト中…", "Testing…": "テスト中…",
"Text Processing": "テキスト処理",
"This will delete cache files not referenced by any post.": "これにより、どの投稿からも参照されていないキャッシュファイルが削除されます。", "This will delete cache files not referenced by any post.": "これにより、どの投稿からも参照されていないキャッシュファイルが削除されます。",
"Too many requests. Please try again later.": "リクエストが多すぎます。後でもう一度お試しください。", "Too many requests. Please try again later.": "リクエストが多すぎます。後でもう一度お試しください。",
"Unsupported post type.": "サポートされていない投稿タイプです。", "Unsupported post type.": "サポートされていない投稿タイプです。",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "抜粋がない場合に投稿本文にフォールバックする際、YouTube、Twitter、サードパーティの埋め込みブロックのテキストをスキップします。", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "抜粋がない場合に投稿本文にフォールバックする際、YouTube、Twitter、サードパーティの埋め込みブロックのテキストをスキップします。",
"Where to insert the audio player relative to the post content.": "投稿コンテンツに対するオーディオプレーヤーの挿入位置。", "Where to insert the audio player relative to the post content.": "投稿コンテンツに対するオーディオプレーヤーの挿入位置。",
"You do not have permission to edit this post.": "この投稿を編集する権限がありません。", "You do not have permission to edit this post.": "この投稿を編集する権限がありません。",
"Your browser does not support the audio element.": "お使いのブラウザはオーディオ要素をサポートしていません。" "Your browser does not support the audio element.": "お使いのブラウザはオーディオ要素をサポートしていません。",
"Audio Format": "オーディオフォーマット",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "出力オーディオフォーマット。MP3は普遍的にサポートされています。Opusは同じビットレートでより高品質ですが、ブラウザのサポートは限定的です。",
"Opus Bitrate": "Opusビットレート",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Opusエンコーディングのビットレート。OpusはMP3よりはるかに低いビットレートで良好な品質を実現します。モノラル出力。",
"24 kbps (standard)": "24 kbps(標準)",
"16 kbps (compact)": "16 kbps(コンパクト)",
"12 kbps (minimal)": "12 kbps(最小)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "MP3/Opus変換用のffmpegツールへの絶対パス。空の場合は自動検出されます。",
"FFmpeg Binaries Path": "FFmpegバイナリパス"
} }
} }
Binary file not shown.
+51
View File
@@ -76,6 +76,14 @@ msgstr "キャッシュをフラッシュしました。"
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "オーディオプレーヤーのビジュアルテーマを選択してください。" msgstr "オーディオプレーヤーのビジュアルテーマを選択してください。"
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "チャンク間の無音"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Chunked — 文の区切りでテキストを分割"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "クラシック" msgstr "クラシック"
@@ -364,10 +372,22 @@ msgstr "選択したプレイヤースタイルがサンプルオーディオク
msgid "Quality tier override" msgid "Quality tier override"
msgstr "品質ティアの上書き" msgstr "品質ティアの上書き"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "Rawモードはテキストを直接Piperに渡します。Chunkedモードは最初にテキストを文に分割します。"
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Raw — テキストをそのままPiperに送信"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "ログの更新" msgstr "ログの更新"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Chunkedモードで文チャンク間に挿入される無音の秒数。デフォルト: 2.0。範囲: 0.55.0。"
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "再生時間を表示" msgstr "再生時間を表示"
@@ -388,6 +408,10 @@ msgstr "接続テスト"
msgid "Testing…" msgid "Testing…"
msgstr "テスト中…" msgstr "テスト中…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "テキスト処理"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "これにより、どの投稿からも参照されていないキャッシュファイルが削除されます。" msgstr "これにより、どの投稿からも参照されていないキャッシュファイルが削除されます。"
@@ -424,3 +448,30 @@ msgstr "この投稿を編集する権限がありません。"
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "お使いのブラウザはオーディオ要素をサポートしていません。" msgstr "お使いのブラウザはオーディオ要素をサポートしていません。"
msgid "Audio Format"
msgstr "オーディオフォーマット"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "出力オーディオフォーマット。MP3は普遍的にサポートされています。Opusは同じビットレートでより高品質ですが、ブラウザのサポートは限定的です。"
msgid "Opus Bitrate"
msgstr "Opusビットレート"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Opusエンコーディングのビットレート。OpusはMP3よりはるかに低いビットレートで良好な品質を実現します。モノラル出力。"
msgid "24 kbps (standard)"
msgstr "24 kbps(標準)"
msgid "16 kbps (compact)"
msgstr "16 kbps(コンパクト)"
msgid "12 kbps (minimal)"
msgstr "12 kbps(最小)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "MP3/Opus変換用のffmpegツールへの絶対パス。空の場合は自動検出されます。"
msgid "FFmpeg Binaries Path"
msgstr "FFmpegバイナリパス"
+20 -5
View File
@@ -2,9 +2,9 @@
"_meta": { "_meta": {
"locale": "nl_NL", "locale": "nl_NL",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-09", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "Cachebeheer", "Cache Management": "Cachebeheer",
"Cache flushed.": "Cache geleegd.", "Cache flushed.": "Cache geleegd.",
"Choose a visual theme for the audio player.": "Kies een visueel thema voor de audiospeler.", "Choose a visual theme for the audio player.": "Kies een visueel thema voor de audiospeler.",
"Chunk Silence": "Pauzelengte",
"Chunked — pre-split text at sentence boundaries for better pacing": "Gesegmenteerd — splits tekst vooraf op zinsgrenzen",
"Classic": "Klassiek", "Classic": "Klassiek",
"Clear Log": "Log wissen", "Clear Log": "Log wissen",
"Clear Orphaned Audio": "Verweesde audio wissen", "Clear Orphaned Audio": "Verweesde audio wissen",
@@ -95,12 +97,16 @@
"Post not found.": "Bericht niet gevonden.", "Post not found.": "Bericht niet gevonden.",
"Preview how the selected player style looks with a sample audio clip.": "Bekijk hoe de geselecteerde spelerstijl eruitziet met een voorbeeld-audiofragment.", "Preview how the selected player style looks with a sample audio clip.": "Bekijk hoe de geselecteerde spelerstijl eruitziet met een voorbeeld-audiofragment.",
"Quality tier override": "Kwaliteitsniveau overschrijven", "Quality tier override": "Kwaliteitsniveau overschrijven",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "Ruwe modus stuurt tekst direct naar Piper. Gesegmenteerde modus splitst tekst eerst in zinnen.",
"Raw — send text as-is to Piper": "Ruw — stuur tekst ongewijzigd naar Piper",
"Refresh Log": "Log vernieuwen", "Refresh Log": "Log vernieuwen",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Seconden stilte tussen zinsblokken in Gesegmenteerde modus. Standaard: 2.0. Bereik: 0.55.0.",
"Show Duration": "Toon duur", "Show Duration": "Toon duur",
"Skip Embedded Content": "Ingesloten inhoud overslaan", "Skip Embedded Content": "Ingesloten inhoud overslaan",
"Styling": "Vormgeving", "Styling": "Vormgeving",
"Test Connection": "Verbinding testen", "Test Connection": "Verbinding testen",
"Testing…": "Testen…", "Testing…": "Testen…",
"Text Processing": "Tekstverwerking",
"This will delete cache files not referenced by any post.": "Hiermee worden cachebestanden verwijderd die niet aan een bericht zijn gekoppeld.", "This will delete cache files not referenced by any post.": "Hiermee worden cachebestanden verwijderd die niet aan een bericht zijn gekoppeld.",
"Too many requests. Please try again later.": "Te veel verzoeken. Probeer het later opnieuw.", "Too many requests. Please try again later.": "Te veel verzoeken. Probeer het later opnieuw.",
"Unsupported post type.": "Niet-ondersteund berichttype.", "Unsupported post type.": "Niet-ondersteund berichttype.",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Bij terugvallen op berichtinhoud (geen samenvatting), tekst van ingesloten blokken zoals YouTube, Twitter en embeds van derden overslaan.", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Bij terugvallen op berichtinhoud (geen samenvatting), tekst van ingesloten blokken zoals YouTube, Twitter en embeds van derden overslaan.",
"Where to insert the audio player relative to the post content.": "Waar de audiospeler moet worden ingevoegd ten opzichte van de berichtinhoud.", "Where to insert the audio player relative to the post content.": "Waar de audiospeler moet worden ingevoegd ten opzichte van de berichtinhoud.",
"You do not have permission to edit this post.": "Je hebt geen rechten om dit bericht te bewerken.", "You do not have permission to edit this post.": "Je hebt geen rechten om dit bericht te bewerken.",
"Your browser does not support the audio element.": "Je browser ondersteunt het audio-element niet." "Your browser does not support the audio element.": "Je browser ondersteunt het audio-element niet.",
"Audio Format": "Audioformaat",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "Uitvoer audioformaat. MP3 wordt universeel ondersteund. Opus biedt betere kwaliteit bij dezelfde bitrate maar heeft beperktere browserondersteuning.",
"Opus Bitrate": "Opus-bitrate",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Bitrate voor Opus-codering. Opus bereikt goede kwaliteit bij veel lagere bitrates dan MP3. Mono-uitvoer.",
"24 kbps (standard)": "24 kbps (standaard)",
"16 kbps (compact)": "16 kbps (compact)",
"12 kbps (minimal)": "12 kbps (minimaal)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "Absoluut pad naar ffmpeg-tools voor MP3/Opus-conversie. Automatisch gedetecteerd als leeg gelaten.",
"FFmpeg Binaries Path": "FFmpeg-binaries-pad"
} }
} }
Binary file not shown.
+52 -1
View File
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Piperless 1.0.0\n" "Project-Id-Version: Piperless 1.0.0\n"
"Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n" "Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n" "POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2026-05-09 00:00+0000\n" "PO-Revision-Date: 2026-05-10 00:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Dutch <LL@li.org>\n" "Language-Team: Dutch <LL@li.org>\n"
"Language: nl_NL\n" "Language: nl_NL\n"
@@ -76,6 +76,14 @@ msgstr "Cache geleegd."
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "Kies een visueel thema voor de audiospeler." msgstr "Kies een visueel thema voor de audiospeler."
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "Pauzelengte"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Gesegmenteerd — splits tekst vooraf op zinsgrenzen"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "Klassiek" msgstr "Klassiek"
@@ -364,10 +372,22 @@ msgstr "Bekijk hoe de geselecteerde spelerstijl eruitziet met een voorbeeld-audi
msgid "Quality tier override" msgid "Quality tier override"
msgstr "Kwaliteitsniveau overschrijven" msgstr "Kwaliteitsniveau overschrijven"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "Ruwe modus stuurt tekst direct naar Piper. Gesegmenteerde modus splitst tekst eerst in zinnen."
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Ruw — stuur tekst ongewijzigd naar Piper"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "Log vernieuwen" msgstr "Log vernieuwen"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Seconden stilte tussen zinsblokken in Gesegmenteerde modus. Standaard: 2.0. Bereik: 0.55.0."
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "Toon duur" msgstr "Toon duur"
@@ -388,6 +408,10 @@ msgstr "Verbinding testen"
msgid "Testing…" msgid "Testing…"
msgstr "Testen…" msgstr "Testen…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "Tekstverwerking"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "Hiermee worden cachebestanden verwijderd die niet aan een bericht zijn gekoppeld." msgstr "Hiermee worden cachebestanden verwijderd die niet aan een bericht zijn gekoppeld."
@@ -424,3 +448,30 @@ msgstr "Je hebt geen rechten om dit bericht te bewerken."
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "Je browser ondersteunt het audio-element niet." msgstr "Je browser ondersteunt het audio-element niet."
msgid "Audio Format"
msgstr "Audioformaat"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "Uitvoer audioformaat. MP3 wordt universeel ondersteund. Opus biedt betere kwaliteit bij dezelfde bitrate maar heeft beperktere browserondersteuning."
msgid "Opus Bitrate"
msgstr "Opus-bitrate"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Bitrate voor Opus-codering. Opus bereikt goede kwaliteit bij veel lagere bitrates dan MP3. Mono-uitvoer."
msgid "24 kbps (standard)"
msgstr "24 kbps (standaard)"
msgid "16 kbps (compact)"
msgstr "16 kbps (compact)"
msgid "12 kbps (minimal)"
msgstr "12 kbps (minimaal)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "Absoluut pad naar ffmpeg-tools voor MP3/Opus-conversie. Automatisch gedetecteerd als leeg gelaten."
msgid "FFmpeg Binaries Path"
msgstr "FFmpeg-binaries-pad"
+18 -3
View File
@@ -3,8 +3,8 @@
"locale": "pt_BR", "locale": "pt_BR",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-10", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "Gerenciamento de Cache", "Cache Management": "Gerenciamento de Cache",
"Cache flushed.": "Cache limpo.", "Cache flushed.": "Cache limpo.",
"Choose a visual theme for the audio player.": "Escolha um tema visual para o reprodutor de áudio.", "Choose a visual theme for the audio player.": "Escolha um tema visual para o reprodutor de áudio.",
"Chunk Silence": "Silêncio entre frases",
"Chunked — pre-split text at sentence boundaries for better pacing": "Segmentado — pré-dividir texto nos limites das frases",
"Classic": "Clássico", "Classic": "Clássico",
"Clear Log": "Limpar Log", "Clear Log": "Limpar Log",
"Clear Orphaned Audio": "Limpar Áudio Órfão", "Clear Orphaned Audio": "Limpar Áudio Órfão",
@@ -95,12 +97,16 @@
"Post not found.": "Post não encontrado.", "Post not found.": "Post não encontrado.",
"Preview how the selected player style looks with a sample audio clip.": "Visualize como o estilo de player selecionado fica com um clipe de áudio de exemplo.", "Preview how the selected player style looks with a sample audio clip.": "Visualize como o estilo de player selecionado fica com um clipe de áudio de exemplo.",
"Quality tier override": "Substituição de nível de qualidade", "Quality tier override": "Substituição de nível de qualidade",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "O modo Bruto envia o texto diretamente para o Piper. O modo Segmentado divide o texto em frases.",
"Raw — send text as-is to Piper": "Bruto — enviar texto como está para o Piper",
"Refresh Log": "Atualizar Log", "Refresh Log": "Atualizar Log",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "Segundos de silêncio inseridos entre blocos de frases no modo Segmentado. Padrão: 2.0. Intervalo: 0.55.0.",
"Show Duration": "Mostrar Duração", "Show Duration": "Mostrar Duração",
"Skip Embedded Content": "Pular Conteúdo Incorporado", "Skip Embedded Content": "Pular Conteúdo Incorporado",
"Styling": "Estilização", "Styling": "Estilização",
"Test Connection": "Testar Conexão", "Test Connection": "Testar Conexão",
"Testing…": "Testando…", "Testing…": "Testando…",
"Text Processing": "Processamento de texto",
"This will delete cache files not referenced by any post.": "Isso excluirá arquivos de cache não referenciados por nenhum post.", "This will delete cache files not referenced by any post.": "Isso excluirá arquivos de cache não referenciados por nenhum post.",
"Too many requests. Please try again later.": "Muitas solicitações. Tente novamente mais tarde.", "Too many requests. Please try again later.": "Muitas solicitações. Tente novamente mais tarde.",
"Unsupported post type.": "Tipo de post não suportado.", "Unsupported post type.": "Tipo de post não suportado.",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Ao recorrer ao corpo do post (sem resumo), pular texto de blocos incorporados como YouTube, Twitter e embeds de terceiros.", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "Ao recorrer ao corpo do post (sem resumo), pular texto de blocos incorporados como YouTube, Twitter e embeds de terceiros.",
"Where to insert the audio player relative to the post content.": "Onde inserir o player de áudio em relação ao conteúdo do post.", "Where to insert the audio player relative to the post content.": "Onde inserir o player de áudio em relação ao conteúdo do post.",
"You do not have permission to edit this post.": "Você não tem permissão para editar este post.", "You do not have permission to edit this post.": "Você não tem permissão para editar este post.",
"Your browser does not support the audio element.": "Seu navegador não suporta o elemento de áudio." "Your browser does not support the audio element.": "Seu navegador não suporta o elemento de áudio.",
"Audio Format": "Formato de áudio",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "Formato de áudio de saída. MP3 é universalmente suportado. Opus oferece melhor qualidade na mesma taxa de bits, mas tem suporte de navegador mais limitado.",
"Opus Bitrate": "Bitrate do Opus",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Bitrate para codificação Opus. O Opus alcança boa qualidade em taxas de bits muito mais baixas que o MP3. Saída mono.",
"24 kbps (standard)": "24 kbps (padrão)",
"16 kbps (compact)": "16 kbps (compacto)",
"12 kbps (minimal)": "12 kbps (mínimo)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "Caminho absoluto para as ferramentas ffmpeg para conversão MP3/Opus. Detectado automaticamente se deixado vazio.",
"FFmpeg Binaries Path": "Caminho dos binários FFmpeg"
} }
} }
Binary file not shown.
+51
View File
@@ -76,6 +76,14 @@ msgstr "Cache limpo."
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "Escolha um tema visual para o reprodutor de áudio." msgstr "Escolha um tema visual para o reprodutor de áudio."
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "Silêncio entre frases"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "Segmentado — pré-dividir texto nos limites das frases"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "Clássico" msgstr "Clássico"
@@ -364,10 +372,22 @@ msgstr "Visualize como o estilo de player selecionado fica com um clipe de áudi
msgid "Quality tier override" msgid "Quality tier override"
msgstr "Substituição de nível de qualidade" msgstr "Substituição de nível de qualidade"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "O modo Bruto envia o texto diretamente para o Piper. O modo Segmentado divide o texto em frases."
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "Bruto — enviar texto como está para o Piper"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "Atualizar Log" msgstr "Atualizar Log"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "Segundos de silêncio inseridos entre blocos de frases no modo Segmentado. Padrão: 2.0. Intervalo: 0.55.0."
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "Mostrar Duração" msgstr "Mostrar Duração"
@@ -388,6 +408,10 @@ msgstr "Testar Conexão"
msgid "Testing…" msgid "Testing…"
msgstr "Testando…" msgstr "Testando…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "Processamento de texto"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "Isso excluirá arquivos de cache não referenciados por nenhum post." msgstr "Isso excluirá arquivos de cache não referenciados por nenhum post."
@@ -424,3 +448,30 @@ msgstr "Você não tem permissão para editar este post."
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "Seu navegador não suporta o elemento de áudio." msgstr "Seu navegador não suporta o elemento de áudio."
msgid "Audio Format"
msgstr "Formato de áudio"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "Formato de áudio de saída. MP3 é universalmente suportado. Opus oferece melhor qualidade na mesma taxa de bits, mas tem suporte de navegador mais limitado."
msgid "Opus Bitrate"
msgstr "Bitrate do Opus"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Bitrate para codificação Opus. O Opus alcança boa qualidade em taxas de bits muito mais baixas que o MP3. Saída mono."
msgid "24 kbps (standard)"
msgstr "24 kbps (padrão)"
msgid "16 kbps (compact)"
msgstr "16 kbps (compacto)"
msgid "12 kbps (minimal)"
msgstr "12 kbps (mínimo)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "Caminho absoluto para as ferramentas ffmpeg para conversão MP3/Opus. Detectado automaticamente se deixado vazio."
msgid "FFmpeg Binaries Path"
msgstr "Caminho dos binários FFmpeg"
+20 -5
View File
@@ -2,9 +2,9 @@
"_meta": { "_meta": {
"locale": "zh_CN", "locale": "zh_CN",
"source": "translations.json", "source": "translations.json",
"generated": "2026-05-09", "generated": "2026-05-10",
"total_strings": 102, "total_strings": 117,
"translated": 102, "translated": 117,
"locked": false "locked": false
}, },
"strings": { "strings": {
@@ -23,6 +23,8 @@
"Cache Management": "缓存管理", "Cache Management": "缓存管理",
"Cache flushed.": "缓存已清空。", "Cache flushed.": "缓存已清空。",
"Choose a visual theme for the audio player.": "为音频播放器选择一个视觉主题。", "Choose a visual theme for the audio player.": "为音频播放器选择一个视觉主题。",
"Chunk Silence": "块间静音",
"Chunked — pre-split text at sentence boundaries for better pacing": "分块 — 在句子边界预先分割文本",
"Classic": "经典", "Classic": "经典",
"Clear Log": "清除日志", "Clear Log": "清除日志",
"Clear Orphaned Audio": "清除孤立音频", "Clear Orphaned Audio": "清除孤立音频",
@@ -95,12 +97,16 @@
"Post not found.": "未找到文章。", "Post not found.": "未找到文章。",
"Preview how the selected player style looks with a sample audio clip.": "使用示例音频片段预览所选播放器样式的效果。", "Preview how the selected player style looks with a sample audio clip.": "使用示例音频片段预览所选播放器样式的效果。",
"Quality tier override": "质量级别覆盖", "Quality tier override": "质量级别覆盖",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "原始模式直接将文本传递给 Piper。分块模式先将文本分割成句子。",
"Raw — send text as-is to Piper": "原始 — 直接将文本发送给 Piper",
"Refresh Log": "刷新日志", "Refresh Log": "刷新日志",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "分块模式下句子块之间插入的静音秒数。默认:2.0。范围:0.5–5.0。",
"Show Duration": "显示时长", "Show Duration": "显示时长",
"Skip Embedded Content": "跳过嵌入内容", "Skip Embedded Content": "跳过嵌入内容",
"Styling": "样式", "Styling": "样式",
"Test Connection": "测试连接", "Test Connection": "测试连接",
"Testing…": "正在测试…", "Testing…": "正在测试…",
"Text Processing": "文本处理",
"This will delete cache files not referenced by any post.": "这将删除未被任何文章引用的缓存文件。", "This will delete cache files not referenced by any post.": "这将删除未被任何文章引用的缓存文件。",
"Too many requests. Please try again later.": "请求过多。请稍后再试。", "Too many requests. Please try again later.": "请求过多。请稍后再试。",
"Unsupported post type.": "不支持的文章类型。", "Unsupported post type.": "不支持的文章类型。",
@@ -109,6 +115,15 @@
"When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "当回退到文章正文(无摘要)时,跳过 YouTube、Twitter 和第三方嵌入等嵌入块中的文本。", "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds.": "当回退到文章正文(无摘要)时,跳过 YouTube、Twitter 和第三方嵌入等嵌入块中的文本。",
"Where to insert the audio player relative to the post content.": "音频播放器相对于文章内容的插入位置。", "Where to insert the audio player relative to the post content.": "音频播放器相对于文章内容的插入位置。",
"You do not have permission to edit this post.": "您没有编辑此文章的权限。", "You do not have permission to edit this post.": "您没有编辑此文章的权限。",
"Your browser does not support the audio element.": "您的浏览器不支持音频元素。" "Your browser does not support the audio element.": "您的浏览器不支持音频元素。",
"Audio Format": "音频格式",
"Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support.": "输出音频格式。MP3 被普遍支持。Opus 在相同比特率下提供更好的质量,但浏览器支持较窄。",
"Opus Bitrate": "Opus 比特率",
"Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output.": "Opus 编码的比特率。Opus 在比 MP3 低得多的比特率下仍能实现良好的质量。单声道输出。",
"24 kbps (standard)": "24 kbps(标准)",
"16 kbps (compact)": "16 kbps(紧凑)",
"12 kbps (minimal)": "12 kbps(最小)",
"Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty.": "ffmpeg 工具的绝对路径,用于 MP3/Opus 转换。留空则自动检测。",
"FFmpeg Binaries Path": "FFmpeg 二进制文件路径"
} }
} }
Binary file not shown.
+52 -1
View File
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Piperless 1.0.0\n" "Project-Id-Version: Piperless 1.0.0\n"
"Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n" "Report-Msgid-Bugs-To: https://github.com/example/piperless/issues\n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n" "POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2026-05-09 00:00+0000\n" "PO-Revision-Date: 2026-05-10 00:00+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: zh <LL@li.org>\n" "Language-Team: zh <LL@li.org>\n"
"Language: zh_CN\n" "Language: zh_CN\n"
@@ -76,6 +76,14 @@ msgstr "缓存已清空。"
msgid "Choose a visual theme for the audio player." msgid "Choose a visual theme for the audio player."
msgstr "为音频播放器选择一个视觉主题。" msgstr "为音频播放器选择一个视觉主题。"
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr "块间静音"
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr "分块 — 在句子边界预先分割文本"
#: includes/class-settings.php:385 #: includes/class-settings.php:385
msgid "Classic" msgid "Classic"
msgstr "经典" msgstr "经典"
@@ -364,10 +372,22 @@ msgstr "使用示例音频片段预览所选播放器样式的效果。"
msgid "Quality tier override" msgid "Quality tier override"
msgstr "质量级别覆盖" msgstr "质量级别覆盖"
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr "原始模式直接将文本传递给 Piper。分块模式先将文本分割成句子。"
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr "原始 — 直接将文本发送给 Piper"
#: includes/class-settings.php:607 #: includes/class-settings.php:607
msgid "Refresh Log" msgid "Refresh Log"
msgstr "刷新日志" msgstr "刷新日志"
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr "分块模式下句子块之间插入的静音秒数。默认:2.0。范围:0.5–5.0。"
#: includes/class-settings.php:405 #: includes/class-settings.php:405
msgid "Show Duration" msgid "Show Duration"
msgstr "显示时长" msgstr "显示时长"
@@ -388,6 +408,10 @@ msgstr "测试连接"
msgid "Testing…" msgid "Testing…"
msgstr "正在测试…" msgstr "正在测试…"
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr "文本处理"
#: includes/class-settings.php:649 #: includes/class-settings.php:649
msgid "This will delete cache files not referenced by any post." msgid "This will delete cache files not referenced by any post."
msgstr "这将删除未被任何文章引用的缓存文件。" msgstr "这将删除未被任何文章引用的缓存文件。"
@@ -424,3 +448,30 @@ msgstr "您没有编辑此文章的权限。"
msgid "Your browser does not support the audio element." msgid "Your browser does not support the audio element."
msgstr "您的浏览器不支持音频元素。" msgstr "您的浏览器不支持音频元素。"
msgid "Audio Format"
msgstr "音频格式"
msgid "Output audio format. MP3 is universally supported. Opus offers better quality at the same bitrate but has narrower browser support."
msgstr "输出音频格式。MP3 被普遍支持。Opus 在相同比特率下提供更好的质量,但浏览器支持较窄。"
msgid "Opus Bitrate"
msgstr "Opus 比特率"
msgid "Bitrate for Opus encoding. Opus achieves good quality at much lower bitrates than MP3. Mono output."
msgstr "Opus 编码的比特率。Opus 在比 MP3 低得多的比特率下仍能实现良好的质量。单声道输出。"
msgid "24 kbps (standard)"
msgstr "24 kbps(标准)"
msgid "16 kbps (compact)"
msgstr "16 kbps(紧凑)"
msgid "12 kbps (minimal)"
msgstr "12 kbps(最小)"
msgid "Absolute path to ffmpeg tools for MP3/Opus conversion. Auto-detected from common paths if left empty."
msgstr "ffmpeg 工具的绝对路径,用于 MP3/Opus 转换。留空则自动检测。"
msgid "FFmpeg Binaries Path"
msgstr "FFmpeg 二进制文件路径"
+24
View File
@@ -149,6 +149,30 @@ msgstr ""
msgid "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds." msgid "When falling back to post body (no excerpt), skip text from embedded blocks like YouTube, Twitter, and third-party embeds."
msgstr "" msgstr ""
#: includes/class-settings.php:now
msgid "Text Processing"
msgstr ""
#: includes/class-settings.php:now
msgid "Raw — send text as-is to Piper"
msgstr ""
#: includes/class-settings.php:now
msgid "Chunked — pre-split text at sentence boundaries for better pacing"
msgstr ""
#: includes/class-settings.php:now
msgid "Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing."
msgstr ""
#: includes/class-settings.php:now
msgid "Chunk Silence"
msgstr ""
#: includes/class-settings.php:now
msgid "Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0."
msgstr ""
#: includes/class-settings.php:378 #: includes/class-settings.php:378
msgid "Audio Player Settings" msgid "Audio Player Settings"
msgstr "" msgstr ""
+6
View File
@@ -14,6 +14,8 @@
"Cache Management": "", "Cache Management": "",
"Cache flushed.": "", "Cache flushed.": "",
"Choose a visual theme for the audio player.": "", "Choose a visual theme for the audio player.": "",
"Chunk Silence": "",
"Chunked — pre-split text at sentence boundaries for better pacing": "",
"Classic": "", "Classic": "",
"Clear Log": "", "Clear Log": "",
"Clear Orphaned Audio": "", "Clear Orphaned Audio": "",
@@ -88,12 +90,16 @@
"Post not found.": "", "Post not found.": "",
"Preview how the selected player style looks with a sample audio clip.": "", "Preview how the selected player style looks with a sample audio clip.": "",
"Quality tier override": "", "Quality tier override": "",
"Raw mode passes text directly to Piper. Chunked mode splits text into sentences first, avoiding false breaks on abbreviations and decimals while improving sentence pacing.": "",
"Raw — send text as-is to Piper": "",
"Refresh Log": "", "Refresh Log": "",
"Seconds of silence inserted between sentence chunks when Text Processing is set to Chunked. Default: 2.0. Range: 0.55.0.": "",
"Show Duration": "", "Show Duration": "",
"Skip Embedded Content": "", "Skip Embedded Content": "",
"Styling": "", "Styling": "",
"Test Connection": "", "Test Connection": "",
"Testing…": "", "Testing…": "",
"Text Processing": "",
"This will delete cache files not referenced by any post.": "", "This will delete cache files not referenced by any post.": "",
"Too many requests. Please try again later.": "", "Too many requests. Please try again later.": "",
"Unsupported post type.": "", "Unsupported post type.": "",
+2 -2
View File
@@ -3,7 +3,7 @@
* Plugin Name: Piperless — Audio Transcripts * Plugin Name: Piperless — Audio Transcripts
* Plugin URI: https://forkless.com * Plugin URI: https://forkless.com
* Description: Generate audio transcripts of WordPress posts using Piper TTS. Customizable players, caching, and full Gutenberg integration. * Description: Generate audio transcripts of WordPress posts using Piper TTS. Customizable players, caching, and full Gutenberg integration.
* Version: 1.0.0 * Version: 1.1.0
* Requires at least: 6.0 * Requires at least: 6.0
* Requires PHP: 8.0 * Requires PHP: 8.0
* Author: Forkless * Author: Forkless
@@ -22,7 +22,7 @@ if ( ! defined( 'ABSPATH' ) ) {
} }
// ── Constants ──────────────────────────────────────────────────────────────── // ── Constants ────────────────────────────────────────────────────────────────
define( 'PIPERLESS_VERSION', '1.0.0' ); define( 'PIPERLESS_VERSION', '1.1.0' );
define( 'PIPERLESS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'PIPERLESS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'PIPERLESS_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'PIPERLESS_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'PIPERLESS_PLUGIN_FILE', __FILE__ ); define( 'PIPERLESS_PLUGIN_FILE', __FILE__ );