Text Normalization
Convert numbers, dates, and symbols into spoken words, with language hints and spell tags
Text normalization converts numbers, dates, times, and other non-verbal text
into spoken words (for example "3 apples" becomes "three apples"). It is on by
default. How it works, the supported languages and their codes are documented in
Text processing. The SDKs control it with the
normalize and language options:
# With explicit language (recommended)
audio = client.tts.generate(
text="I bought 3 items for €50.99 on 01/15/2024.",
voice_id=1071,
normalize=True,
language="en",
)
# Without language: normalized in the voice's primary language (English if none)
audio = client.tts.generate(
text="Ich habe 3 Artikel für 50,99€ gekauft.",
voice_id=1071,
normalize=True,
# language not specified: the voice's primary language is used
)// With explicit language (recommended)
const audio = await client.tts.generate({
text: 'I bought 3 items for €50.99 on 01/15/2024.',
voiceId: 1071,
normalize: true,
language: 'en',
});
// Without language: normalized in the voice's primary language (English if none)
const voiceLanguageAudio = await client.tts.generate({
text: 'Ich habe 3 Artikel für 50,99€ gekauft.',
voiceId: 1071,
normalize: true,
// language not specified: the voice's primary language is used
});// With explicit language (recommended)
AudioResponse audio = client.tts().generate(
GenerateRequest.builder("I bought 3 items for €50.99 on 01/15/2024.")
.voiceId(1071)
.normalize(true)
.language("en")
.build()
);
// Without language: normalized in the voice's primary language (English if none)
AudioResponse voiceLanguageAudio = client.tts().generate(
GenerateRequest.builder("Ich habe 3 Artikel für 50,99€ gekauft.")
.voiceId(1071)
.normalize(true)
// language not specified: the voice's primary language is used
.build()
);// With explicit language (recommended)
let audio = client
.tts()
.generate(
&TtsRequest::new("I bought 3 items for €50.99 on 01/15/2024.")
.voice_id(1071)
.normalize(true)
.language("en"),
)
.await?;
// Without language: normalized in the voice's primary language (English if none)
let voice_language_audio = client
.tts()
.generate(
&TtsRequest::new("Ich habe 3 Artikel für 50,99€ gekauft.")
.voice_id(1071)
.normalize(true), // language not specified: the voice's primary language is used
)
.await?;// With explicit language (recommended)
kugelaudio::GenerateRequest request;
request.text = "I bought 3 items for €50.99 on 01/15/2024.";
request.voice_id = 1071;
request.normalize = true;
request.language = "en";
kugelaudio::AudioResponse audio = client.tts().generate(request);
// Without language: normalized in the voice's primary language (English if none)
kugelaudio::GenerateRequest voice_language_request;
voice_language_request.text = "Ich habe 3 Artikel für 50,99€ gekauft.";
voice_language_request.voice_id = 1071;
voice_language_request.normalize = true;
// language not specified: the voice's primary language is used
kugelaudio::AudioResponse voice_language_audio = client.tts().generate(voice_language_request);// With explicit language (recommended)
final audio = await client.tts.generate(
text: 'I bought 3 items for €50.99 on 01/15/2024.',
voiceId: 1071,
normalize: true,
language: 'en',
);
// Without language: normalized in the voice's primary language (English if none)
final voiceLanguageAudio = await client.tts.generate(
text: 'Ich habe 3 Artikel für 50,99€ gekauft.',
voiceId: 1071,
normalize: true,
// language not specified: the voice's primary language is used
);Without a language, the Rust, C++ and Dart SDKs log a warning when normalization is on.
Spell tags
Wrap text in <spell> tags to have it read character by character (emails,
codes, acronyms). Tag semantics and per-language character names are in
Spell tags. In a streaming session, a tag split across
tokens is handled for you:
async with client.tts.streaming_session(
voice_id=1071,
normalize=True,
language="en",
) as session:
async for chunk in session.send("My code is <spell>"):
play_audio(chunk.audio)
async for chunk in session.send("ABC123</spell>"):
play_audio(chunk.audio)
async for chunk in session.flush():
play_audio(chunk.audio)const session = client.tts.streamingSession(
{ voiceId: 1071, normalize: true, language: 'en' },
{ onChunk: (chunk) => playAudio(chunk.audio) },
);
await session.connect();
session.send('My code is <spell>');
session.send('ABC123</spell>');
await session.close();StreamConfig config = StreamConfig.builder()
.voiceId(1071)
.normalize(true)
.language("en")
.build();
try (StreamingSession session = client.streamingSession(config, chunk -> playAudio(chunk.getAudio()))) {
session.send("My code is <spell>");
session.send("ABC123</spell>");
}use futures_util::StreamExt;
use kugelaudio::StreamConfig;
let mut session = client
.tts()
.streaming_session(StreamConfig::new(1071).normalize(true).language("en"));
for text in ["My code is <spell>", "ABC123</spell>"] {
let mut audio = session.send(text, false);
while let Some(chunk) = audio.next().await {
play_audio(&chunk?.audio);
}
}
let mut tail = session.flush();
while let Some(chunk) = tail.next().await {
play_audio(&chunk?.audio);
}
drop(tail);
session.close().await?;kugelaudio::StreamConfig config;
config.voice_id = 1071;
config.normalize = true;
config.language = "en";
auto play_chunk = [](const kugelaudio::AudioChunk& chunk) { play_audio(chunk.audio); };
kugelaudio::StreamingSession session = client.tts().streaming_session(config);
session.send("My code is <spell>", /*flush=*/false, play_chunk);
session.send("ABC123</spell>", /*flush=*/false, play_chunk);
session.flush(play_chunk);
session.close();final session = client.tts.streamingSession(
StreamConfig(voiceId: 1071, normalize: true, language: 'en'),
);
session.audio.listen((chunk) => playAudio(chunk.audio));
await session.send('My code is <spell>');
await session.send('ABC123</spell>');
await session.flush();
await session.close();play_audio / playAudio stands for your own playback function.
Next steps
- Dictionaries: per-project pronunciation and replacement lists
- Generate speech: generation parameters including
normalizeandlanguage