mirror of
https://github.com/storytold/filmcraft.git
synced 2026-11-02 18:09:21 +00:00
Read decades like 1990s as plural years in TTS normalizer (#3930)
* Read decades like 1990s as plural years in TTS normalizer Found while testing crates/tts-text/src/normalize.rs:~654 (cardinal/year branch) and parse_continuation ~line 680 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * tts-text: decade tests in the it binary, with boundary cases Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
@@ -654,9 +654,31 @@ fn parse_number_core(rest: &str, lang: Lang) -> Option<(Vec<Token>, usize)> {
|
||||
if !grouped && digits.len() == 4 && (1100..=2099).contains(&value) && year_is_standalone(rest, used) {
|
||||
return Some((year_words(value, lang), used));
|
||||
}
|
||||
// A decade such as "1990s" reads as a plural year: "nineteen nineties".
|
||||
if !grouped
|
||||
&& digits.len() == 4
|
||||
&& (1100..=2099).contains(&value)
|
||||
&& value.is_multiple_of(10)
|
||||
&& matches!(peek(rest, used), Some('s'))
|
||||
&& !peek(rest, used + 1).is_some_and(char::is_alphanumeric)
|
||||
{
|
||||
let mut words = year_words(value, lang);
|
||||
if let Some(Token::Word(last)) = words.last_mut() {
|
||||
*last = pluralize_decade(last);
|
||||
}
|
||||
return Some((words, used + 1));
|
||||
}
|
||||
Some((english_cardinal(value).into_iter().map(Token::Word).collect(), used))
|
||||
}
|
||||
|
||||
/// Plural of the last word of a round year: ninety → nineties, hundred → hundreds.
|
||||
fn pluralize_decade(word: &str) -> String {
|
||||
match word.strip_suffix('y') {
|
||||
Some(stem) => format!("{stem}ies"),
|
||||
None => format!("{word}s"),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_leading_zero_str(digits: &str) -> bool {
|
||||
digits.len() > 1 && digits.starts_with('0')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
use filmcraft_tts_text::{Lang, Token, normalize};
|
||||
|
||||
fn spoken(text: &str) -> String {
|
||||
let words: Vec<String> = normalize(text, Lang::EnUs).unwrap().into_iter().filter_map(|t| if let Token::Word(w) = t { Some(w) } else { None }).collect();
|
||||
words.join(" ")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bare_year_is_unchanged() {
|
||||
assert_eq!(spoken("in 1990"), "in nineteen ninety");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decade_reads_as_plural_year() {
|
||||
assert_eq!(spoken("the 1990s"), "the nineteen nineties");
|
||||
assert_eq!(spoken("the 2010s."), "the twenty tens");
|
||||
assert_eq!(spoken("the 1900s"), "the nineteen hundreds");
|
||||
assert_eq!(spoken("the 1100s"), "the eleven hundreds");
|
||||
assert_eq!(spoken("the 2090s"), "the twenty nineties");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_round_years_followed_by_a_lone_s_are_decades() {
|
||||
assert_ne!(spoken("the 1995s"), "the nineteen ninety fives");
|
||||
assert!(!spoken("the 1990sx").contains("nineties"));
|
||||
assert!(!spoken("the 3000s").contains("thousands"));
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
mod decades;
|
||||
Reference in New Issue
Block a user