""" Tests for the Internationalization (i18n) UI component (Story 7.12). """ import pytest from pathlib import Path from PyQt6.QtWidgets import QApplication from PyQt6.QtCore import QLocale from src.ui.i18n import ( SupportedLanguage, TRANSLATIONS, I18nManager, get_i18n_manager, t, ) @pytest.fixture def app(qtbot): """Create QApplication for tests.""" return QApplication.instance() or QApplication([]) @pytest.fixture def clean_manager(): """Create a fresh I18nManager for testing.""" import src.ui.i18n as i18n i18n._i18n_manager_instance = None manager = I18nManager() return manager class TestSupportedLanguage: """Tests for SupportedLanguage enum.""" def test_language_values(self): """Test SupportedLanguage enum values.""" assert SupportedLanguage.CHINESE_SIMPLIFIED.code == "zh_CN" assert SupportedLanguage.ENGLISH.code == "en_US" def test_native_names(self): """Test native language names.""" assert SupportedLanguage.CHINESE_SIMPLIFIED.native_name == "简体中文" assert SupportedLanguage.ENGLISH.native_name == "English" def test_english_names(self): """Test English language names.""" assert SupportedLanguage.CHINESE_SIMPLIFIED.english_name == "Chinese (Simplified)" assert SupportedLanguage.ENGLISH.english_name == "English" def test_from_locale_chinese(self): """Test getting language from Chinese locale.""" locale = QLocale(QLocale.Language.Chinese, QLocale.Country.China) lang = SupportedLanguage.from_locale(locale) assert lang == SupportedLanguage.CHINESE_SIMPLIFIED def test_from_locale_english(self): """Test getting language from English locale.""" locale = QLocale(QLocale.Language.English, QLocale.Country.UnitedStates) lang = SupportedLanguage.from_locale(locale) assert lang == SupportedLanguage.ENGLISH class TestTranslations: """Tests for translation strings.""" def test_translations_structure(self): """Test that translations have proper structure.""" for key, translations in TRANSLATIONS.items(): assert "zh_CN" in translations assert "en_US" in translations def test_common_translations_exist(self): """Test that common UI strings have translations.""" # Menu items assert "menu.file" in TRANSLATIONS assert "menu.edit" in TRANSLATIONS # Buttons assert "button.ok" in TRANSLATIONS assert "button.cancel" in TRANSLATIONS # Status assert "status.ready" in TRANSLATIONS assert "status.translating" in TRANSLATIONS def test_translation_values(self): """Test specific translation values.""" assert TRANSLATIONS["button.ok"]["zh_CN"] == "确定" assert TRANSLATIONS["button.ok"]["en_US"] == "OK" assert TRANSLATIONS["button.cancel"]["zh_CN"] == "取消" assert TRANSLATIONS["button.cancel"]["en_US"] == "Cancel" def test_formatted_translations(self): """Test translations with format placeholders.""" assert "{count}" in TRANSLATIONS["msg.added_files"]["zh_CN"] assert "{count}" in TRANSLATIONS["msg.added_files"]["en_US"] assert "{path}" in TRANSLATIONS["msg.file_not_found"]["zh_CN"] assert "{path}" in TRANSLATIONS["msg.file_not_found"]["en_US"] class TestI18nManager: """Tests for I18nManager.""" def test_initialization(self, clean_manager): """Test manager initialization.""" assert isinstance(clean_manager, I18nManager) # Default to Chinese assert clean_manager.current_language == SupportedLanguage.CHINESE_SIMPLIFIED def test_current_language(self, clean_manager): """Test current_language property.""" assert clean_manager.current_language == SupportedLanguage.CHINESE_SIMPLIFIED clean_manager.set_language(SupportedLanguage.ENGLISH) assert clean_manager.current_language == SupportedLanguage.ENGLISH def test_current_locale(self, clean_manager): """Test current_locale property.""" locale = clean_manager.current_locale assert isinstance(locale, QLocale) def test_set_language_chinese(self, clean_manager): """Test setting Chinese language.""" clean_manager.set_language(SupportedLanguage.CHINESE_SIMPLIFIED) assert clean_manager.current_language == SupportedLanguage.CHINESE_SIMPLIFIED def test_set_language_english(self, clean_manager): """Test setting English language.""" clean_manager.set_language(SupportedLanguage.ENGLISH) assert clean_manager.current_language == SupportedLanguage.ENGLISH def test_translate_chinese(self, clean_manager): """Test translation to Chinese.""" clean_manager.set_language(SupportedLanguage.CHINESE_SIMPLIFIED) text = clean_manager.translate("button.ok") assert text == "确定" text = clean_manager.translate("button.cancel") assert text == "取消" def test_translate_english(self, clean_manager): """Test translation to English.""" clean_manager.set_language(SupportedLanguage.ENGLISH) text = clean_manager.translate("button.ok") assert text == "OK" text = clean_manager.translate("button.cancel") assert text == "Cancel" def test_translate_with_format(self, clean_manager): """Test translation with format arguments.""" clean_manager.set_language(SupportedLanguage.ENGLISH) text = clean_manager.translate("msg.added_files", count=5) assert "5" in text assert "file" in text def test_translate_unknown_key(self, clean_manager): """Test translating unknown key returns key itself.""" text = clean_manager.translate("unknown.key") assert text == "unknown.key" def test_shorthand_t(self, clean_manager): """Test shorthand t() function.""" clean_manager.set_language(SupportedLanguage.CHINESE_SIMPLIFIED) text = clean_manager.t("button.ok") assert text == "确定" def test_language_changed_signal(self, app, clean_manager, qtbot): """Test that language_changed signal is emitted.""" signals = [] def on_language_changed(lang): signals.append(lang) clean_manager.language_changed.connect(on_language_changed) clean_manager.set_language(SupportedLanguage.ENGLISH) assert len(signals) == 1 assert signals[0] == SupportedLanguage.ENGLISH def test_retranslate_callback(self, clean_manager): """Test retranslate callbacks are called on language change.""" callback_calls = [] def callback(): callback_calls.append(True) clean_manager.register_retranslate_callback(callback) # Change language clean_manager.set_language(SupportedLanguage.ENGLISH) assert len(callback_calls) == 1 # Change again clean_manager.set_language(SupportedLanguage.CHINESE_SIMPLIFIED) assert len(callback_calls) == 2 def test_get_language_menu(self, clean_manager): """Test getting language selection menu.""" menu = clean_manager.get_language_menu() assert menu is not None # Should have actions for all languages assert menu.isEmpty() is False class TestModuleLevelFunctions: """Tests for module-level functions.""" def test_get_i18n_manager(self): """Test getting i18n manager singleton.""" import src.ui.i18n as i18n i18n._i18n_manager_instance = None manager = get_i18n_manager() assert manager is not None assert isinstance(manager, I18nManager) def test_t_function(self): """Test module-level t() function.""" import src.ui.i18n as i18n i18n._i18n_manager_instance = None i18n._i18n_manager_instance = I18nManager() # Set to Chinese i18n._i18n_manager_instance.set_language(SupportedLanguage.CHINESE_SIMPLIFIED) text = t("button.ok") assert text == "确定" def test_singleton_persistence(self): """Test that singleton returns same instance.""" import src.ui.i18n as i18n i18n._i18n_manager_instance = None manager1 = get_i18n_manager() manager2 = get_i18n_manager() assert manager1 is manager2 class TestTranslationCoverage: """Tests to ensure translation coverage.""" def test_all_categories(self): """Test translations for all UI categories.""" # Menus assert any(key.startswith("menu.") for key in TRANSLATIONS) # Actions assert any(key.startswith("action.") for key in TRANSLATIONS) # Buttons assert any(key.startswith("button.") for key in TRANSLATIONS) # Labels assert any(key.startswith("label.") for key in TRANSLATIONS) # Status assert any(key.startswith("status.") for key in TRANSLATIONS) # Dialogs assert any(key.startswith("dialog.") for key in TRANSLATIONS) # Messages assert any(key.startswith("msg.") for key in TRANSLATIONS) def test_glossary_translations(self): """Test glossary-related translations.""" assert "glossary.add_term" in TRANSLATIONS assert "glossary.character" in TRANSLATIONS assert "glossary.skill" in TRANSLATIONS def test_log_translations(self): """Test log-related translations.""" assert "log.level_info" in TRANSLATIONS assert "log.level_error" in TRANSLATIONS def test_theme_translations(self): """Test theme-related translations.""" assert "theme.light" in TRANSLATIONS assert "theme.dark" in TRANSLATIONS