- i18n 사전 100% (break/overtime/leave/clockin) — 50+ 신규 키 - 런타임 재번역 인프라 (ui/i18n_runtime.py) — 재시작 없이 메인 UI 적용 - MealController 분리 — 점심/저녁 토글을 컨트롤러로 추출 - 통합 테스트 +15 (S36-S52: 온보딩/salary/CSV/notification dedupe 등) - pytest 신규 4종 + i18n_runtime 테스트 (총 122 케이스, 90→122) - README/INSTALL/CLAUDE/AGENTS v2.6+ 아키텍처 반영
107 lines
2.9 KiB
Python
107 lines
2.9 KiB
Python
"""
|
|
ui.i18n_runtime 단위 테스트.
|
|
|
|
QApplication이 필요해서 offscreen으로.
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
os.environ.setdefault('QT_QPA_PLATFORM', 'offscreen')
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def qapp():
|
|
from PyQt5.QtWidgets import QApplication
|
|
app = QApplication.instance() or QApplication([])
|
|
yield app
|
|
|
|
|
|
@pytest.fixture
|
|
def i18n():
|
|
from core import i18n
|
|
from ui import i18n_runtime
|
|
saved_lang = i18n.get_language()
|
|
yield i18n_runtime
|
|
i18n_runtime.clear()
|
|
i18n.set_language(saved_lang)
|
|
|
|
|
|
def test_register_applies_initial_text(qapp, i18n):
|
|
from PyQt5.QtWidgets import QLabel
|
|
from core.i18n import set_language
|
|
set_language('ko')
|
|
label = QLabel()
|
|
i18n.register(label, 'btn.save')
|
|
assert label.text() == '💾 저장'
|
|
|
|
|
|
def test_retranslate_after_language_change(qapp, i18n):
|
|
from PyQt5.QtWidgets import QLabel
|
|
from core.i18n import set_language
|
|
set_language('ko')
|
|
label = QLabel()
|
|
i18n.register(label, 'btn.close')
|
|
assert label.text() == '닫기'
|
|
|
|
i18n.set_language_and_retranslate('en')
|
|
assert label.text() == 'Close'
|
|
|
|
i18n.set_language_and_retranslate('ko')
|
|
assert label.text() == '닫기'
|
|
|
|
|
|
def test_setter_kwarg_for_window_title(qapp, i18n):
|
|
from PyQt5.QtWidgets import QDialog
|
|
from core.i18n import set_language
|
|
set_language('ko')
|
|
dlg = QDialog()
|
|
i18n.register(dlg, 'window.settings', setter='setWindowTitle')
|
|
assert dlg.windowTitle() == '⚙️ 설정'
|
|
|
|
i18n.set_language_and_retranslate('en')
|
|
assert dlg.windowTitle() == '⚙️ Settings'
|
|
|
|
|
|
def test_post_callback_applied(qapp, i18n):
|
|
from PyQt5.QtWidgets import QLabel
|
|
from core.i18n import set_language
|
|
set_language('ko')
|
|
label = QLabel()
|
|
i18n.register(label, 'btn.save', post=lambda t: f"[{t}]")
|
|
assert label.text() == '[💾 저장]'
|
|
|
|
i18n.set_language_and_retranslate('en')
|
|
assert label.text() == '[💾 Save]'
|
|
|
|
|
|
def test_dead_widget_pruned(qapp, i18n):
|
|
"""삭제된 위젯은 retranslate에서 자동 제외 (RuntimeError 안 남)."""
|
|
from PyQt5.QtWidgets import QLabel
|
|
from core.i18n import set_language
|
|
set_language('ko')
|
|
|
|
label = QLabel()
|
|
i18n.register(label, 'btn.cancel')
|
|
label.deleteLater()
|
|
label = None # weakref 끊기
|
|
|
|
# Qt 이벤트 처리 한 번 강제로 (deleteLater 처리)
|
|
qapp.processEvents()
|
|
|
|
# 죽은 위젯이 있어도 예외 없이 실행돼야 함
|
|
i18n.set_language_and_retranslate('en')
|
|
i18n.set_language_and_retranslate('ko')
|
|
|
|
|
|
def test_kwargs_format(qapp, i18n):
|
|
from PyQt5.QtWidgets import QLabel
|
|
from core.i18n import set_language
|
|
set_language('ko')
|
|
label = QLabel()
|
|
# 'tray.tooltip_remaining': '퇴근까지: {time}'
|
|
i18n.register(label, 'tray.tooltip_remaining', kwargs={'time': '01:23'})
|
|
assert '01:23' in label.text()
|