Refactor translation

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2025-03-20 00:22:32 +08:00
parent d3a2fd46ff
commit d600f86d66
35 changed files with 175 additions and 548 deletions
-7
View File
@@ -34,13 +34,6 @@ __all__ = ['CoreManager']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Unable to connect',
'Routing option with direct rules is not allowed in VPN mode',
)
def fixLogObjectPath(config: ConfigurationFactory, attr: str, value: str, log=True):
try:
+45 -30
View File
@@ -4,8 +4,8 @@ TRANSLATION = {
"Furious.QtFramework.QtWidgets",
"Furious.Widget.UserServersQTableWidget",
"Furious.Widget.UserSubsQTableWidget",
"Furious.Window.UserSubsWindow",
"Furious.Widget.XrayAssetViewerQListWidget"
"Furious.Widget.XrayAssetViewerQListWidget",
"Furious.Window.UserSubsWindow"
],
"RU": "Удалить",
"ZH": "删除",
@@ -252,8 +252,8 @@ TRANSLATION = {
},
"Save As...": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Сохранить как...",
"ZH": "另存为...",
@@ -261,7 +261,7 @@ TRANSLATION = {
},
"Close Window": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Закрыть окно",
"ZH": "关闭窗口",
@@ -269,8 +269,8 @@ TRANSLATION = {
},
"File": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow",
"Furious.Window.XrayAssetViewerWindow"
],
"RU": "Файл",
@@ -303,8 +303,8 @@ TRANSLATION = {
},
"Copy": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Копировать",
"ZH": "复制",
@@ -320,9 +320,9 @@ TRANSLATION = {
},
"Select All": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Widget.UserServersQTableWidget",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Выбрать все",
"ZH": "全选",
@@ -338,8 +338,8 @@ TRANSLATION = {
},
"Edit": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Редактировать",
"ZH": "编辑",
@@ -347,8 +347,8 @@ TRANSLATION = {
},
"Zoom In": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Увеличить маштаб",
"ZH": "变大",
@@ -356,8 +356,8 @@ TRANSLATION = {
},
"Zoom Out": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Уменьшить маштаб",
"ZH": "变小",
@@ -365,8 +365,8 @@ TRANSLATION = {
},
"View": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Вид",
"ZH": "显示",
@@ -382,8 +382,8 @@ TRANSLATION = {
},
"Save File": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.Window.LogViewerWindow"
"Furious.Window.LogViewerWindow",
"Furious.Window.TextEditorWindow"
],
"RU": "Сохранить файл",
"ZH": "保存文件",
@@ -399,8 +399,8 @@ TRANSLATION = {
},
"Invalid server configuration": {
"source": [
"Furious.Window.TextEditorWindow",
"Furious.TrayActions.Connect"
"Furious.TrayActions.Connect",
"Furious.Window.TextEditorWindow"
],
"RU": "Неверная конфигурация сервера",
"ZH": "无效的服务器配置",
@@ -418,8 +418,11 @@ TRANSLATION = {
"source": [
"Furious.Widget.GuiHysteria1",
"Furious.Widget.GuiHysteria2",
"Furious.Widget.UserServersQTableWidget",
"Furious.Widget.UserSubsQTableWidget"
"Furious.Widget.GuiShadowsocks",
"Furious.Widget.GuiTrojan",
"Furious.Widget.GuiVLESS",
"Furious.Widget.GuiVMess",
"Furious.Widget.UserServersQTableWidget"
],
"RU": "Примечание",
"ZH": "别名",
@@ -567,7 +570,8 @@ TRANSLATION = {
},
"New Empty Configuration": {
"source": [
"Furious.Widget.UserServersQTableWidget"
"Furious.Widget.UserServersQTableWidget",
"Furious.Window.AppMainWindow"
],
"RU": "Создать новую пустую конфигурацию",
"ZH": "新建空白配置",
@@ -599,8 +603,8 @@ TRANSLATION = {
},
"Connecting": {
"source": [
"Furious.Widget.UserServersQTableWidget",
"Furious.TrayActions.Connect"
"Furious.TrayActions.Connect",
"Furious.Widget.UserServersQTableWidget"
],
"RU": "Подключение",
"ZH": "正在连接",
@@ -672,9 +676,9 @@ TRANSLATION = {
},
"Exit": {
"source": [
"Furious.TrayActions.Exit",
"Furious.Window.LogViewerWindow",
"Furious.Window.XrayAssetViewerWindow",
"Furious.TrayActions.Exit"
"Furious.Window.XrayAssetViewerWindow"
],
"RU": "Выход",
"ZH": "退出",
@@ -864,7 +868,7 @@ TRANSLATION = {
],
"RU": "Открыть папку приложения",
"ZH": "打开应用程序文件夹",
"isReviewed": "True",
"isReviewed": "True"
},
"Check For Updates": {
"source": [
@@ -1360,5 +1364,16 @@ TRANSLATION = {
"RU": "Режим энергосбережения",
"ZH": "省电模式",
"isReviewed": "True"
},
"OK": {
"source": [
"Furious.__main__",
"Furious.QtFramework.GuiEditorXXX",
"Furious.Widget.IndentSpinBox",
"Furious.Window.UserSubsWindow"
],
"RU": "OK",
"ZH": "OK",
"isReviewed": "True"
}
}
+5 -21
View File
@@ -25,11 +25,9 @@ import functools
__all__ = [
'gettext',
'needTransFn',
'LANGUAGE_TO_ABBR',
'ABBR_TO_LANGUAGE',
'SUPPORTED_LANGUAGE',
'TranslationPool',
]
@@ -74,9 +72,11 @@ def installTranslation(translation):
def gettext(source, locale=None):
if locale is None:
assert APP() is not None
return translator.translate(source, AppSettings.get('Language'))
if APP() is None:
# Normally should not reach here if performing a translation
return source
else:
return translator.translate(source, AppSettings.get('Language'))
else:
assert locale in SUPPORTED_LANGUAGE
@@ -95,19 +95,3 @@ ABBR_TO_LANGUAGE = {value: key for key, value in LANGUAGE_TO_ABBR.items()}
SUPPORTED_LANGUAGE = list(LANGUAGE_TO_ABBR.values())
installTranslation(TRANSLATION)
class TranslatorHelper:
TranslationPool = list()
@staticmethod
def appendText(*texts, **kwargs):
source = kwargs.pop('source', '')
for text in texts:
if isinstance(text, str):
TranslatorHelper.TranslationPool.append([text, source])
needTransFn = functools.partial(TranslatorHelper.appendText)
TranslationPool = TranslatorHelper.TranslationPool
+2 -6
View File
@@ -18,7 +18,7 @@
from __future__ import annotations
from Furious.Interface import *
from Furious.QtFramework.DynamicTranslate import gettext as _, needTransFn
from Furious.QtFramework.DynamicTranslate import gettext as _
from Furious.QtFramework.QtWidgets import *
from Furious.Utility import *
@@ -40,8 +40,6 @@ __all__ = [
'GuiEditorWidgetQDialog',
]
needTrans = functools.partial(needTransFn, source=__name__)
class GuiEditorItemTextInput(GuiEditorItemWidgetContainer):
def __init__(self, *args, **kwargs):
@@ -309,9 +307,6 @@ class GuiEditorWidgetQGroupBox(GuiEditorWidget, AppQGroupBox):
# self.setLayout(layout)
needTrans('Cancel')
class GuiEditorWidgetQDialog(GuiEditorItemFactory, AppQDialog):
def __init__(self, *args, **kwargs):
tabText = kwargs.pop('tabText', '')
@@ -330,6 +325,7 @@ class GuiEditorWidgetQDialog(GuiEditorItemFactory, AppQDialog):
self.groupBoxes = self.groupBoxSequence()
for index, groupBox in enumerate(self.groupBoxes):
# TODO: Layout
self.tabCentralWidgetLayout.addWidget(groupBox, index // 2, index % 2)
self.tabCentralWidget.setLayout(self.tabCentralWidgetLayout)
+1 -18
View File
@@ -19,7 +19,7 @@ from __future__ import annotations
from Furious.QtFramework.Ancestors import *
from Furious.QtFramework.DynamicTheme import AppHue
from Furious.QtFramework.DynamicTranslate import gettext as _, needTransFn
from Furious.QtFramework.DynamicTranslate import gettext as _
from Furious.QtFramework.QtGui import AppQAction, AppQSeperator
from Furious.PyFramework import *
from Furious.Utility import *
@@ -55,8 +55,6 @@ __all__ = [
'showUnrecognizedConfigMBox',
]
needTrans = functools.partial(needTransFn, source=__name__)
def moveToCenter(widget, parent=None):
geometry = widget.geometry()
@@ -550,13 +548,6 @@ class AppQToolBar(QTranslatable, QToolBar):
self.setWindowTitle(_(self.windowTitle()))
needTrans(
'Delete',
'Delete these items?',
'Delete this item?',
)
class QuestionDeleteMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -584,9 +575,6 @@ class QuestionDeleteMBox(AppQMessageBox):
self.moveToCenter()
needTrans('New changes will take effect next time')
class NewChangesNextTimeMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -613,11 +601,6 @@ def showNewChangesNextTimeMBox(**kwargs):
pass
needTrans(
'Unrecognized Configuration. Please modify it in the editor',
)
class UnrecognizedConfigMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+1 -12
View File
@@ -19,7 +19,7 @@ from __future__ import annotations
from Furious.QtFramework.QtNetwork import *
from Furious.QtFramework.QtWidgets import *
from Furious.QtFramework.DynamicTranslate import gettext as _, needTransFn
from Furious.QtFramework.DynamicTranslate import gettext as _
from Furious.Utility import *
from Furious.Library import *
@@ -37,10 +37,6 @@ __all__ = ['UpdatesManager']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans('New version available')
class QuestionUpdateMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
@@ -65,13 +61,6 @@ class QuestionUpdateMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Check for updates failed',
'Go to download page?',
f'{APPLICATION_NAME} is already the latest version',
)
class UpdatesManager(AppQNetworkAccessManager):
API_URL = (
f'https://api.github.com/repos/'
+1 -23
View File
@@ -38,27 +38,6 @@ logger = logging.getLogger(__name__)
registerAppSettings('Connect', isBinary=True)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Connect',
'Connecting',
'Disconnect',
'Unable to connect',
'Server configuration empty. Please configure your server first',
'Select and press Enter to activate configuration and connect',
f'{APPLICATION_NAME} cannot find any valid http proxy '
f'endpoint in the configuration',
'Please complete your server configuration',
'Connected',
'Unknown error',
'Invalid server configuration',
'Failed to start core',
'Connection to server has been lost',
'Core terminated unexpectedly',
'Disconnected',
)
def validateProxyServer(server) -> bool:
try:
@@ -237,8 +216,7 @@ class ConnectAction(AppQAction):
mbox.setWindowTitle(_('Unable to connect'))
mbox.setText(
_(
f'{APPLICATION_NAME} cannot find any valid http proxy '
f'endpoint in the configuration'
f'{APPLICATION_NAME} cannot find any valid http proxy endpoint in the configuration'
)
)
mbox.setInformativeText(_('Please complete your server configuration'))
-4
View File
@@ -23,10 +23,6 @@ import functools
__all__ = ['EditConfigurationAction']
needTrans = functools.partial(needTransFn, source=__name__)
needTrans('Edit Configuration...')
class EditConfigurationAction(AppQAction):
def __init__(self, **kwargs):
-4
View File
@@ -23,10 +23,6 @@ import functools
__all__ = ['ExitAction']
needTrans = functools.partial(needTransFn, source=__name__)
needTrans('Exit')
class ExitAction(AppQAction):
def __init__(self, **kwargs):
-42
View File
@@ -36,13 +36,6 @@ __all__ = [
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Invalid data',
'Invalid data. The content of the clipboard is:',
)
def showImportErrorMBox(clipboard: str):
mbox = ImportErrorMBox(icon=AppQMessageBox.Icon.Critical)
@@ -75,9 +68,6 @@ def importItemFromClipboard(clipboard: str):
mbox.open()
needTrans('Import')
class ImportErrorMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -93,13 +83,6 @@ class ImportErrorMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Import',
'Import share link success',
'Imported to row',
)
class ImportMultiSuccessMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -139,12 +122,6 @@ class ImportMultiSuccessMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Import',
'Import success',
)
class ImportSuccessMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -167,16 +144,6 @@ class ImportSuccessMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Import From File...',
'Import File',
'Text files (*.json);;All files (*)',
'Error opening file',
'Invalid configuration file',
'Invalid data',
)
class ImportFromFileAction(AppQAction):
def __init__(self, **kwargs):
super().__init__(
@@ -227,9 +194,6 @@ class ImportFromFileAction(AppQAction):
mbox.open()
needTrans('Import Share Link From Clipboard')
class ImportURIFromClipboardAction(AppQAction):
def __init__(self, **kwargs):
super().__init__(_('Import Share Link From Clipboard'), **kwargs)
@@ -276,9 +240,6 @@ class ImportURIFromClipboardAction(AppQAction):
mbox.open()
needTrans('Import JSON Configuration From Clipboard')
class ImportJSONFromClipboardAction(AppQAction):
def __init__(self, **kwargs):
super().__init__(_('Import JSON Configuration From Clipboard'), **kwargs)
@@ -289,9 +250,6 @@ class ImportJSONFromClipboardAction(AppQAction):
importItemFromClipboard(clipboard)
needTrans('Import')
class ImportAction(AppQAction):
def __init__(self, **kwargs):
super().__init__(
-5
View File
@@ -35,8 +35,6 @@ registerAppSettings(
'Language', validRange=SUPPORTED_LANGUAGE, default=SMART_CHOSEN_LANGUAGE
)
needTrans = functools.partial(needTransFn, source=__name__)
class LanguageChildAction(AppQAction):
def __init__(self, *args, **kwargs):
@@ -57,9 +55,6 @@ class LanguageChildAction(AppQAction):
pass
needTrans('Language')
class LanguageAction(AppQAction):
def __init__(self, **kwargs):
super().__init__(
+6 -6
View File
@@ -27,9 +27,12 @@ BUILTIN_ROUTING = ['Bypass Mainland China', 'Global', 'Custom']
registerAppSettings('Routing', validRange=BUILTIN_ROUTING)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(*BUILTIN_ROUTING)
# ALL BUILTIN ROUTING VALUE
TRANSLATABLE_BUILTIN_ROUTING = [
_('Bypass Mainland China'),
_('Global'),
_('Custom'),
]
class RoutingChildAction(AppQAction):
@@ -47,9 +50,6 @@ class RoutingChildAction(AppQAction):
APP().systemTray.ConnectAction.trigger()
needTrans('Routing')
class RoutingAction(AppQAction):
def __init__(self, **kwargs):
if AppSettings.get('Routing') == 'Bypass':
+5 -18
View File
@@ -35,13 +35,11 @@ registerAppSettings(
)
registerAppSettings('ShowTabAndSpacesInEditor', isBinary=True)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'VPN Mode',
'VPN Mode Disabled (Administrator)',
'VPN Mode Disabled (root)',
)
# Administrator, root
TRANSLATABLE_VPN_MODE = [
_('VPN Mode Disabled (Administrator)'),
_('VPN Mode Disabled (root)'),
]
class VPNModeAction(AppQAction):
@@ -134,17 +132,6 @@ class SettingsChildAction(AppQAction):
AppSettings.turnOFF('ShowTabAndSpacesInEditor')
needTrans(
'Settings',
'Dark Mode',
'Use Monochrome Tray Icon',
'Startup On Boot',
'Power Save Mode',
'Show Progress Bar When Connecting',
'Show Tab And Spaces In Editor',
)
class SettingsAction(AppQAction):
def __init__(self, **kwargs):
if PLATFORM == 'Windows' or PLATFORM == 'Darwin':
-9
View File
@@ -27,8 +27,6 @@ BUILTIN_PROXY_MODE = ['Auto', 'NoChanges']
registerAppSettings('SystemProxyMode', validRange=BUILTIN_PROXY_MODE)
needTrans = functools.partial(needTransFn, source=__name__)
class SystemProxyChildAction(AppQAction):
def __init__(self, *args, **kwargs):
@@ -41,13 +39,6 @@ class SystemProxyChildAction(AppQAction):
AppSettings.set('SystemProxyMode', 'NoChanges')
needTrans(
'System Proxy',
'Automatically Configure System Proxy',
'Do Not Change System Proxy',
)
class SystemProxyAction(AppQAction):
def __init__(self, **kwargs):
super().__init__(
+4 -3
View File
@@ -53,10 +53,11 @@ GOLDEN_RATIO = (math.sqrt(5) + 1) / 2
PROXY_OUTBOUND_USER_EMAIL = f'user@{ORGANIZATION_DOMAIN}'
ROOT_DIR = pathlib.Path(__file__).resolve().parent.parent.parent
DATA_DIR = ROOT_DIR / APPLICATION_NAME / 'Data'
PACKAGE_DIR = ROOT_DIR / APPLICATION_NAME
DATA_DIR = PACKAGE_DIR / 'Data'
XRAY_ASSET_DIR = DATA_DIR / 'xray'
CRASH_LOG_DIR = ROOT_DIR / APPLICATION_NAME / 'CrashLog'
GEN_TRANSLATION_FILE = ROOT_DIR / APPLICATION_NAME / 'Externals' / 'GenTranslation.py'
CRASH_LOG_DIR = PACKAGE_DIR / 'CrashLog'
GEN_TRANSLATION_FILE = PACKAGE_DIR / 'Externals' / 'GenTranslation.py'
PROXY_SERVER_BYPASS = (
'localhost;*.local;127.*;10.*;172.16.*;172.17.*;'
-10
View File
@@ -47,8 +47,6 @@ registerAppSettings('AppLogViewerWidgetPointSize')
registerAppSettings('CoreLogViewerWidgetPointSize')
registerAppSettings('TunLogViewerWidgetPointSize')
needTrans = functools.partial(needTransFn, source=__name__)
def rateLimited(maxCallPerSecond):
"""
@@ -158,14 +156,6 @@ class ApplicationThemeDetector(QtCore.QObject):
super().__init__(*args, **kwargs)
needTrans(
'Already started',
'Furious Log',
'Core Log',
'Tun2socks Log',
)
class Application(ApplicationFactory, SingletonApplication):
def __init__(self, argv):
super().__init__(argv)
-22
View File
@@ -33,8 +33,6 @@ __all__ = ['GuiHysteria1']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
class GuiHy1ItemTextInput(GuiEditorItemTextInput):
def __init__(self, *args, **kwargs):
@@ -217,9 +215,6 @@ class GuiHy1ItemTLSInsecure(GuiEditorItemTextCheckBox):
self.setChecked(checked)
needTrans('Project Website')
class GuiHy1ProjectWebsiteURL(AppQLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -247,14 +242,6 @@ class GuiHy1ProjectWebsiteURL(AppQLabel):
self.setWebsiteURL()
needTrans(
'Basic Configuration',
'Remark',
'Server',
'Protocol',
)
class GuiHy1GroupBoxBasic(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Basic Configuration'), **kwargs)
@@ -269,9 +256,6 @@ class GuiHy1GroupBoxBasic(GuiEditorWidgetQGroupBox):
]
needTrans('Proxy')
class GuiHy1GroupBoxProxy(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Proxy'), **kwargs)
@@ -283,9 +267,6 @@ class GuiHy1GroupBoxProxy(GuiEditorWidgetQGroupBox):
]
needTrans('Speed')
class GuiHy1GroupBoxSpeed(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Speed'), **kwargs)
@@ -312,9 +293,6 @@ class GuiHy1GroupBoxTLS(GuiEditorWidgetQGroupBox):
]
needTrans('Other')
class GuiHy1GroupBoxOther(GuiEditorItemFactory, AppQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Other'), **kwargs)
-18
View File
@@ -33,8 +33,6 @@ __all__ = ['GuiHysteria2']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
class GuiHy2ItemBasicServer(GuiEditorItemTextInput):
def __init__(self, *args, **kwargs):
@@ -355,13 +353,6 @@ class GuiHy2ItemTLSInsecure(GuiEditorItemTextCheckBox):
self.setChecked(checked)
needTrans(
'Basic Configuration',
'Remark',
'Server',
)
class GuiHy2GroupBoxBasic(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Basic Configuration'), **kwargs)
@@ -374,9 +365,6 @@ class GuiHy2GroupBoxBasic(GuiEditorWidgetQGroupBox):
]
needTrans('Proxy')
class GuiHy2GroupBoxProxy(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Proxy'), **kwargs)
@@ -418,9 +406,6 @@ class GuiHy2GroupBoxTLS(GuiEditorWidgetQGroupBox):
]
needTrans('Project Website')
class GuiHy2ProjectWebsiteURL(AppQLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -448,9 +433,6 @@ class GuiHy2ProjectWebsiteURL(AppQLabel):
self.setWebsiteURL()
needTrans('Other')
class GuiHy2GroupBoxOther(GuiEditorItemFactory, AppQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Other'), **kwargs)
-14
View File
@@ -26,8 +26,6 @@ from Furious.Widget.GuiVTLS import *
__all__ = ['GuiShadowsocks']
needTrans = functools.partial(needTransFn, source=__name__)
def getProxyOutboundObject(config: ConfigurationFactory) -> dict:
if not isinstance(config.get('outbounds'), list):
@@ -213,15 +211,6 @@ class GuiSSItemBasicMethod(GuiEditorItemTextComboBox):
self.setText('')
needTrans(
'Basic Configuration',
'Address',
'Port',
'Encryption',
'Password',
)
class GuiSSGroupBoxBasic(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Basic Configuration'), **kwargs)
@@ -236,9 +225,6 @@ class GuiSSGroupBoxBasic(GuiEditorWidgetQGroupBox):
]
needTrans('Proxy')
class GuiSSGroupBoxProxy(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Proxy'), **kwargs)
-13
View File
@@ -26,8 +26,6 @@ from Furious.Widget.GuiVTLS import *
__all__ = ['GuiTrojan']
needTrans = functools.partial(needTransFn, source=__name__)
def getProxyOutboundObject(config: ConfigurationFactory) -> dict:
if not isinstance(config.get('outbounds'), list):
@@ -161,14 +159,6 @@ class GuiTrojanItemBasicPort(GuiEditorItemTextSpinBox):
self.setValue(0)
needTrans(
'Basic Configuration',
'Address',
'Port',
'Password',
)
class GuiTrojanGroupBoxBasic(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Basic Configuration'), **kwargs)
@@ -182,9 +172,6 @@ class GuiTrojanGroupBoxBasic(GuiEditorWidgetQGroupBox):
]
needTrans('Proxy')
class GuiTrojanGroupBoxProxy(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Proxy'), **kwargs)
-14
View File
@@ -26,8 +26,6 @@ from Furious.Widget.GuiVTLS import *
__all__ = ['GuiVLESS']
needTrans = functools.partial(needTransFn, source=__name__)
def getProxyOutboundObject(config: ConfigurationFactory) -> dict:
if not isinstance(config.get('outbounds'), list):
@@ -292,15 +290,6 @@ class GuiVLESSItemBasicFlow(GuiEditorItemTextComboBox):
self.setText('')
needTrans(
'Basic Configuration',
'Address',
'Port',
'Encryption',
'Flow',
)
class GuiVLESSGroupBoxBasic(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Basic Configuration'), **kwargs)
@@ -316,9 +305,6 @@ class GuiVLESSGroupBoxBasic(GuiEditorWidgetQGroupBox):
]
needTrans('Proxy')
class GuiVLESSGroupBoxProxy(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Proxy'), **kwargs)
-12
View File
@@ -26,8 +26,6 @@ from Furious.Widget.GuiVTLS import *
__all__ = ['GuiVMess']
needTrans = functools.partial(needTransFn, source=__name__)
def getProxyOutboundObject(config: ConfigurationFactory) -> dict:
if not isinstance(config.get('outbounds'), list):
@@ -293,13 +291,6 @@ class GuiVMessItemBasicSecurity(GuiEditorItemTextComboBox):
self.setText('')
needTrans(
'Basic Configuration',
'Address',
'Port',
)
class GuiVMessGroupBoxBasic(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Basic Configuration'), **kwargs)
@@ -315,9 +306,6 @@ class GuiVMessGroupBoxBasic(GuiEditorWidgetQGroupBox):
]
needTrans('Proxy')
class GuiVMessGroupBoxProxy(GuiEditorWidgetQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Proxy'), **kwargs)
-2
View File
@@ -28,8 +28,6 @@ from typing import Callable
__all__ = ['GuiVTLSQGroupBox']
needTrans = functools.partial(needTransFn, source=__name__)
STREAM_SECURITY = [
'',
'none',
-7
View File
@@ -30,8 +30,6 @@ from typing import Callable
__all__ = ['GuiVTransportQGroupBox']
needTrans = functools.partial(needTransFn, source=__name__)
STREAM_NETWORK = [
'tcp',
'kcp',
@@ -1440,11 +1438,6 @@ class GuiVTransportPageStackedWidget(QStackedWidget):
page.connectActivated(func)
needTrans(
'Transport',
)
class GuiVTransportQGroupBox(GuiEditorItemFactory, AppQGroupBox):
def __init__(self, **kwargs):
super().__init__(_('Transport'), **kwargs)
-8
View File
@@ -27,14 +27,6 @@ import functools
__all__ = ['IndentSpinBox']
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Set Indent',
'Indent:',
'Cancel',
)
class IndentSpinBox(AppQDialog):
def __init__(self, parent=None):
+13 -32
View File
@@ -53,8 +53,6 @@ logger = logging.getLogger(__name__)
registerAppSettings('ActivatedItemIndex')
registerAppSettings('ServerWidgetSectionSizeTable')
needTrans = functools.partial(needTransFn, source=__name__)
class SubscriptionManager(AppQNetworkAccessManager):
def __init__(self, parent):
@@ -584,35 +582,18 @@ class UserServersQTableWidgetHeaders:
return self.name
needTrans(
'Remark',
'Protocol',
'Address',
'Port',
'Transport',
'TLS',
'Subscription',
'Latency',
'Speed',
'Customize JSON Configuration...',
'Move Up',
'Move Down',
'Duplicate',
'Delete',
'Select All',
'Scroll To Activated Server',
'Test Ping Latency',
'Test Tcping Latency',
'Test Download Speed',
'Clear Test Results',
'New Empty Configuration',
'Export Share Link To Clipboard',
'Export As QR Code',
'Export JSON Configuration To Clipboard',
'Connecting',
'Connecting. Please wait',
'Untitled',
)
# ALL Headers VALUE
TRANSLATABLE_HEADERS = [
_('Remark'),
_('Protocol'),
_('Address'),
_('Port'),
_('Transport'),
_('TLS'),
_('Subscription'),
_('Latency'),
_('Speed'),
]
class UserServersQTableWidget(QTranslatable, AppQTableWidget):
@@ -857,7 +838,7 @@ class UserServersQTableWidget(QTranslatable, AppQTableWidget):
if APP().systemTray.ConnectAction.isConnecting():
mbox = AppQMessageBox(icon=AppQMessageBox.Icon.Information)
mbox.setWindowTitle(_('Connecting'))
mbox.setText(_('Connecting. Please wait'))
mbox.setText(_('Connecting. Please wait...'))
if PLATFORM != 'Darwin':
# Show the MessageBox asynchronously
-8
View File
@@ -36,8 +36,6 @@ __all__ = ['UserSubsQTableWidget']
registerAppSettings('SubscriptionWidgetSectionSizeTable')
needTrans = functools.partial(needTransFn, source=__name__)
class UserSubsQTableWidgetHorizontalHeader(AppQHeaderView):
def __init__(self, *args, **kwargs):
@@ -67,12 +65,6 @@ class UserSubsQTableWidgetHeaders:
return self.name
needTrans(
'Remark',
'Delete',
)
class UserSubsQTableWidget(QTranslatable, AppQTableWidget):
Headers = [
UserSubsQTableWidgetHeaders('Remark', lambda item: item.get('remark', '')),
@@ -37,8 +37,6 @@ __all__ = ['XrayAssetViewerQListWidget']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
class AssetExistsMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
@@ -57,15 +55,6 @@ class AssetExistsMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Delete',
'Import',
'Asset file already exists. Overwrite?',
'Error import asset file',
'Import asset file success',
)
class XrayAssetViewerQListWidget(SupportThemeChangedCallback, AppQListWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
+9 -28
View File
@@ -44,8 +44,6 @@ logger = logging.getLogger(__name__)
registerAppSettings('ServerWidgetWindowSize')
needTrans = functools.partial(needTransFn, source=__name__)
def connectedHttpProxyEndpoint() -> Union[str, None]:
try:
@@ -129,32 +127,6 @@ class AppNetworkStateManager(NetworkStateManager):
self.stopTest()
needTrans(
'Server',
'Add VMess Server...',
'Add VLESS Server...',
'Add Shadowsocks Server...',
'Add Trojan Server...',
'Add Hysteria1 Server...',
'Add Hysteria2 Server...',
'Subscription',
'Update Subscription (Use Current Proxy)',
'Update Subscription (Force Proxy)',
'Update Subscription (No Proxy)',
'Edit Subscription...',
'Log',
'Show Furious Log',
'Show Core Log',
'Show Tun2socks Log',
'Tools',
'Manage Xray-core Asset File...',
'Open Application Folder',
'Check For Updates',
'About',
'Help',
)
class AppMainWindow(AppQMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -393,6 +365,15 @@ class AppMainWindow(AppQMainWindow):
],
}
# Corresponds to menus defined above
TRANSLATABLE_MENU_NAME = [
_('Log'),
_('Server'),
_('Subscription'),
_('Tools'),
_('Help'),
]
# Menus
for menuDict in (logMenu, serverMenu, subsMenu, toolsMenu, helpMenu):
menuName = menuDict['name']
-25
View File
@@ -27,10 +27,6 @@ import functools
__all__ = ['LogViewerWindow']
needTrans = functools.partial(needTransFn, source=__name__)
needTrans('Unable to save log')
class SaveErrorMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
@@ -53,13 +49,6 @@ class SaveErrorMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Save File',
'Text files (*.txt);;All files (*)',
'Error saving log',
)
def saveAsFile(content: str):
filename, selectedFilter = QFileDialog.getSaveFileName(
None, _('Save File'), filter=_('Text files (*.txt);;All files (*)')
@@ -81,20 +70,6 @@ def saveAsFile(content: str):
mbox.open()
needTrans(
'Log Viewer',
'Save As...',
'Exit',
'File',
'Copy',
'Select All',
'Edit',
'Zoom In',
'Zoom Out',
'View',
)
class LogViewerWindow(AppQMainWindow):
def __init__(self, *args, **kwargs):
tabTitle = kwargs.pop('tabTitle', '')
-38
View File
@@ -34,16 +34,6 @@ __all__ = ['TextEditorWindow']
registerAppSettings('ServerWidgetPointSize')
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Save Changes',
'The content has been modified. Save changes?',
'Save',
'Cancel',
'Discard',
)
class QuestionSaveMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
@@ -61,9 +51,6 @@ class QuestionSaveMBox(AppQMessageBox):
self.setDefaultButton(self.button0)
needTrans('Please check if the configuration is in valid JSON format')
class JSONDecodeErrorMBox(AppQMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -85,31 +72,6 @@ class JSONDecodeErrorMBox(AppQMessageBox):
self.moveToCenter()
needTrans(
'Save',
'Save As...',
'Close Window',
'File',
'Undo',
'Redo',
'Cut',
'Copy',
'Paste',
'Select All',
'Indent...',
'Edit',
'Zoom In',
'Zoom Out',
'View',
'Error saving configuration',
'Save File',
'Text files (*.json);;All files (*)',
'Error Saving File',
'Invalid server configuration',
'Error setting indent',
)
class TextEditorWindow(AppQMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
-17
View File
@@ -33,15 +33,6 @@ __all__ = ['UserSubsWindow']
registerAppSettings('SubscriptionWidgetWindowSize')
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Add Subscription',
'Enter subscription remark:',
'Enter subscription URL:',
'Cancel',
)
class AddSubsDialog(AppQDialog):
def __init__(self, *args, **kwargs):
@@ -83,14 +74,6 @@ class AddSubsDialog(AppQDialog):
return self.webURLEdit.text()
needTrans(
'Edit Subscription',
'Subscription List',
'Add',
'Delete',
)
class UserSubsWindow(AppQMainWindow):
def __init__(self, *args, **kwargs):
callback = kwargs.pop('deleteUniqueCallback', None)
-13
View File
@@ -34,19 +34,6 @@ __all__ = ['XrayAssetViewerWindow']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
'Xray-core Asset File',
'Refresh',
'Open Asset Directory',
'Import From File...',
'Exit',
'File',
'Import File',
'All files (*)',
)
class XrayAssetViewerWindow(AppQMainWindow):
def __init__(self, *args, **kwargs):
-11
View File
@@ -34,17 +34,6 @@ __all__ = ['main']
logger = logging.getLogger(__name__)
needTrans = functools.partial(needTransFn, source=__name__)
needTrans(
f'{APPLICATION_NAME} is not able to run on this operating system',
'Operating system information',
f'{APPLICATION_NAME} encountered an internal error and needs to be stopped',
f'{APPLICATION_NAME} stopped unexpectedly due to an unknown exception',
'Crash log has been saved to',
'Open crash log',
)
def runAppMain():
appMainProcess = AppMainProcess(functools.partial(Application, sys.argv))
+83 -37
View File
@@ -17,23 +17,20 @@
from __future__ import annotations
from Furious.Core import *
from Furious.Interface import *
from Furious.Library import *
from Furious.Utility import *
from Furious.PyFramework import *
from Furious.QtFramework import *
from Furious.Storage import *
from Furious.TrayActions import *
from Furious.Widget import *
from Furious.Window import *
from Furious.__main__ import *
from Furious.Externals import *
import os
import re
import copy
import deepl
# import deepl
import logging
import argparse
import functools
import Furious
logging.basicConfig(
format='[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s',
@@ -44,9 +41,32 @@ logging.raiseExceptions = False
logger = logging.getLogger('Translation')
@functools.lru_cache(None)
def getAppSourceCodePath(path):
# Walk through the directory tree
for dirpath, dirnames, filenames in os.walk(path):
# Check if __init__.py exists in the current directory
if '__init__.py' in filenames:
for filename in filenames:
yield os.path.join(dirpath, filename)
@functools.lru_cache(None)
def getMagicNameFromPath(path):
return os.path.relpath(path, ROOT_DIR).removesuffix('.py').replace(os.sep, '.')
@functools.lru_cache(None)
def getAppConstantsByName(name):
return getattr(Furious.Utility.Constants, name)
APPLICATION_SOURCE_CODE_PATH = getAppSourceCodePath(PACKAGE_DIR)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-k', '--key', help='DeepL auth key', required=True)
# parser.add_argument('-k', '--key', help='DeepL auth key', required=True)
parser.add_argument(
'-t', '--target', help='Target translation language', required=True
)
@@ -68,14 +88,40 @@ def main():
# Reset source
translation[key]['source'] = []
for text, source in TranslationPool:
if text not in translation:
translation[text] = {'source': [source]}
else:
unit = translation[text]
for sourceCodePath in APPLICATION_SOURCE_CODE_PATH:
with open(sourceCodePath, 'r', encoding='utf-8') as file:
content = file.read()
if source not in unit['source']:
unit['source'].append(source)
magicName = getMagicNameFromPath(sourceCodePath)
pattern = r"(?<![a-zA-Z])_\(\s*f?\s*(?:'([^']*)'|\"([^\"]*)\")\s*\)"
matches = re.findall(pattern, content)
if matches:
match = [m[0] or m[1] for m in matches]
for source in match:
foundBraces = True
while foundBraces:
lBraceIndex = source.find('{')
rBraceIndex = source.find('}')
if lBraceIndex >= 0 and rBraceIndex >= 0:
parsed = source[lBraceIndex + 1 : rBraceIndex]
source = source.replace(
source[lBraceIndex : rBraceIndex + 1],
getAppConstantsByName(parsed),
)
else:
foundBraces = False
if source not in translation:
translation[source] = {'source': [magicName]}
else:
if magicName not in translation[source]['source']:
translation[source]['source'].append(magicName)
nonexist = []
@@ -88,7 +134,7 @@ def main():
# Key with no source, remove
translation.pop(key, None)
translator = deepl.Translator(args.key, send_platform_info=False, proxy=proxy)
# translator = deepl.Translator(args.key, send_platform_info=False, proxy=proxy)
for text in translation.keys():
# Remove redundant EN translation
@@ -103,21 +149,21 @@ def main():
f'skip reviewed translation: \'{text}\' --{target}--> \'{targetText}\''
)
else:
result = translator.translate_text(
text,
source_lang='EN',
target_lang=target,
context=(
f'\'{APPLICATION_NAME}\' is application name. '
'Please do not translate this word'
),
)
logger.info(
f'query translation: \'{text}\' --{target}--> \'{result.text}\''
)
translation[text][target] = result.text
# result = translator.translate_text(
# text,
# source_lang='EN',
# target_lang=target,
# context=(
# f'\'{APPLICATION_NAME}\' is application name. '
# 'Please do not translate this word'
# ),
# )
#
# logger.info(
# f'query translation: \'{text}\' --{target}--> \'{result.text}\''
# )
#
# translation[text][target] = result.text
if not targetText or translation[text].get('isReviewed') is None:
# Target translation does not exist, or does not have 'isReviewed' field.
@@ -143,12 +189,12 @@ def main():
if isReviewed == 'False':
unreviewed += 1
logger.warning(f'have unreviewed translations \'{text}\'')
logger.warning(f'have unreviewed translation \'{text}\'')
if unreviewed > 0:
logger.error(f'have {unreviewed} unreviewed translations')
logger.error(f'have {unreviewed} unreviewed translation(s)')
else:
logger.info(f'all translations have been reviewed')
logger.info(f'all {len(translation)} translation(s) have been reviewed')
if __name__ == '__main__':