| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- """
- 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
|