Changeset 3496018
- Timestamp:
- 03/31/2026 09:44:07 PM (5 days ago)
- Location:
- text-to-speech-tts/trunk
- Files:
-
- 3 edited
-
includes/class-mementor-tts-processor.php (modified) (3 diffs)
-
readme.txt (modified) (2 diffs)
-
text-to-speech-tts.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
text-to-speech-tts/trunk/includes/class-mementor-tts-processor.php
r3494985 r3496018 149 149 $text = implode(' -- ', $text_parts); 150 150 151 // Normalize numbers, currency, and percentages into spoken words 152 $text = $this->normalize_numbers($text); 153 151 154 // Apply word replacements before custom pauses 152 155 $text = $this->apply_word_replacements($text); … … 291 294 292 295 /** 296 * Convert a number to its English spoken form 297 * 298 * @param int|float $number The number to convert 299 * @return string The number in words 300 */ 301 private function number_to_words($number) { 302 if (class_exists('NumberFormatter')) { 303 $fmt = new \NumberFormatter('en', \NumberFormatter::SPELLOUT); 304 return $fmt->format($number); 305 } 306 307 // Minimal fallback for small numbers if intl extension is missing 308 $ones = array('', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 309 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 310 'seventeen', 'eighteen', 'nineteen'); 311 $tens = array('', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'); 312 313 $n = (int) $number; 314 if ($n < 0) return 'minus ' . $this->number_to_words(-$n); 315 if ($n === 0) return 'zero'; 316 if ($n < 20) return $ones[$n]; 317 if ($n < 100) return $tens[(int)($n / 10)] . ($n % 10 ? ' ' . $ones[$n % 10] : ''); 318 if ($n < 1000) return $ones[(int)($n / 100)] . ' hundred' . ($n % 100 ? ' ' . $this->number_to_words($n % 100) : ''); 319 if ($n < 1000000) return $this->number_to_words((int)($n / 1000)) . ' thousand' . ($n % 1000 ? ' ' . $this->number_to_words($n % 1000) : ''); 320 if ($n < 1000000000) return $this->number_to_words((int)($n / 1000000)) . ' million' . ($n % 1000000 ? ' ' . $this->number_to_words($n % 1000000) : ''); 321 return $this->number_to_words((int)($n / 1000000000)) . ' billion' . ($n % 1000000000 ? ' ' . $this->number_to_words($n % 1000000000) : ''); 322 } 323 324 /** 325 * Normalize numbers, currency, and percentages into spoken words 326 * so TTS engines pronounce them naturally. 327 * 328 * Handles: $1,234 $1234 1,234 1234 12.5% 1st/2nd/3rd/4th 1.5 etc. 329 * 330 * @param string $text The text to process 331 * @return string Text with numbers converted to spoken words 332 */ 333 private function normalize_numbers($text) { 334 // 1. Currency: $1,234.56 or $1234 (with optional cents) 335 $text = preg_replace_callback( 336 '/\$\s?([\d,]+)(?:\.([\d]{1,2}))?/', 337 function ($m) { 338 $whole = (int) str_replace(',', '', $m[1]); 339 $words = $this->number_to_words($whole); 340 if ($whole === 1) { 341 $words .= ' dollar'; 342 } else { 343 $words .= ' dollars'; 344 } 345 if (!empty($m[2])) { 346 $cents = (int) $m[2]; 347 if (strlen($m[2]) === 1) $cents *= 10; // $1.5 → 50 cents 348 if ($cents > 0) { 349 $words .= ' and ' . $this->number_to_words($cents); 350 $words .= ($cents === 1) ? ' cent' : ' cents'; 351 } 352 } 353 return $words; 354 }, 355 $text 356 ); 357 358 // 2. Percentages: 2% or 12.5% 359 $text = preg_replace_callback( 360 '/(\d+(?:\.\d+)?)\s?%/', 361 function ($m) { 362 $num = (float) $m[1]; 363 if (floor($num) == $num) { 364 return $this->number_to_words((int) $num) . ' percent'; 365 } 366 $parts = explode('.', $m[1]); 367 return $this->number_to_words((int) $parts[0]) . ' point ' . 368 implode(' ', array_map(function($d) { return $this->number_to_words((int) $d); }, str_split($parts[1]))) . 369 ' percent'; 370 }, 371 $text 372 ); 373 374 // 3. Ordinals: 1st, 2nd, 3rd, 4th, 21st, etc. 375 $text = preg_replace_callback( 376 '/\b(\d+)(st|nd|rd|th)\b/i', 377 function ($m) { 378 $n = (int) $m[1]; 379 if (class_exists('NumberFormatter')) { 380 $fmt = new \NumberFormatter('en', \NumberFormatter::SPELLOUT); 381 $fmt->setTextAttribute(\NumberFormatter::DEFAULT_RULESET, '%spellout-ordinal'); 382 return $fmt->format($n); 383 } 384 return $this->number_to_words($n) . $m[2]; 385 }, 386 $text 387 ); 388 389 // 4. Plain large numbers with commas: 1,234 or 1,234,567 390 // (only when not already handled by currency above) 391 $text = preg_replace_callback( 392 '/\b(\d{1,3}(?:,\d{3})+)\b/', 393 function ($m) { 394 $num = (int) str_replace(',', '', $m[1]); 395 return $this->number_to_words($num); 396 }, 397 $text 398 ); 399 400 // 5. Standalone large numbers (4+ digits, no commas) that TTS may mispronounce 401 // e.g. 22200 → "twenty-two thousand two hundred" 402 // Skip numbers that look like years (1900-2099) in natural context 403 $text = preg_replace_callback( 404 '/\b(\d{4,})\b/', 405 function ($m) { 406 $num = (int) $m[1]; 407 // Preserve 4-digit numbers in year range — TTS handles these fine 408 if ($num >= 1900 && $num <= 2099 && strlen($m[1]) === 4) { 409 return $m[0]; 410 } 411 return $this->number_to_words($num); 412 }, 413 $text 414 ); 415 416 return $text; 417 } 418 419 /** 293 420 * Apply word replacements to text 294 * 421 * 295 422 * @param string $text The text to process 296 423 * @return string Text with word replacements applied … … 1302 1429 } 1303 1430 1431 // Normalize numbers, currency, and percentages into spoken words 1432 $processed_text = $this->normalize_numbers($processed_text); 1433 1304 1434 // Apply word replacements before custom pauses 1305 1435 $processed_text = $this->apply_word_replacements($processed_text); 1306 1436 1307 1437 // Apply custom pauses to the processed text 1308 1438 $processed_text = $this->apply_custom_pauses($processed_text); -
text-to-speech-tts/trunk/readme.txt
r3496011 r3496018 6 6 Tested up to: 6.9 7 7 Requires PHP: 7.2 8 Stable tag: 3.1. 58 Stable tag: 3.1.6 9 9 License: GPLv3 or later 10 10 License URI: [https://www.gnu.org/licenses/gpl-3.0.txt](https://www.gnu.org/licenses/gpl-3.0.txt) … … 236 236 237 237 == Changelog == 238 239 = 3.1.6 - 2026-03-31 = 240 241 * New: Numbers, currency, and percentages are now converted to spoken words before synthesis (e.g. $22,200 → "twenty-two thousand two hundred dollars", 2% → "two percent") 242 * Fixed: Shortcode audio generator was missing number normalization, causing TTS to mispronounce amounts 243 * Fixed: ElevenLabs Playground was sending raw text without any preprocessing 238 244 239 245 = 3.1.5 - 2026-03-31 = -
text-to-speech-tts/trunk/text-to-speech-tts.php
r3496011 r3496018 9 9 * Plugin URI: https://mementor.no/en/wordpress-plugins/text-to-speech/ 10 10 * Description: The easiest Text-to-Speech plugin for WordPress. Add natural voices, boost accessibility, and engage visitors with an instant audio player. 11 * Version: 3.1. 511 * Version: 3.1.6 12 12 * Author: Mementor AS 13 13 * Author URI: https://mementor.no/en/ … … 26 26 27 27 // Define plugin constants 28 define('MEMENTOR_TTS_VERSION', '3.1. 5');28 define('MEMENTOR_TTS_VERSION', '3.1.6'); 29 29 define('MEMENTOR_TTS_PLUGIN_DIR', plugin_dir_path(__FILE__)); 30 30 define('MEMENTOR_TTS_PLUGIN_URL', plugin_dir_url(__FILE__));
Note: See TracChangeset
for help on using the changeset viewer.