feat(languages): add Slovenian (sl) to the supported languages (#995)
Slovenian was missing from SUPPORTED_LANGUAGES, so the Settings picker did not offer it and normalize_language_shortcuts dropped any shortcut bound to it. Add it as a Whisper-only entry (whisper code sl; alphacephei publishes no Slovenian VOSK model), map the Slovenian XKB layout si to it for follow-keyboard-layout, and list it on the website languages page. Fixes #970
This commit is contained in:
@@ -60,12 +60,14 @@ def test_normalize_language_shortcuts_keeps_valid_bindings() -> None:
|
||||
[
|
||||
{"shortcut": "alt+d", "language": "de"},
|
||||
{"shortcut": "ctrl+alt+g", "language": "hu"},
|
||||
{"shortcut": "ctrl+alt+s", "language": "sl"},
|
||||
{"shortcut": "f5", "language": "auto"},
|
||||
]
|
||||
)
|
||||
assert entries == [
|
||||
{"shortcut": "alt+d", "language": "de"},
|
||||
{"shortcut": "ctrl+alt+g", "language": "hu"},
|
||||
{"shortcut": "ctrl+alt+s", "language": "sl"},
|
||||
{"shortcut": "f5", "language": "auto"},
|
||||
]
|
||||
|
||||
@@ -1023,3 +1025,50 @@ def test_language_shortcut_managers_share_the_evdev_device_layer() -> None:
|
||||
assert isinstance(german.backend_instance, EvdevKeyboardBackend)
|
||||
assert isinstance(french.backend_instance, EvdevKeyboardBackend)
|
||||
assert french.backend_instance._hub is german.backend_instance._hub
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"engine,offered",
|
||||
[("whisper_cpp", True), ("whisper", True), ("remote_api", True), ("vosk", False)],
|
||||
)
|
||||
def test_settings_language_picker_offers_slovenian_on_whisper_engines(
|
||||
settings_dialog: Any, dialog_class: type[Any], engine: str, offered: bool
|
||||
) -> None:
|
||||
"""Slovenian (#970) is selectable wherever Whisper runs; VOSK has no model for it."""
|
||||
dialog = MagicMock()
|
||||
dialog.engine_combo.get_active_text.return_value = settings_dialog.ENGINE_DISPLAY_NAMES[engine]
|
||||
|
||||
with patch.object(settings_dialog, "_is_vosk_model_downloaded", return_value=False):
|
||||
dialog_class._populate_language_options(dialog)
|
||||
|
||||
appended = [c.args[0] for c in dialog.language_combo.append.call_args_list]
|
||||
assert ("sl" in appended) is offered
|
||||
assert "sk" not in appended
|
||||
|
||||
|
||||
def test_slovenian_shortcut_row_persists_through_config(
|
||||
dialog_class: type[Any], tmp_path: Any
|
||||
) -> None:
|
||||
"""A row picked as Slovenian is saved and read back, not dropped (#970)."""
|
||||
config_dir = tmp_path / "vocalinux"
|
||||
config_dir.mkdir()
|
||||
with (
|
||||
patch("vocalinux.ui.config_manager.CONFIG_DIR", str(config_dir)),
|
||||
patch("vocalinux.ui.config_manager.CONFIG_FILE", str(config_dir / "config.json")),
|
||||
patch("vocalinux.utils.system_language.detect_system_language", return_value=None),
|
||||
):
|
||||
dialog = _dialog_stub()
|
||||
dialog.config_manager = ConfigManager()
|
||||
dialog.config_manager.save_settings = dialog.config_manager.save_config
|
||||
picker, entry = MagicMock(), MagicMock()
|
||||
picker.get_active_id.return_value = "sl"
|
||||
entry.get_text.return_value = "ctrl+alt+s"
|
||||
refs = {"language_picker": picker, "shortcut_entry": entry, "row": MagicMock()}
|
||||
dialog._language_shortcut_rows = [refs]
|
||||
dialog._report_language_shortcut_rejections = MagicMock()
|
||||
|
||||
dialog_class._persist_language_shortcuts(dialog)
|
||||
|
||||
assert ConfigManager().get_language_shortcuts() == [
|
||||
{"shortcut": "ctrl+alt+s", "language": "sl"}
|
||||
]
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ class TestMainModule(unittest.TestCase):
|
||||
|
||||
self.assertEqual(LANGUAGE_CHOICES, tuple(SUPPORTED_LANGUAGES.keys()))
|
||||
# Spot-check newly exposed languages (issue #565 and catalog expansion).
|
||||
for lang in ["auto", "en-us", "hu", "ja", "ko", "ar", "nl", "pl", "uk"]:
|
||||
for lang in ["auto", "en-us", "hu", "ja", "ko", "ar", "nl", "pl", "sl", "uk"]:
|
||||
self.assertIn(lang, LANGUAGE_CHOICES)
|
||||
with patch("sys.argv", ["vocalinux", "--language", lang]):
|
||||
args = parse_arguments()
|
||||
|
||||
@@ -305,6 +305,18 @@ class TestSpeechRecognition(unittest.TestCase):
|
||||
self.assertIsNone(hu["vosk"])
|
||||
self.assertNotIn("hu", VOSK_MODEL_INFO["small"]["languages"])
|
||||
|
||||
def test_slovenian_is_whisper_only_in_catalog(self) -> None:
|
||||
"""Slovenian (issue #970) is exposed for Whisper engines, not VOSK or Slovak."""
|
||||
from vocalinux.utils.vosk_model_info import SUPPORTED_LANGUAGES
|
||||
|
||||
slovenian = SUPPORTED_LANGUAGES["sl"]
|
||||
self.assertEqual(slovenian["name"], "Slovenian")
|
||||
self.assertEqual(slovenian["whisper"], "sl")
|
||||
self.assertIsNone(slovenian["vosk"])
|
||||
for size in ("small", "medium", "large"):
|
||||
self.assertNotIn("sl", VOSK_MODEL_INFO[size]["languages"])
|
||||
self.assertNotIn("sk", SUPPORTED_LANGUAGES)
|
||||
|
||||
def test_resolve_whisper_language_maps_english_variants(self):
|
||||
"""Catalog ids like en-us/en-in must become Whisper's 'en' code."""
|
||||
from unittest.mock import patch
|
||||
@@ -314,6 +326,7 @@ class TestSpeechRecognition(unittest.TestCase):
|
||||
self.assertEqual(resolve_whisper_language("en-us"), "en")
|
||||
self.assertEqual(resolve_whisper_language("en-in"), "en")
|
||||
self.assertEqual(resolve_whisper_language("hu"), "hu")
|
||||
self.assertEqual(resolve_whisper_language("sl"), "sl")
|
||||
self.assertEqual(resolve_whisper_language("ja"), "ja")
|
||||
self.assertIsNone(resolve_whisper_language("auto"))
|
||||
# Unknown catalog ids pass through unchanged.
|
||||
|
||||
@@ -24,6 +24,8 @@ def isolated_config(tmp_path, monkeypatch):
|
||||
("de", "de"),
|
||||
("cz", "cs"),
|
||||
("se", "sv"),
|
||||
("si", "sl"),
|
||||
("sk", None),
|
||||
("us", "en-us"),
|
||||
("gb", "en-us"),
|
||||
("xyz", None),
|
||||
@@ -48,6 +50,8 @@ def test_layouts_map_onto_catalogue_entries(layout, expected):
|
||||
("nb_NO", "no"),
|
||||
("nb_NO.UTF-8", "no"),
|
||||
("nn_NO", "no"),
|
||||
("sl_SI.UTF-8", "sl"),
|
||||
("sk_SK.UTF-8", None),
|
||||
("C", None),
|
||||
("POSIX", None),
|
||||
("C.UTF-8", None),
|
||||
|
||||
Reference in New Issue
Block a user