diff --git a/Furious/Window/SingTUNSettingsDialog.py b/Furious/Window/SingTUNSettingsDialog.py index 1bd3c233..c17fc4ed 100644 --- a/Furious/Window/SingTUNSettingsDialog.py +++ b/Furious/Window/SingTUNSettingsDialog.py @@ -355,10 +355,9 @@ class SingTUNSettingsDialog(AppQTransientDialog): layout.addWidget(self.errorLabel) - buttons = AppQDialogButtonBox( - AppQDialogButtonBox.StandardButton.Ok - | AppQDialogButtonBox.StandardButton.Cancel - ) + buttons = AppQDialogButtonBox(QtCore.Qt.Orientation.Horizontal) + buttons.addButton(_('OK'), AppQDialogButtonBox.ButtonRole.AcceptRole) + buttons.addButton(_('Cancel'), AppQDialogButtonBox.ButtonRole.RejectRole) connectWeakly(buttons.accepted, self, 'accept') connectWeakly(buttons.rejected, self, 'reject') diff --git a/tests/README.md b/tests/README.md index aef24e60..662e0a0d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -109,7 +109,7 @@ worker. Choose tests by the changed contract rather than by filename alone. | [test_python_compatibility.py](test_python_compatibility.py) | Once-only implementation selection without import-time metadata enumeration, exact affix removal, both metadata entry-point APIs and plugin discovery, distribution-version failures, real modern/legacy executor cancellation and statistics-owner shutdown, and profile import with an unsubscriptable collections ABC. Runs actual interpreter APIs alongside legacy-shape simulations; native-only cases skip on Python 3.8. The version matrix executes this module with the cold-import checks. | | [test_frozenlib.py](test_frozenlib.py) | Nested state guards, cleanup isolation, native peer destruction during connection/theme/translation/cleanup notifications, bounded caches/throttling, dual-stack probe selection, mocked proxy/DNS/routes/startup/session boundaries and failure handling. | | [test_native_tun_semantics.py](test_native_tun_semantics.py) | Xray/Hysteria2 runtime-copy TUN preservation/replacement, managed-TUN failures, download-test stripping, prevention of a second tun2socks owner. | -| [test_sing_tun.py](test_sing_tun.py) | tun2socks engine default, saved engine choices and ownership-aware reconnect notices, sing-tun Go stack default, development-stack and congestion-control compatibility, independent backend settings and host defaults, selected-only snapshots, captured TUN log sources in both startup paths, staged settings and malformed storage, SOCKS authentication/UDP, harmless real spawn/status/stop, native readiness, cancellation, synchronous compatibility, mocked DNS/routing ownership including development IPv6 rule ordering and refused cleanup. | +| [test_sing_tun.py](test_sing_tun.py) | tun2socks engine default, saved engine choices and ownership-aware reconnect notices, sing-tun Go stack default, development-stack and congestion-control compatibility, independent backend settings and host defaults, initial and live dialog-button translation, selected-only snapshots, captured TUN log sources in both startup paths, staged settings and malformed storage, SOCKS authentication/UDP, harmless real spawn/status/stop, native readiness, cancellation, synchronous compatibility, mocked DNS/routing ownership including development IPv6 rule ordering and refused cleanup. | | [test_subscription_sync.py](test_subscription_sync.py) | Group-local preparation/commit, stable duplicate identity, atomic failure, preservation of newer local metadata, rejection of changed source state. | | [test_subscription_manager.py](test_subscription_manager.py) | Stable request generations, provider metadata, batch/partial failures, timer policy, targeted updates, real Stop Updates input, worker responsiveness, cancellation and synchronous shutdown ownership. | | [test_subscription_scalability.py](test_subscription_scalability.py) | Deterministic 1/3/8-group preparation and commit with 1,500 profiles per group and bounded workers; uses the offline benchmark helper. | diff --git a/tests/test_sing_tun.py b/tests/test_sing_tun.py index 303a2d91..44058c6b 100644 --- a/tests/test_sing_tun.py +++ b/tests/test_sing_tun.py @@ -55,7 +55,7 @@ from Furious.Controllers.ConnectionController import ( ConnectionController, ConnectionState, ) -from Furious.Qt import gettext as _ +from Furious.Qt import AppQDialogButtonBox, gettext as _ from Furious.Service.RuntimeLease import RuntimeEventRouter, RuntimeLeaseState from Furious.Service.LogManager import LogManager, TUN_LOG_CATEGORY @@ -600,6 +600,41 @@ class SingTUNUIAndStorageTest(unittest.TestCase): processQtEvents() self.assertFalse(isValid(dialog)) + def testDialogButtonsUseInitialLanguageAndFollowLanguageChanges(self): + for initialLanguage in ('ZH', 'RU', 'EN'): + with self.subTest(language=initialLanguage), isolatedSettings(): + AppSettings.set('Language', initialLanguage) + + dialog = self._dialog({}) + buttons = dialog.findChild(AppQDialogButtonBox) + buttonsByRole = { + buttons.buttonRole(button): button for button in buttons.buttons() + } + cancelButton = buttonsByRole[buttons.ButtonRole.RejectRole] + okButton = buttonsByRole[buttons.ButtonRole.AcceptRole] + + original = dialog.document() + + dialog.open() + processQtEvents() + + try: + self.assertEqual(cancelButton.text(), _('Cancel')) + self.assertEqual(okButton.text(), _('OK')) + + for language in ('EN', 'ZH', 'RU', 'EN'): + AppSettings.set('Language', language) + Mixins.QTranslatable.retranslateAll() + processQtEvents() + + self.assertEqual(cancelButton.text(), _('Cancel')) + self.assertEqual(okButton.text(), _('OK')) + + self.assertEqual(dialog.document(), original) + finally: + dialog.reject() + processQtEvents() + def testUnsupportedSettingsMessagesAreLocalizedAndRetranslatable(self): """Reject unknown options with localized text without committing settings.""" cases = (