diff --git a/README.md b/README.md index 6bc6165..0fc05b6 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,38 @@ # Supertonic β€” Lightning Fast, On-Device, Accurate TTS -[![v3 Demo](https://img.shields.io/badge/πŸ€—%20v3-Demo-yellow)](https://huggingface.co/spaces/Supertone/supertonic-3) -[![v3 Models](https://img.shields.io/badge/πŸ€—%20v3-Models-blue)](https://huggingface.co/Supertone/supertonic-3) -[![v2 Branch](https://img.shields.io/badge/v2-release%2Fsupertonic--2-lightgrey)](https://github.com/supertone-inc/supertonic/tree/release/supertonic-2) -[![v1 Demo](https://img.shields.io/badge/πŸ€—%20v1%20(old)-Demo-lightgrey)](https://huggingface.co/spaces/Supertone/supertonic#interactive-demo) -[![v1 Models](https://img.shields.io/badge/πŸ€—%20v1%20(old)-Models-lightgrey)](https://huggingface.co/Supertone/supertonic) -

Supertonic 3 Banner

-**Supertonic** is a lightning-fast, on-device text-to-speech system designed for local inference with minimal overhead. Powered by ONNX Runtime, it runs entirely on your deviceβ€”no cloud, no API calls, no privacy concerns. +[![GitHub | Official Repo](https://img.shields.io/badge/GitHub-Official%20Repo-black?logo=github)](https://github.com/supertone-inc/supertonic) +[![Models](https://img.shields.io/badge/πŸ€—%20Hugging%20Face-Models-blue)](https://huggingface.co/Supertone/supertonic-3) +[![Runs Locally via WebGPU](https://img.shields.io/badge/πŸ€—%20Hugging%20Face-Demo-yellow)](https://huggingface.co/spaces/Supertone/supertonic-3) +[![DemoPage | Audio Samples](https://img.shields.io/badge/DemoPage-Audio%20Samples-F5D90A?labelColor=0B0C0E)](https://supertonic3.github.io/) +[![Voice Builder | Cloning Demo](https://img.shields.io/badge/Voice%20Builder-Cloning%20Demo-3457D5?logo=soundcloud&logoColor=white)](https://supertonic.supertone.ai/voice_builder) +[![GitHub | Python Package](https://img.shields.io/badge/GitHub-Python%20Package-black?logo=github)](https://github.com/supertone-inc/supertonic-py) +[![Docs | Python PyPI](https://img.shields.io/badge/Docs-Python%20PyPI-blue?logo=readthedocs&logoColor=white)](https://supertone-inc.github.io/supertonic-py/) + +

+ supertone-inc%2Fsupertonic | Trendshift +

+ +**Supertonic** is a lightning-fast, on-device multilingual text-to-speech system designed for local inference with minimal overhead. Powered by ONNX Runtime, it runs entirely on your deviceβ€”no cloud, no API calls, no privacy concerns. + +### ✨ Highlights + +- ⚑ **Blazingly Fast** β€” Low-latency, real-time synthesis across desktop, browser, mobile, and edge β€” fast enough to turn an entire webpage into audio in under a second +- 🌍 **31-Language Multilingual** β€” Synthesize directly from text across 31 languages, or pass `lang="na"` to let Supertonic process the text language-agnostically when you don't know the input language β€” no separate language adapters needed +- πŸͺΆ **99M-Parameter Open-Weight Model** β€” A compact, fully open-weight checkpoint β€” a fraction of the size of 0.7B–2B class open TTS systems β€” for smaller downloads, faster cold starts, and lower memory footprint +- πŸ“± **Edge-Device Ready** β€” Runs locally on desktop, mobile, browsers, and resource-constrained hardware like Raspberry Pi or e-readers, with zero network dependency, complete privacy, and no GPU required +- πŸ”Š **44.1kHz High-Quality Audio** β€” Outputs studio-grade 44.1kHz 16-bit WAV directly, ready for production playback without any external upsampler +- 🎭 **Expression Tags** β€” 10 inline tags (e.g. ``, ``, ``) bring natural human nuance into generated speech without prompt engineering or reference audio +- πŸ› οΈ **Multi-Runtime SDKs** β€” Ready-to-use examples through ONNX Runtime across Python, Node.js, Browser (WebGPU), Java, C++, C#, Go, Swift, iOS, Rust, and Flutter + +### 🌍 Supported Languages (31) + +Arabic (`ar`), Bulgarian (`bg`), Croatian (`hr`), Czech (`cs`), Danish (`da`), Dutch (`nl`), English (`en`), Estonian (`et`), Finnish (`fi`), French (`fr`), German (`de`), Greek (`el`), Hindi (`hi`), Hungarian (`hu`), Indonesian (`id`), Italian (`it`), Japanese (`ja`), Korean (`ko`), Latvian (`lv`), Lithuanian (`lt`), Polish (`pl`), Portuguese (`pt`), Romanian (`ro`), Russian (`ru`), Slovak (`sk`), Slovenian (`sl`), Spanish (`es`), Swedish (`sv`), Turkish (`tr`), Ukrainian (`uk`), Vietnamese (`vi`) + +> **Not sure which language your text is in?** Pass `lang="na"` and Supertonic will handle the input in a language-agnostic way β€” no explicit language tag required. ### πŸ“° Update News @@ -22,6 +44,8 @@ - **2025.12.08** - Optimized ONNX models via [OnnxSlim](https://github.com/inisis/OnnxSlim) now available on [Hugging Face Models](https://huggingface.co/Supertone/supertonic) - **2025.11.24** - Added Flutter SDK support with macOS compatibility +--- + ## Quick Start Install the Python SDK and generate speech immediately. On the first run, Supertonic downloads the model assets from Hugging Face automatically. @@ -40,11 +64,23 @@ tts = TTS(auto_download=True) style = tts.get_voice_style(voice_name="M1") -text = "A gentle breeze moved through the open window while everyone listened to the story." -wav, duration = tts.synthesize(text, voice_style=style, lang="en") +text = "Supertonic is a lightning fast, on-device TTS system." + +wav, duration = tts.synthesize( + text=text, + lang="en", # Language code (e.g., "en", "ko", "na" for language-agnostic) + voice_style=style, # Voice style object + total_steps=8, # Quality: 5 (low) to 12 (high), default 8 (medium) + speed=1.05, # Speed: 0.7 (slow) to 2.0 (fast) +) +# wav: numpy array of shape (1, num_samples,) with dtype=np.float32, sampled at 44100 Hz +# duration: numpy array of shape (1,) containing the duration of the generated audio in seconds tts.save_audio(wav, "output.wav") -print(f"Generated {duration:.2f}s of audio") +# import soundfile as sf +# sf.write("output.wav", wav.squeeze(), 44100) + +print(f"Generated {duration[0]:.2f}s of audio") ``` ## Getting Started @@ -157,13 +193,14 @@ In Xcode: Targets β†’ ExampleiOSApp β†’ Signing: select your Team, then choose y +--- ### Technical Details - **Runtime**: ONNX Runtime for cross-platform inference - **Browser Support**: onnxruntime-web for client-side inference - **Batch Processing**: Supports batch inference for improved throughput -- **Audio Output**: Outputs 16-bit WAV files +- **Audio Output**: Outputs 44.1kHz 16-bit WAV files ## Performance Highlights @@ -175,7 +212,40 @@ Supertonic 3 is designed for practical on-device inference: compact enough to ru Supertonic 3 reading accuracy compared with measured model ranges and VoxCPM2

-Across measured languages, Supertonic 3 stays within a competitive WER/CER range against much larger open TTS models such as VoxCPM2, while preserving a lightweight on-device deployment path. Asterisked languages use CER; the others use WER. +Evaluated on the **[Minimax-MLS-test](https://huggingface.co/datasets/MiniMaxAI/TTS-MLS-Test) benchmark**, Supertonic 3 stays within a competitive WER/CER range against much larger open TTS models such as VoxCPM2, while preserving a lightweight on-device deployment path. Asterisked languages (`*`) use CER; the others use WER. + +
+πŸ“Š Detailed per-language results (WER / CER*) + +
+ +| Lang | VoxCPM2 | OmniVoice | Qwen3-TTS | Supertonic 2 | **Supertonic 3** | +|---|:---:|:---:|:---:|:---:|:---:| +| arabic\* | 4.14 | 1.74 | β€” | β€” | **2.14** | +| czech | 23.73 | 2.40 | β€” | β€” | **3.02** | +| dutch | 0.84 | 0.77 | β€” | β€” | **1.47** | +| english | 2.11 | 2.02 | 2.25 | 2.52 | **2.06** | +| finnish | 2.29 | 3.94 | β€” | β€” | **5.40** | +| french | 4.41 | 4.74 | 3.82 | 5.09 | **4.89** | +| german | 0.85 | 0.96 | 0.52 | β€” | **0.86** | +| greek | 3.22 | 2.96 | β€” | β€” | **3.54** | +| hindi\* | 5.85 | 5.14 | β€” | β€” | **5.34** | +| indonesian | 1.25 | 1.67 | β€” | β€” | **1.34** | +| italian | 1.74 | 1.29 | 1.40 | β€” | **1.75** | +| japanese\* | 3.35 | 3.81 | 3.67 | β€” | **4.61** | +| korean\* | 4.70 | 3.22 | 4.07 | 3.65 | **3.26** | +| polish | 1.30 | 0.64 | β€” | β€” | **1.63** | +| portuguese | 1.74 | 1.40 | 1.21 | 1.52 | **2.48** | +| romanian | 22.39 | 2.29 | β€” | β€” | **2.19** | +| russian | 3.31 | 4.53 | 4.48 | β€” | **3.99** | +| spanish | 1.34 | 0.99 | 0.75 | 1.81 | **1.13** | +| turkish | 0.88 | 2.18 | β€” | β€” | **1.00** | +| ukrainian | 5.85 | 0.71 | β€” | β€” | **1.23** | +| vietnamese | 1.48 | 0.79 | β€” | β€” | **4.49** | + +> Lower is better. `*` indicates CER (character error rate); all other rows use WER (word error rate). Dashes (`β€”`) indicate the model does not officially support the language or no result is available. + +
### Supertonic 2 to Supertonic 3 @@ -223,29 +293,7 @@ Turns any webpage into audio in under one second, delivering lightning-fast, on- https://github.com/user-attachments/assets/cc8a45fc-5c3e-4b2c-8439-a14c3d00d91c -## Why Supertonic? - -- **Blazingly Fast**: Optimized for low-latency, on-device speech generation across desktop, browser, and edge deployments -- **Lightweight**: Compact ONNX assets designed for efficient local execution -- **On-Device Capable**: Complete privacy and zero network dependency -- **Accurate Reading**: Improved reading stability with fewer repeat and skip failures -- **Expressive Tags**: Supports simple expression tags such as ``, ``, and `` -- **Flexible Deployment**: Ready-to-use examples across Python, JavaScript, browser, mobile, and native runtimes - -## Language Support - -Supertonic 3 supports 31 languages: - -| Code | Language | Code | Language | Code | Language | Code | Language | -|------|----------|------|----------|------|----------|------|----------| -| `en` | English | `ko` | Korean | `ja` | Japanese | `ar` | Arabic | -| `bg` | Bulgarian | `cs` | Czech | `da` | Danish | `de` | German | -| `el` | Greek | `es` | Spanish | `et` | Estonian | `fi` | Finnish | -| `fr` | French | `hi` | Hindi | `hr` | Croatian | `hu` | Hungarian | -| `id` | Indonesian | `it` | Italian | `lt` | Lithuanian | `lv` | Latvian | -| `nl` | Dutch | `pl` | Polish | `pt` | Portuguese | `ro` | Romanian | -| `ru` | Russian | `sk` | Slovak | `sl` | Slovenian | `sv` | Swedish | -| `tr` | Turkish | `uk` | Ukrainian | `vi` | Vietnamese | | | +## Programming Language Support We provide ready-to-use TTS inference examples across multiple ecosystems: @@ -373,6 +421,19 @@ Supertonic is designed to handle complex, real-world text inputs that contain na | **Transformers.js** | Hugging Face's JS library with Supertonic support | [GitHub PR](https://github.com/huggingface/transformers.js/pull/1459) Β· [Demo](https://huggingface.co/spaces/webml-community/Supertonic-TTS-WebGPU) | | **Pinokio** | 1-click localhost cloud for Mac, Windows, and Linux | [Pinokio](https://pinokio.co/) Β· [GitHub](https://github.com/SUP3RMASS1VE/SuperTonic-TTS) | +## Models & Versions + +| | **Supertonic 3** | Supertonic 2 | Supertonic 1 | +|---|:---:|:---:|:---:| +| **Status** | 🟒 Latest | Stable | Legacy | +| **Parameters** | ~99M | ~66M | ~66M | +| **Languages** | 31 | 5 | 1 (en) | +| **Expression Tags** | βœ… 10 tags | β€” | β€” | +| **Code** | [main](https://github.com/supertone-inc/supertonic) | [release/supertonic-2](https://github.com/supertone-inc/supertonic/tree/release/supertonic-2) | β€” | +| **Weights** | [πŸ€— HF](https://huggingface.co/Supertone/supertonic-3) | [πŸ€— HF](https://huggingface.co/Supertone/supertonic-2) | [πŸ€— HF](https://huggingface.co/Supertone/supertonic) | +| **Interactive Demo** | [πŸ€— Space](https://huggingface.co/spaces/Supertone/supertonic-3) | [πŸ€— Space](https://huggingface.co/spaces/Supertone/supertonic-2) | [πŸ€— Space](https://huggingface.co/spaces/Supertone/supertonic#interactive-demo) | +| **Audio Samples** | [DemoPage](https://supertonic3.github.io/) | β€” | [DemoPage](https://supertonictts.github.io/) | + ## Citation The following papers describe the core technologies used in Supertonic. If you use this system in your research or find these techniques useful, please consider citing the relevant papers: diff --git a/cpp/helper.cpp b/cpp/helper.cpp index 5933c9e..1545c99 100644 --- a/cpp/helper.cpp +++ b/cpp/helper.cpp @@ -12,7 +12,7 @@ using json = nlohmann::json; // Available languages for multilingual TTS -const std::vector AVAILABLE_LANGS = {"en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"}; +const std::vector AVAILABLE_LANGS = {"en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"}; // Global tensor buffers for memory management static std::vector> g_tensor_buffers_float; diff --git a/csharp/Helper.cs b/csharp/Helper.cs index 72867b9..3569ea1 100644 --- a/csharp/Helper.cs +++ b/csharp/Helper.cs @@ -13,7 +13,7 @@ namespace Supertonic // Available languages for multilingual TTS public static class Languages { - public static readonly string[] Available = { "en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi" }; + public static readonly string[] Available = { "en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na" }; } // ============================================================================ diff --git a/flutter/lib/helper.dart b/flutter/lib/helper.dart index ed554b6..734380e 100644 --- a/flutter/lib/helper.dart +++ b/flutter/lib/helper.dart @@ -12,7 +12,7 @@ final logger = Logger( ); // Available languages for multilingual TTS -const List availableLangs = ['en', 'ko', 'ja', 'ar', 'bg', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'hi', 'hr', 'hu', 'id', 'it', 'lt', 'lv', 'nl', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'vi']; +const List availableLangs = ['en', 'ko', 'ja', 'ar', 'bg', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'hi', 'hr', 'hu', 'id', 'it', 'lt', 'lv', 'nl', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'vi', 'na']; bool isValidLang(String lang) => availableLangs.contains(lang); diff --git a/go/helper.go b/go/helper.go index f3c1d97..f456469 100644 --- a/go/helper.go +++ b/go/helper.go @@ -19,7 +19,7 @@ import ( ) // Available languages for multilingual TTS -var AvailableLangs = []string{"en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"} +var AvailableLangs = []string{"en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"} // Config structures type SpecProcessorConfig struct { diff --git a/ios/ExampleiOSApp/TTSService.swift b/ios/ExampleiOSApp/TTSService.swift index 58a25b8..65c9096 100644 --- a/ios/ExampleiOSApp/TTSService.swift +++ b/ios/ExampleiOSApp/TTSService.swift @@ -35,7 +35,8 @@ final class TTSService { case tr = "tr" case uk = "uk" case vi = "vi" - + case na = "na" + var displayName: String { switch self { case .en: return "English" @@ -69,6 +70,7 @@ final class TTSService { case .tr: return "Turkish" case .uk: return "Ukrainian" case .vi: return "Vietnamese" + case .na: return "Auto (language-agnostic)" } } } diff --git a/java/Helper.java b/java/Helper.java index 0f1c978..e09cbad 100644 --- a/java/Helper.java +++ b/java/Helper.java @@ -22,7 +22,7 @@ import java.util.regex.Matcher; * Available languages for multilingual TTS */ class Languages { - public static final List AVAILABLE = Arrays.asList("en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"); + public static final List AVAILABLE = Arrays.asList("en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"); public static boolean isValid(String lang) { return AVAILABLE.contains(lang); diff --git a/nodejs/helper.js b/nodejs/helper.js index 2bfedfc..a455e76 100644 --- a/nodejs/helper.js +++ b/nodejs/helper.js @@ -5,7 +5,7 @@ import * as ort from 'onnxruntime-node'; const __filename = fileURLToPath(import.meta.url); -const AVAILABLE_LANGS = ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"]; +const AVAILABLE_LANGS = ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"]; /** * Unicode text processor diff --git a/py/example_pypi.py b/py/example_pypi.py index 26f091f..d1c1c6f 100644 --- a/py/example_pypi.py +++ b/py/example_pypi.py @@ -13,4 +13,5 @@ wav, duration = tts.synthesize(text, voice_style=style) # duration: np.ndarray, shape = (1,) # Save to file -tts.save_audio(wav, "results/example_pypi.wav") \ No newline at end of file +tts.save_audio(wav, "results/example_pypi.wav") +print(f"Generated {duration[0]:.2f}s of audio") \ No newline at end of file diff --git a/py/helper.py b/py/helper.py index c0f12a3..ff9e4da 100644 --- a/py/helper.py +++ b/py/helper.py @@ -10,7 +10,7 @@ import onnxruntime as ort import re -AVAILABLE_LANGS = ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"] +AVAILABLE_LANGS = ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"] class UnicodeProcessor: diff --git a/rust/src/helper.rs b/rust/src/helper.rs index 032541f..8f3acbd 100644 --- a/rust/src/helper.rs +++ b/rust/src/helper.rs @@ -15,7 +15,7 @@ use rand_distr::{Distribution, Normal}; use regex::Regex; // Available languages for multilingual TTS -pub const AVAILABLE_LANGS: &[&str] = &["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"]; +pub const AVAILABLE_LANGS: &[&str] = &["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"]; pub fn is_valid_lang(lang: &str) -> bool { AVAILABLE_LANGS.contains(&lang) diff --git a/swift/Sources/Helper.swift b/swift/Sources/Helper.swift index cc551ee..f9f4260 100644 --- a/swift/Sources/Helper.swift +++ b/swift/Sources/Helper.swift @@ -4,7 +4,7 @@ import OnnxRuntimeBindings // MARK: - Available Languages -let AVAILABLE_LANGS = ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi"] +let AVAILABLE_LANGS = ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hi", "hr", "hu", "id", "it", "lt", "lv", "nl", "pl", "pt", "ro", "ru", "sk", "sl", "sv", "tr", "uk", "vi", "na"] func isValidLang(_ lang: String) -> Bool { return AVAILABLE_LANGS.contains(lang) diff --git a/web/helper.js b/web/helper.js index 3513e8d..8e16388 100644 --- a/web/helper.js +++ b/web/helper.js @@ -1,7 +1,7 @@ import * as ort from 'onnxruntime-web'; // Available languages for multilingual TTS -export const AVAILABLE_LANGS = ['en', 'ko', 'ja', 'ar', 'bg', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'hi', 'hr', 'hu', 'id', 'it', 'lt', 'lv', 'nl', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'vi']; +export const AVAILABLE_LANGS = ['en', 'ko', 'ja', 'ar', 'bg', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'hi', 'hr', 'hu', 'id', 'it', 'lt', 'lv', 'nl', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sv', 'tr', 'uk', 'vi', 'na']; export function isValidLang(lang) { return AVAILABLE_LANGS.includes(lang);