chore: minor fixes (#2459)

* fix: fixed links on page with service description

* fix: fixed subscription text color

* chore: update ru translations

* chore: add save button

* fix: ru translation fixes
This commit is contained in:
vkamn
2026-04-10 21:24:00 +07:00
committed by GitHub
parent 493ee22883
commit 46f5b3894b
17 changed files with 389 additions and 203 deletions

View File

@@ -192,7 +192,7 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
} }
qDebug() << "something went wrong"; qDebug() << "something went wrong";
return amnezia::ErrorCode::InternalError; return amnezia::ErrorCode::ApiConfigDownloadError;
} }
bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject) bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)

View File

@@ -82,7 +82,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiPurchaseError): errorMessage = QObject::tr("Unable to process purchase"); break; case (ErrorCode::ApiPurchaseError): errorMessage = QObject::tr("Unable to process purchase"); break;
case (ErrorCode::ApiSubscriptionNotActiveError): errorMessage = QObject::tr("No active subscription found"); break; case (ErrorCode::ApiSubscriptionNotActiveError): errorMessage = QObject::tr("No active subscription found"); break;
case (ErrorCode::ApiNoPurchasedSubscriptionsError): errorMessage = QObject::tr("No purchased subscriptions found. Please purchase a subscription first"); break; case (ErrorCode::ApiNoPurchasedSubscriptionsError): errorMessage = QObject::tr("No purchased subscriptions found. Please purchase a subscription first"); break;
case (ErrorCode::ApiTrialAlreadyUsedError): errorMessage = QObject::tr("This email has already been used for trial activation"); break; case (ErrorCode::ApiTrialAlreadyUsedError): errorMessage = QObject::tr("This email address has already been used to activate a trial"); break;
// QFile errors // QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break; case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;

View File

@@ -52,18 +52,18 @@
<context> <context>
<name>ApiAccountInfoModel</name> <name>ApiAccountInfoModel</name>
<message> <message>
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="31"/> <location filename="../ui/models/api/apiAccountInfoModel.cpp" line="32"/>
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="35"/> <location filename="../ui/models/api/apiAccountInfoModel.cpp" line="37"/>
<source>Active</source> <source>Active</source>
<translation>Активна</translation> <translation>Активна</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="34"/> <location filename="../ui/models/api/apiAccountInfoModel.cpp" line="36"/>
<source>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Inactive&lt;/a&gt;</source> <source>Inactive</source>
<translation>Не активна</translation> <translation>Не активна</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="48"/> <location filename="../ui/models/api/apiAccountInfoModel.cpp" line="50"/>
<source>%1 out of %2</source> <source>%1 out of %2</source>
<translation>%1 из %2</translation> <translation>%1 из %2</translation>
</message> </message>
@@ -71,23 +71,51 @@
<context> <context>
<name>ApiConfigsController</name> <name>ApiConfigsController</name>
<message> <message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="514"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="859"/>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="690"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="929"/>
<source>%1 installed successfully.</source> <source>%1 installed successfully.</source>
<translation>%1 успешно установлен.</translation> <translation>%1 успешно установлен.</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="637"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="810"/>
<source>Subscription restored successfully.</source> <source>Subscription restored successfully.</source>
<translation>Подписка успешно восстановлена.</translation> <translation>Подписка успешно восстановлена.</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="751"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="391"/>
<source>%1/mo</source>
<comment>IAP: price per month in plan subtitle</comment>
<translation>%1/мес</translation>
</message>
<message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="410"/>
<source>from %1 per month</source>
<comment>IAP: card footer minimum monthly price from StoreKit</comment>
<translation>от %1 в месяц</translation>
</message>
<message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="664"/>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="802"/>
<source>This subscription has already been added</source>
<translation>Эта подписка уже добавлена</translation>
</message>
<message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="672"/>
<source>%1 has been added to the app</source>
<translation>%1 добавлено в приложение</translation>
</message>
<message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="897"/>
<source>This email address has already been used to activate a trial. If you like the service, you can upgrade to Premium</source>
<translation>Этот адрес электронной почты уже использовался для активации пробного периода. Если вам понравился сервис, вы можете оформить подписку Premium</translation>
</message>
<message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="998"/>
<source>API config reloaded</source> <source>API config reloaded</source>
<translation>Конфигурация API перезагружена</translation> <translation>Конфигурация API перезагружена</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="755"/> <location filename="../ui/controllers/api/apiConfigsController.cpp" line="1002"/>
<source>Successfully changed the country of connection to %1</source> <source>Successfully changed the country of connection to %1</source>
<translation>Страна подключения изменена на %1</translation> <translation>Страна подключения изменена на %1</translation>
</message> </message>
@@ -182,29 +210,24 @@
<translation>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Недоступно в вашем регионе. Если у вас включен VPN, отключите его, вернитесь на предыдущий экран и попробуйте снова.&lt;/a&gt;</translation> <translation>&lt;p&gt;&lt;a style=&quot;color: #EB5757;&quot;&gt;Недоступно в вашем регионе. Если у вас включен VPN, отключите его, вернитесь на предыдущий экран и попробуйте снова.&lt;/a&gt;</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiServicesModel.cpp" line="95"/>
<source>%1 MBit/s</source> <source>%1 MBit/s</source>
<translation>%1 Мбит/с</translation> <translation type="vanished">%1 Мбит/с</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiServicesModel.cpp" line="102"/>
<source>%1 days</source> <source>%1 days</source>
<translation>%1 дней</translation> <translation type="vanished">%1 дней</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiServicesModel.cpp" line="113"/>
<source>Free</source> <source>Free</source>
<translation>Бесплатно</translation> <translation type="vanished">Бесплатно</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiServicesModel.cpp" line="116"/>
<source>%1 $</source> <source>%1 $</source>
<translation>%1 $</translation> <translation type="vanished">%1 $</translation>
</message> </message>
<message> <message>
<location filename="../ui/models/api/apiServicesModel.cpp" line="118"/>
<source>%1 $/month</source> <source>%1 $/month</source>
<translation>%1 $/месяц</translation> <translation type="vanished">%1 $/месяц</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -241,45 +264,45 @@
<context> <context>
<name>ConnectionController</name> <name>ConnectionController</name>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="81"/> <location filename="../ui/controllers/connectionController.cpp" line="82"/>
<source>Connecting...</source> <source>Connecting...</source>
<translation>Подключение...</translation> <translation>Подключение...</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="86"/> <location filename="../ui/controllers/connectionController.cpp" line="89"/>
<source>Connected</source> <source>Connected</source>
<translation>Подключено</translation> <translation>Подключено</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="110"/> <location filename="../ui/controllers/connectionController.cpp" line="113"/>
<source>Preparing...</source> <source>Preparing...</source>
<translation>Подготовка...</translation> <translation>Подготовка...</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="132"/> <location filename="../ui/controllers/connectionController.cpp" line="135"/>
<source>Settings updated successfully, reconnnection...</source> <source>Settings updated successfully, reconnnection...</source>
<translation>Настройки успешно обновлены, переподключение...</translation> <translation>Настройки успешно обновлены, переподключение...</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="135"/> <location filename="../ui/controllers/connectionController.cpp" line="138"/>
<source>Settings updated successfully</source> <source>Settings updated successfully</source>
<translation>Настройки успешно обновлены</translation> <translation>Настройки успешно обновлены</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="95"/> <location filename="../ui/controllers/connectionController.cpp" line="98"/>
<source>Reconnecting...</source> <source>Reconnecting...</source>
<translation>Переподключение...</translation> <translation>Переподключение...</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.h" line="70"/> <location filename="../ui/controllers/connectionController.h" line="70"/>
<location filename="../ui/controllers/connectionController.cpp" line="100"/> <location filename="../ui/controllers/connectionController.cpp" line="103"/>
<location filename="../ui/controllers/connectionController.cpp" line="115"/> <location filename="../ui/controllers/connectionController.cpp" line="118"/>
<location filename="../ui/controllers/connectionController.cpp" line="121"/> <location filename="../ui/controllers/connectionController.cpp" line="124"/>
<source>Connect</source> <source>Connect</source>
<translation>Подключиться</translation> <translation>Подключиться</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/connectionController.cpp" line="105"/> <location filename="../ui/controllers/connectionController.cpp" line="108"/>
<source>Disconnecting...</source> <source>Disconnecting...</source>
<translation>Отключение...</translation> <translation>Отключение...</translation>
</message> </message>
@@ -1697,17 +1720,32 @@ Thank you for staying with us!</source>
<context> <context>
<name>PageSettingsApiAvailableCountries</name> <name>PageSettingsApiAvailableCountries</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="84"/> <location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="129"/>
<source>Subscription expired</source>
<translation>Подписка закончилась</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="129"/>
<source>Subscription expiring soon</source>
<translation>Подписка скоро закончится</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="148"/>
<source>Renew subscription</source>
<translation>Продлить подписку</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="162"/>
<source>Location for connection</source> <source>Location for connection</source>
<translation>Страны для подключения</translation> <translation>Страны для подключения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="123"/> <location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="191"/>
<source>Unable change server location while trying to make an active connection</source> <source>Unable change server location while trying to make an active connection</source>
<translation>Невозможно изменить локацию во время попытки соединения</translation> <translation>Невозможно изменить локацию во время попытки соединения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="127"/> <location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="195"/>
<source>Unable change server location while there is an active connection</source> <source>Unable change server location while there is an active connection</source>
<translation>Невозможно изменить локацию во время активного соединения</translation> <translation>Невозможно изменить локацию во время активного соединения</translation>
</message> </message>
@@ -1939,12 +1977,12 @@ Thank you for staying with us!</source>
<context> <context>
<name>PageSettingsApiServerInfo</name> <name>PageSettingsApiServerInfo</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="190"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="298"/>
<source>Configurations have been updated for some countries. Download and install the updated configuration files</source> <source>Configurations have been updated for some countries. Download and install the updated configuration files</source>
<translation>Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы</translation> <translation>Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="235"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="343"/>
<source>Manage configuration files</source> <source>Manage configuration files</source>
<translation>Управление файлами конфигурации</translation> <translation>Управление файлами конфигурации</translation>
</message> </message>
@@ -1964,106 +2002,122 @@ Thank you for staying with us!</source>
<translation>Активные соединения</translation> <translation>Активные соединения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="166"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="150"/>
<source>Subscription expired</source>
<translation>Подписка закончилась</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="151"/>
<source>Subscription expiring soon</source>
<translation>Подписка скоро закончится</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="181"/>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="246"/>
<source>Renew subscription</source>
<translation>Продлить подписку</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="270"/>
<source>Use VLESS protocol</source> <source>Use VLESS protocol</source>
<translation>Использовать протокол VLESS</translation> <translation>Использовать протокол VLESS</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="170"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="274"/>
<source>Cannot change protocol during active connection</source> <source>Cannot change protocol during active connection</source>
<translation>Невозможно изменить протокол во время активного соединения</translation> <translation>Невозможно изменить протокол во время активного соединения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="211"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="319"/>
<source>Subscription Key</source> <source>Subscription Key</source>
<translation>Ключ для подключения</translation> <translation>Ключ для подключения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="233"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="341"/>
<source>Configuration Files</source> <source>Configuration Files</source>
<translation>Файлы конфигурации</translation> <translation>Файлы конфигурации</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="253"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="361"/>
<source>Active Devices</source> <source>Active Devices</source>
<translation>Активные устройства</translation> <translation>Активные устройства</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="255"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="363"/>
<source>Manage currently connected devices</source> <source>Manage currently connected devices</source>
<translation>Управление подключенными устройствами</translation> <translation>Управление подключенными устройствами</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="272"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="380"/>
<source>Support</source> <source>Support</source>
<translation>Поддержка</translation> <translation>Поддержка</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="287"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="395"/>
<source>How to connect on another device</source> <source>How to connect on another device</source>
<translation>Как подключить другие устройства</translation> <translation>Как подключить другие устройства</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="312"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="420"/>
<source>Reload API config</source> <source>Reload API config</source>
<translation>Перезагрузить конфигурацию API</translation> <translation>Перезагрузить конфигурацию API</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="315"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="423"/>
<source>Reload API config?</source> <source>Reload API config?</source>
<translation>Перезагрузить конфигурацию API?</translation> <translation>Перезагрузить конфигурацию API?</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="316"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="424"/>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="354"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="462"/>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="391"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="499"/>
<source>Continue</source> <source>Continue</source>
<translation>Продолжить</translation> <translation>Продолжить</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="317"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="425"/>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="355"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="463"/>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="392"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="500"/>
<source>Cancel</source> <source>Cancel</source>
<translation>Отменить</translation> <translation>Отменить</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="321"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="429"/>
<source>Cannot reload API config during active connection</source> <source>Cannot reload API config during active connection</source>
<translation>Невозможно перзагрузить API конфигурацию при активном соединении</translation> <translation>Невозможно перзагрузить API конфигурацию при активном соединении</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="349"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="457"/>
<source>Unlink this device</source> <source>Unlink this device</source>
<translation>Отвязать это устройство</translation> <translation>Отвязать это устройство</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="352"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="460"/>
<source>Are you sure you want to unlink this device?</source> <source>Are you sure you want to unlink this device?</source>
<translation>Вы уверены, что хотите отвязать это устройство?</translation> <translation>Вы уверены, что хотите отвязать это устройство?</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="353"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="461"/>
<source>This will unlink the device from your subscription. You can reconnect it anytime by pressing&#xa0;&quot;Reload API config&quot; in subscription settings on device.</source> <source>This will unlink the device from your subscription. You can reconnect it anytime by pressing&#xa0;&quot;Reload API config&quot; in subscription settings on device.</source>
<translation>Это отключит устройство от вашей подписки. Вы можете повторно подключить его в любое время, нажав &quot;Перезагрузить конфигурацию API&quot; в настройках подписки на устройстве.</translation> <translation>Это отключит устройство от вашей подписки. Вы можете повторно подключить его в любое время, нажав &quot;Перезагрузить конфигурацию API&quot; в настройках подписки на устройстве.</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="359"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="467"/>
<source>Cannot unlink device during active connection</source> <source>Cannot unlink device during active connection</source>
<translation>Невозможно отвязать устройство во время активного соединения</translation> <translation>Невозможно отвязать устройство во время активного соединения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="387"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="495"/>
<source>Remove from application</source> <source>Remove from application</source>
<translation>Удалить из приложения</translation> <translation>Удалить из приложения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="390"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="498"/>
<source>Remove from application?</source> <source>Remove from application?</source>
<translation>Удалить из приложения?</translation> <translation>Удалить из приложения?</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="396"/> <location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="504"/>
<source>Cannot remove server during active connection</source> <source>Cannot remove server during active connection</source>
<translation>Невозможно удалить сервер во время активного соединения</translation> <translation>Невозможно удалить сервер во время активного соединения</translation>
</message> </message>
@@ -3111,51 +3165,83 @@ Thank you for staying with us!</source>
</message> </message>
</context> </context>
<context> <context>
<name>PageSetupWizardApiServiceInfo</name> <name>PageSetupWizardApiFreeInfo</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="113"/> <location filename="../ui/qml/Pages2/PageSetupWizardApiFreeInfo.qml" line="74"/>
<source>Free features</source>
<translation>Возможности Free</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiFreeInfo.qml" line="125"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
</context>
<context>
<name>PageSetupWizardApiPremiumInfo</name>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml" line="91"/>
<source>Recommended</source>
<translation>Рекомендуется</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml" line="103"/>
<source>Premium features</source>
<translation>Возможности Premium</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml" line="132"/>
<source>Charged to your Apple ID at confirmation. Renews automatically unless auto-renew is turned off at least 24 hours before period end. Manage in Apple ID settings.</source> <source>Charged to your Apple ID at confirmation. Renews automatically unless auto-renew is turned off at least 24 hours before period end. Manage in Apple ID settings.</source>
<translation>Списание с Apple ID при подтверждении. Продление автоматическое, если автопродление не отключено минимум за 24 часа до окончания периода. Управление в настройках Apple ID.</translation> <translation>Списание с Apple ID при подтверждении. Продление автоматическое, если автопродление не отключено минимум за 24 часа до окончания периода. Управление в настройках Apple ID.</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="125"/> <location filename="../ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml" line="169"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiPremiumInfo.qml" line="171"/>
<source>Subscribe %1 for %2</source>
<translation>Подписаться %1 за %2</translation>
</message>
</context>
<context>
<name>PageSetupWizardApiServiceInfo</name>
<message>
<source>Charged to your Apple ID at confirmation. Renews automatically unless auto-renew is turned off at least 24 hours before period end. Manage in Apple ID settings.</source>
<translation type="vanished">Списание с Apple ID при подтверждении. Продление автоматическое, если автопродление не отключено минимум за 24 часа до окончания периода. Управление в настройках Apple ID.</translation>
</message>
<message>
<source>Subscribe Now</source> <source>Subscribe Now</source>
<translation>Подписаться сейчас</translation> <translation type="vanished">Подписаться сейчас</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="158"/>
<source>By continuing, you agree to the &lt;a href=&quot;%1&quot; style=&quot;color: #FBB26A;&quot;&gt;Terms of Use&lt;/a&gt; and &lt;a href=&quot;%2&quot; style=&quot;color: #FBB26A;&quot;&gt;Privacy Policy&lt;/a&gt;</source> <source>By continuing, you agree to the &lt;a href=&quot;%1&quot; style=&quot;color: #FBB26A;&quot;&gt;Terms of Use&lt;/a&gt; and &lt;a href=&quot;%2&quot; style=&quot;color: #FBB26A;&quot;&gt;Privacy Policy&lt;/a&gt;</source>
<translation>Продолжая, вы соглашаетесь с &lt;a href=&quot;%1&quot; style=&quot;color: #FBB26A;&quot;&gt;Условиями использования&lt;/a&gt; и &lt;a href=&quot;%2&quot; style=&quot;color: #FBB26A;&quot;&gt;Политикой конфиденциальности&lt;/a&gt;</translation> <translation type="vanished">Продолжая, вы соглашаетесь с &lt;a href=&quot;%1&quot; style=&quot;color: #FBB26A;&quot;&gt;Условиями использования&lt;/a&gt; и &lt;a href=&quot;%2&quot; style=&quot;color: #FBB26A;&quot;&gt;Политикой конфиденциальности&lt;/a&gt;</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="186"/>
<source>For the region</source> <source>For the region</source>
<translation>Для региона</translation> <translation type="vanished">Для региона</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="195"/>
<source>Price</source> <source>Price</source>
<translation>Цена</translation> <translation type="vanished">Цена</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="204"/>
<source>Work period</source> <source>Work period</source>
<translation>Период работы</translation> <translation type="vanished">Период работы</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="213"/>
<source>Speed</source> <source>Speed</source>
<translation>Скорость</translation> <translation type="vanished">Скорость</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="222"/>
<source>Features</source> <source>Features</source>
<translation>Особенности</translation> <translation type="vanished">Особенности</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServiceInfo.qml" line="125"/>
<source>Connect</source> <source>Connect</source>
<translation>Подключиться</translation> <translation type="vanished">Подключиться</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -3170,11 +3256,50 @@ Thank you for staying with us!</source>
<source>Choose a VPN service that suits your needs.</source> <source>Choose a VPN service that suits your needs.</source>
<translation>Выберите VPN-сервис, который подходит именно вам.</translation> <translation>Выберите VPN-сервис, который подходит именно вам.</translation>
</message> </message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiServicesList.qml" line="88"/>
<source>Recommended</source>
<translation>Рекомендуется</translation>
</message>
</context>
<context>
<name>PageSetupWizardApiTrialEmail</name>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="65"/>
<source>Create an account</source>
<translation>Создайте учётную запись</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="66"/>
<source>To manage your subscription</source>
<translation>Для управления подпиской</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="77"/>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="78"/>
<source>Email</source>
<translation>Электронная почта</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="102"/>
<source>We will create an account for your trial subscription and send important subscription updates to this email address</source>
<translation>Мы создадим учётную запись для вашей пробной подписки и будем отправлять на этот адрес электронной почты важные уведомления о подписке</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="118"/>
<source>Continue</source>
<translation>Продолжить</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardApiTrialEmail.qml" line="126"/>
<source>Enter a valid email address</source>
<translation>Введите корректный адрес электронной почты</translation>
</message>
</context> </context>
<context> <context>
<name>PageSetupWizardConfigSource</name> <name>PageSetupWizardConfigSource</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="324"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="331"/>
<source>File with connection settings</source> <source>File with connection settings</source>
<translation>Файл с настройками подключения</translation> <translation>Файл с настройками подключения</translation>
</message> </message>
@@ -3249,71 +3374,80 @@ Thank you for staying with us!</source>
<translation>Другие варианты подключения</translation> <translation>Другие варианты подключения</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="253"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="226"/>
<source>Recommended</source>
<translation>Рекомендуется</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="256"/>
<source>Site Amnezia</source> <source>Site Amnezia</source>
<translation>Сайт Amnezia</translation> <translation>Сайт Amnezia</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="358"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="281"/>
<source>The easiest way to connect to the VPN</source>
<translation>Самый простой способ подключиться к VPN</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="367"/>
<source>Restore purchases</source> <source>Restore purchases</source>
<translation>Восстановить покупки</translation> <translation>Восстановить покупки</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="277"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="280"/>
<source>VPN by Amnezia</source> <source>VPN by Amnezia</source>
<translation>VPN от Amnezia</translation> <translation>VPN от Amnezia</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="278"/>
<source>Connect to classic paid and free VPN services from Amnezia</source> <source>Connect to classic paid and free VPN services from Amnezia</source>
<translation>Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia</translation> <translation type="vanished">Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="294"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="299"/>
<source>Self-hosted VPN</source> <source>Self-hosted VPN</source>
<translation>Self-hosted VPN</translation> <translation>Self-hosted VPN</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="295"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="300"/>
<source>Configure Amnezia VPN on your own server</source> <source>Configure Amnezia VPN on your own server</source>
<translation>Настроить VPN на собственном сервере</translation> <translation>Настроить VPN на собственном сервере</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="306"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="312"/>
<source>Restore from backup</source> <source>Restore from backup</source>
<translation>Восстановить из резервной копии</translation> <translation>Восстановить из резервной копии</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="307"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="313"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="325"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="332"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="344"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="352"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="359"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="368"/>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="373"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="383"/>
<source></source> <source></source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="311"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="317"/>
<source>Open backup file</source> <source>Open backup file</source>
<translation>Открыть резервную копию</translation> <translation>Открыть резервную копию</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="312"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="318"/>
<source>Backup files (*.backup)</source> <source>Backup files (*.backup)</source>
<translation>Файлы резервных копий (*.backup)</translation> <translation>Файлы резервных копий (*.backup)</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="331"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="338"/>
<source>Open config file</source> <source>Open config file</source>
<translation>Открыть файл с конфигурацией</translation> <translation>Открыть файл с конфигурацией</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="343"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="351"/>
<source>QR code</source> <source>QR code</source>
<translation>QR-код</translation> <translation>QR-код</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="372"/> <location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="382"/>
<source>I have nothing</source> <source>I have nothing</source>
<translation>У меня ничего нет</translation> <translation>У меня ничего нет</translation>
</message> </message>
@@ -3321,17 +3455,17 @@ Thank you for staying with us!</source>
<context> <context>
<name>PageSetupWizardCredentials</name> <name>PageSetupWizardCredentials</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="194"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="206"/>
<source>Server IP address [:port]</source> <source>Server IP address [:port]</source>
<translation>IP-адрес[:порт] сервера</translation> <translation>IP-адрес[:порт] сервера</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="100"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="112"/>
<source>Continue</source> <source>Continue</source>
<translation>Продолжить</translation> <translation>Продолжить</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="167"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="179"/>
<source>Enter the address in the format 255.255.255.255:88</source> <source>Enter the address in the format 255.255.255.255:88</source>
<translation>Введите адрес в формате 255.255.255.255:88</translation> <translation>Введите адрес в формате 255.255.255.255:88</translation>
</message> </message>
@@ -3341,48 +3475,54 @@ Thank you for staying with us!</source>
<translation>Настроить ваш сервер</translation> <translation>Настроить ваш сервер</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="195"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="207"/>
<source>255.255.255.255:22</source> <source>255.255.255.255:22</source>
<translation>255.255.255.255:22</translation> <translation>255.255.255.255:22</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="203"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="215"/>
<source>SSH Username</source> <source>SSH Username</source>
<translation>Имя пользователя SSH</translation> <translation>Имя пользователя SSH</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="82"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="82"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="212"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="94"/>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="224"/>
<source>Password or SSH private key</source> <source>Password or SSH private key</source>
<translation>Пароль или закрытый ключ SSH</translation> <translation>Пароль или закрытый ключ SSH</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="132"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="97"/>
<source>SSH key requirements: supported key types are ED25519 and RSA in PEM format. Paste the private key, including the BEGIN/END lines. If your key doesnt work, generate a compatible one</source>
<translation>Требования к SSH-ключу: поддерживаются ключи ED25519 и RSA в формате PEM. Вставьте закрытый ключ целиком, включая строки BEGIN/END. Если ваш ключ не подходит, создайте совместимый ключ</translation>
</message>
<message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/>
<source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source> <source>All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties</source>
<translation>Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам</translation> <translation>Все данные, которые вы вводите, останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или каким-либо третьим лицам</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="143"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="155"/>
<source>How to run your VPN server</source> <source>How to run your VPN server</source>
<translation>Как создать VPN на собственном сервере</translation> <translation>Как создать VPN на собственном сервере</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="144"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="156"/>
<source>Where to get connection data, step-by-step instructions for buying a VPS</source> <source>Where to get connection data, step-by-step instructions for buying a VPS</source>
<translation>Где взять данные для подключения, пошаговые инструкции по покупке VPS</translation> <translation>Где взять данные для подключения, пошаговые инструкции по покупке VPS</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="164"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="176"/>
<source>Ip address cannot be empty</source> <source>Ip address cannot be empty</source>
<translation>Поле с IP-адресом не может быть пустым</translation> <translation>Поле с IP-адресом не может быть пустым</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="172"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="184"/>
<source>Login cannot be empty</source> <source>Login cannot be empty</source>
<translation>Поле с логином не может быть пустым</translation> <translation>Поле с логином не может быть пустым</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="178"/> <location filename="../ui/qml/Pages2/PageSetupWizardCredentials.qml" line="190"/>
<source>Password/private key cannot be empty</source> <source>Password/private key cannot be empty</source>
<translation>Поле с паролем/закрытым ключом не может быть пустым</translation> <translation>Поле с паролем/закрытым ключом не может быть пустым</translation>
</message> </message>
@@ -3516,7 +3656,7 @@ Thank you for staying with us!</source>
<context> <context>
<name>PageSetupWizardStart</name> <name>PageSetupWizardStart</name>
<message> <message>
<location filename="../ui/qml/Pages2/PageSetupWizardStart.qml" line="41"/> <location filename="../ui/qml/Pages2/PageSetupWizardStart.qml" line="42"/>
<source>Let&apos;s get started</source> <source>Let&apos;s get started</source>
<translation>Приступим</translation> <translation>Приступим</translation>
</message> </message>
@@ -4326,7 +4466,22 @@ Thank you for staying with us!</source>
<translation>Не удалось обработать покупку</translation> <translation>Не удалось обработать покупку</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="97"/> <location filename="../core/errorstrings.cpp" line="83"/>
<source>No active subscription found</source>
<translation>Активная подписка не найдена</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="84"/>
<source>No purchased subscriptions found. Please purchase a subscription first</source>
<translation>Платные подписки не найдены. Сначала оформите подписку</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="85"/>
<source>This email address has already been used to activate a trial</source>
<translation>Этот адрес электронной почты уже использовался для активации пробного периода</translation>
</message>
<message>
<location filename="../core/errorstrings.cpp" line="100"/>
<source>ErrorCode: %1. </source> <source>ErrorCode: %1. </source>
<translation>Код ошибки: %1. </translation> <translation>Код ошибки: %1. </translation>
</message> </message>
@@ -4426,37 +4581,37 @@ Thank you for staying with us!</source>
<translation>Превышен лимит разрешенных конфигураций для одной подписки</translation> <translation>Превышен лимит разрешенных конфигураций для одной подписки</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="85"/> <location filename="../core/errorstrings.cpp" line="88"/>
<source>QFile error: The file could not be opened</source> <source>QFile error: The file could not be opened</source>
<translation>Ошибка QFile: не удалось открыть файл</translation> <translation>Ошибка QFile: не удалось открыть файл</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="86"/> <location filename="../core/errorstrings.cpp" line="89"/>
<source>QFile error: An error occurred when reading from the file</source> <source>QFile error: An error occurred when reading from the file</source>
<translation>Ошибка QFile: произошла ошибка при чтении из файла</translation> <translation>Ошибка QFile: произошла ошибка при чтении из файла</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="87"/> <location filename="../core/errorstrings.cpp" line="90"/>
<source>QFile error: The file could not be accessed</source> <source>QFile error: The file could not be accessed</source>
<translation>Ошибка QFile: не удалось получить доступ к файлу</translation> <translation>Ошибка QFile: не удалось получить доступ к файлу</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="88"/> <location filename="../core/errorstrings.cpp" line="91"/>
<source>QFile error: An unspecified error occurred</source> <source>QFile error: An unspecified error occurred</source>
<translation>Ошибка QFile: произошла неизвестная ошибка</translation> <translation>Ошибка QFile: произошла неизвестная ошибка</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="89"/> <location filename="../core/errorstrings.cpp" line="92"/>
<source>QFile error: A fatal error occurred</source> <source>QFile error: A fatal error occurred</source>
<translation>Ошибка QFile: произошла фатальная ошибка</translation> <translation>Ошибка QFile: произошла фатальная ошибка</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="90"/> <location filename="../core/errorstrings.cpp" line="93"/>
<source>QFile error: The operation was aborted</source> <source>QFile error: The operation was aborted</source>
<translation>Ошибка QFile: операция была прервана</translation> <translation>Ошибка QFile: операция была прервана</translation>
</message> </message>
<message> <message>
<location filename="../core/errorstrings.cpp" line="94"/> <location filename="../core/errorstrings.cpp" line="97"/>
<source>Internal error</source> <source>Internal error</source>
<translation>Внутренняя ошибка</translation> <translation>Внутренняя ошибка</translation>
</message> </message>
@@ -4985,7 +5140,17 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<context> <context>
<name>ServersListView</name> <name>ServersListView</name>
<message> <message>
<location filename="../ui/qml/Components/ServersListView.qml" line="79"/> <location filename="../ui/qml/Components/ServersListView.qml" line="71"/>
<source>Subscription expired. Please renew</source>
<translation>Подписка закончилась. Пожалуйста, продлите её</translation>
</message>
<message>
<location filename="../ui/qml/Components/ServersListView.qml" line="71"/>
<source>Subscription expiring soon</source>
<translation>Подписка скоро закончится</translation>
</message>
<message>
<location filename="../ui/qml/Components/ServersListView.qml" line="84"/>
<source>Unable change server while there is an active connection</source> <source>Unable change server while there is an active connection</source>
<translation>Невозможно изменить сервер во время активного соединения</translation> <translation>Невозможно изменить сервер во время активного соединения</translation>
</message> </message>
@@ -5007,12 +5172,17 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<context> <context>
<name>SettingsController</name> <name>SettingsController</name>
<message> <message>
<location filename="../ui/controllers/settingsController.cpp" line="270"/> <location filename="../ui/controllers/settingsController.cpp" line="185"/>
<source>Can&apos;t open file: %1</source>
<translation>Невозможно открыть файл: %1</translation>
</message>
<message>
<location filename="../ui/controllers/settingsController.cpp" line="271"/>
<source>All settings have been reset to default values</source> <source>All settings have been reset to default values</source>
<translation>Все настройки сброшены до значений по умолчанию</translation> <translation>Все настройки сброшены до значений по умолчанию</translation>
</message> </message>
<message> <message>
<location filename="../ui/controllers/settingsController.cpp" line="247"/> <location filename="../ui/controllers/settingsController.cpp" line="248"/>
<source>Backup file is corrupted</source> <source>Backup file is corrupted</source>
<translation>Файл резервной копии поврежден</translation> <translation>Файл резервной копии поврежден</translation>
</message> </message>
@@ -5065,6 +5235,29 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<translation>Экспорт завершен</translation> <translation>Экспорт завершен</translation>
</message> </message>
</context> </context>
<context>
<name>SubscriptionExpiredDrawer</name>
<message>
<location filename="../ui/qml/Components/SubscriptionExpiredDrawer.qml" line="47"/>
<source>Amnezia Premium subscription has expired</source>
<translation>Подписка Amnezia Premium закончилась</translation>
</message>
<message>
<location filename="../ui/qml/Components/SubscriptionExpiredDrawer.qml" line="60"/>
<source>Renew to continue using VPN</source>
<translation>Продлите подписку, чтобы продолжить использовать VPN</translation>
</message>
<message>
<location filename="../ui/qml/Components/SubscriptionExpiredDrawer.qml" line="72"/>
<source>Renew</source>
<translation>Продлить</translation>
</message>
<message>
<location filename="../ui/qml/Components/SubscriptionExpiredDrawer.qml" line="96"/>
<source>Support</source>
<translation>Поддержка</translation>
</message>
</context>
<context> <context>
<name>SystemTrayNotificationHandler</name> <name>SystemTrayNotificationHandler</name>
<message> <message>
@@ -5098,6 +5291,14 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<translation>Закрыть</translation> <translation>Закрыть</translation>
</message> </message>
</context> </context>
<context>
<name>TermsAndPrivacyText</name>
<message>
<location filename="../ui/qml/Components/TermsAndPrivacyText.qml" line="23"/>
<source>By continuing, you agree to the &lt;a href=&quot;%1&quot; style=&quot;color: %3;&quot;&gt;Terms of Use&lt;/a&gt; and &lt;a href=&quot;%2&quot; style=&quot;color: %3;&quot;&gt;Privacy Policy&lt;/a&gt;</source>
<translation>Продолжая, вы соглашаетесь с &lt;a href=&quot;%1&quot; style=&quot;color: %3;&quot;&gt;Условиями использования&lt;/a&gt; и &lt;a href=&quot;%2&quot; style=&quot;color: %3;&quot;&gt;Политикой конфиденциальности&lt;/a&gt;</translation>
</message>
</context>
<context> <context>
<name>TextFieldWithHeaderType</name> <name>TextFieldWithHeaderType</name>
<message> <message>
@@ -5173,12 +5374,12 @@ FileZilla или другие SFTP-клиенты, а также смонтир
<context> <context>
<name>main2</name> <name>main2</name>
<message> <message>
<location filename="../ui/qml/main2.qml" line="230"/> <location filename="../ui/qml/main2.qml" line="247"/>
<source>Private key passphrase</source> <source>Private key passphrase</source>
<translation>Парольная фраза для закрытого ключа</translation> <translation>Парольная фраза для закрытого ключа</translation>
</message> </message>
<message> <message>
<location filename="../ui/qml/main2.qml" line="251"/> <location filename="../ui/qml/main2.qml" line="268"/>
<source>Save</source> <source>Save</source>
<translation>Сохранить</translation> <translation>Сохранить</translation>
</message> </message>

View File

@@ -661,7 +661,7 @@ bool ApiConfigsController::importPremiumFromAppStore(const QString &storeProduct
int duplicateServerIndex = -1; int duplicateServerIndex = -1;
errorCode = importServiceFromBilling(responseBody, isTestPurchase, duplicateServerIndex); errorCode = importServiceFromBilling(responseBody, isTestPurchase, duplicateServerIndex);
if (errorCode == ErrorCode::ApiConfigAlreadyAdded) { if (errorCode == ErrorCode::ApiConfigAlreadyAdded) {
emit installServerFromApiFinished(tr("This subscription is already in the app."), duplicateServerIndex); emit installServerFromApiFinished(tr("This subscription has already been added"), duplicateServerIndex);
return true; return true;
} }
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
@@ -669,7 +669,7 @@ bool ApiConfigsController::importPremiumFromAppStore(const QString &storeProduct
return false; return false;
} }
emit installServerFromApiFinished( emit installServerFromApiFinished(
tr("%1 was added to the app.").arg(m_apiServicesModel->getSelectedServiceName())); tr("%1 has been added to the app").arg(m_apiServicesModel->getSelectedServiceName()));
return true; return true;
#else #else
Q_UNUSED(storeProductId); Q_UNUSED(storeProductId);
@@ -799,7 +799,7 @@ bool ApiConfigsController::restoreServiceFromAppStore()
if (!hasInstalledConfig) { if (!hasInstalledConfig) {
if (duplicateConfigAlreadyPresent) { if (duplicateConfigAlreadyPresent) {
emit installServerFromApiFinished(tr("This subscription is already in the app."), duplicateServerIndex); emit installServerFromApiFinished(tr("This subscription has already been added"), duplicateServerIndex);
return true; return true;
} }
@@ -894,7 +894,7 @@ bool ApiConfigsController::importTrialFromGateway(const QString &email)
ErrorCode errorCode = executeRequest(QString("%1v1/trial"), apiPayload, responseBody); ErrorCode errorCode = executeRequest(QString("%1v1/trial"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
if (errorCode == ErrorCode::ApiTrialAlreadyUsedError) { if (errorCode == ErrorCode::ApiTrialAlreadyUsedError) {
emit trialEmailError(tr("This email has already been used for trial activation. If you like the service, you can buy Premium.")); emit trialEmailError(tr("This email address has already been used to activate a trial. If you like the service, you can upgrade to Premium"));
return false; return false;
} }
emit errorOccurred(errorCode); emit errorOccurred(errorCode);

View File

@@ -32,8 +32,9 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
return tr("Active"); return tr("Active");
} }
return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("<p><a style=\"color: #EB5757;\">Inactive</a>") return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate)
: tr("<p><a style=\"color: #28c840;\">Active</a>"); ? QStringLiteral("<p><a style=\"color: #EB5757;\">%1</a>").arg(tr("Inactive"))
: QStringLiteral("<p><a style=\"color: #28c840;\">%1</a>").arg(tr("Active"));
} }
case EndDateRole: { case EndDateRole: {
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) { if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {

View File

@@ -12,7 +12,7 @@ namespace configKey
constexpr char title[] = "title"; constexpr char title[] = "title";
constexpr char body[] = "body"; constexpr char body[] = "body";
constexpr char icon[] = "icon"; constexpr char icon[] = "icon";
constexpr char accent[] = "accent"; constexpr char link[] = "link";
} }
QString gatewayIconKeyToUrl(const QString &iconKey) QString gatewayIconKeyToUrl(const QString &iconKey)
@@ -62,8 +62,8 @@ QVariant ApiBenefitsModel::data(const QModelIndex &index, int role) const
return item.title; return item.title;
case BodyRole: case BodyRole:
return item.body; return item.body;
case AccentRole: case LinkRole:
return item.accent; return item.link;
default: default:
return {}; return {};
} }
@@ -75,7 +75,7 @@ QHash<int, QByteArray> ApiBenefitsModel::roleNames() const
{ IconRole, "icon" }, { IconRole, "icon" },
{ TitleRole, "title" }, { TitleRole, "title" },
{ BodyRole, "body" }, { BodyRole, "body" },
{ AccentRole, "accent" }, { LinkRole, "link" },
}; };
} }
@@ -90,7 +90,11 @@ void ApiBenefitsModel::updateModel(const QJsonArray &benefits)
const QJsonObject benefitObject = benefitValue.toObject(); const QJsonObject benefitObject = benefitValue.toObject();
QString title = benefitObject.value(configKey::title).toString(); QString title = benefitObject.value(configKey::title).toString();
QString body = benefitObject.value(configKey::body).toString(); QString body = benefitObject.value(configKey::body).toString();
const bool isLink = benefitObject.value(configKey::link).toBool();
const QString iconKey = benefitObject.value(configKey::icon).toString(); const QString iconKey = benefitObject.value(configKey::icon).toString();
if (isLink) {
body = body.trimmed();
}
if (title.isEmpty() && body.isEmpty()) { if (title.isEmpty() && body.isEmpty()) {
continue; continue;
} }
@@ -98,7 +102,7 @@ void ApiBenefitsModel::updateModel(const QJsonArray &benefits)
item.icon = gatewayIconKeyToUrl(iconKey); item.icon = gatewayIconKeyToUrl(iconKey);
item.title = std::move(title); item.title = std::move(title);
item.body = std::move(body); item.body = std::move(body);
item.accent = benefitObject.value(configKey::accent).toBool(); item.link = isLink;
m_serviceBenefits.append(std::move(item)); m_serviceBenefits.append(std::move(item));
} }
endResetModel(); endResetModel();

View File

@@ -15,7 +15,7 @@ public:
IconRole = Qt::UserRole + 1, IconRole = Qt::UserRole + 1,
TitleRole, TitleRole,
BodyRole, BodyRole,
AccentRole LinkRole
}; };
Q_ENUM(Roles) Q_ENUM(Roles)
@@ -34,7 +34,7 @@ private:
QString icon; QString icon;
QString title; QString title;
QString body; QString body;
bool accent = false; bool link = false;
}; };
QVector<ServiceBenefitItem> m_serviceBenefits; QVector<ServiceBenefitItem> m_serviceBenefits;

View File

@@ -11,7 +11,11 @@ RowLayout {
property string iconSource: "" property string iconSource: ""
property string titleText: "" property string titleText: ""
property string bodyText: "" property string bodyText: ""
property bool accent: false property bool link: false
readonly property string bodyLineText: root.link && root.bodyText.length > 0 ? "@" + root.bodyText : root.bodyText
readonly property bool bodyClickable: root.link && root.bodyText.length > 0
spacing: 12 spacing: 12
@@ -43,22 +47,17 @@ RowLayout {
LabelTextType { LabelTextType {
id: bodyLabel id: bodyLabel
width: parent.width width: parent.width
text: root.bodyText text: root.bodyLineText
color: root.accent ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.mutedGray color: root.link ? AmneziaStyle.color.goldenApricot : AmneziaStyle.color.mutedGray
font.pixelSize: 14 font.pixelSize: 14
wrapMode: Text.Wrap wrapMode: Text.Wrap
} }
MouseArea { MouseArea {
anchors.fill: bodyLabel anchors.fill: bodyLabel
visible: root.accent && root.bodyText.length > 0 visible: root.bodyClickable
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: Qt.openUrlExternally("https://t.me/" + root.bodyText)
var t = root.bodyText.trim()
if (t.startsWith("@")) {
Qt.openUrlExternally("https://t.me/" + t.substring(1))
}
}
} }
} }
} }

View File

@@ -33,7 +33,7 @@ Rectangle {
iconSource: model.icon iconSource: model.icon
titleText: model.title titleText: model.title
bodyText: model.body bodyText: model.body
accent: !!model.accent link: !!model.link
} }
} }
} }

View File

@@ -68,7 +68,7 @@ ListViewType {
text: name text: name
descriptionText: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon) descriptionText: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
? (isSubscriptionExpired ? qsTr("Subscription expired. Please renew.") : qsTr("Subscription expiring soon.")) ? (isSubscriptionExpired ? qsTr("Subscription expired. Please renew") : qsTr("Subscription expiring soon"))
: serverDescription : serverDescription
descriptionColor: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon) descriptionColor: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon)
? (isSubscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot) ? (isSubscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot)

View File

@@ -57,7 +57,7 @@ DrawerType2 {
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
text: qsTr("Renew your subscription to continue using VPN") text: qsTr("Renew to continue using VPN")
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
} }

View File

@@ -17,6 +17,8 @@ ParagraphTextType {
textFormat: Text.RichText textFormat: Text.RichText
color: AmneziaStyle.color.mutedGray color: AmneziaStyle.color.mutedGray
font.pixelSize: 12 font.pixelSize: 12
lineHeight: 1.35
lineHeightMode: Text.ProportionalHeight
text: qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: %3;\">Terms of Use</a> and <a href=\"%2\" style=\"color: %3;\">Privacy Policy</a>") text: qsTr("By continuing, you agree to the <a href=\"%1\" style=\"color: %3;\">Terms of Use</a> and <a href=\"%2\" style=\"color: %3;\">Privacy Policy</a>")
.arg(root.termsUrl) .arg(root.termsUrl)

View File

@@ -28,20 +28,20 @@ Button {
property string leftImageSource property string leftImageSource
property real textOpacity: 1.0
property alias focusItem: rightImage property alias focusItem: rightImage
hoverEnabled: true hoverEnabled: true
clip: false clip: false
readonly property real cardTextOpacity: !enabled ? 1.0 : pressed ? 0.7 : hovered ? 0.8 : 1.0
background: Rectangle { background: Rectangle {
id: backgroundRect id: backgroundRect
anchors.fill: parent anchors.fill: parent
radius: 16 radius: 16
color: defaultColor color: root.hovered && root.enabled ? root.hoveredColor : root.defaultColor
Behavior on color { Behavior on color {
PropertyAnimation { duration: 200 } PropertyAnimation { duration: 200 }
@@ -51,6 +51,7 @@ Button {
contentItem: Item { contentItem: Item {
id: contentRoot id: contentRoot
z: 1
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -129,7 +130,7 @@ Button {
Layout.topMargin: contentRoot.badgeVisible ? 0 : 16 Layout.topMargin: contentRoot.badgeVisible ? 0 : 16
Layout.bottomMargin: root.bodyText !== "" ? 0 : 16 Layout.bottomMargin: root.bodyText !== "" ? 0 : 16
opacity: root.textOpacity opacity: root.cardTextOpacity
} }
CaptionTextType { CaptionTextType {
@@ -138,13 +139,16 @@ Button {
color: root.bodyTextColor color: root.bodyTextColor
textFormat: Text.RichText textFormat: Text.RichText
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.bottomMargin: root.footerText !== "" ? 0 : 8 Layout.bottomMargin: root.footerText !== "" ? 0 : 8
opacity: root.textOpacity opacity: root.cardTextOpacity
} }
ButtonTextType { ButtonTextType {
@@ -159,7 +163,7 @@ Button {
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
opacity: root.textOpacity opacity: root.cardTextOpacity
} }
} }
@@ -184,7 +188,7 @@ Button {
anchors.fill: parent anchors.fill: parent
radius: 12 radius: 12
color: "transparent" color: root.pressed ? rightImage.pressedColor : root.hovered ? rightImage.hoveredColor : rightImage.defaultColor
Behavior on color { Behavior on color {
PropertyAnimation { duration: 200 } PropertyAnimation { duration: 200 }
@@ -198,41 +202,4 @@ Button {
} }
} }
} }
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
enabled: root.enabled
onEntered: {
backgroundRect.color = root.hoveredColor
if (rightImageSource) {
rightImageBackground.color = rightImage.hoveredColor
}
root.textOpacity = 0.8
}
onExited: {
backgroundRect.color = root.defaultColor
if (rightImageSource) {
rightImageBackground.color = rightImage.defaultColor
}
root.textOpacity = 1
}
onPressedChanged: {
if (rightImageSource) {
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
}
root.textOpacity = 0.7
}
onClicked: {
root.clicked()
}
}
} }

View File

@@ -2,8 +2,6 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0 import PageEnum 1.0
import Style 1.0 import Style 1.0
@@ -52,6 +50,8 @@ PageType {
width: listView.width width: listView.width
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: gatewayEndpointField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
@@ -64,13 +64,25 @@ PageType {
clickedFunc: function() { clickedFunc: function() {
SettingsController.resetGatewayEndpoint() SettingsController.resetGatewayEndpoint()
gatewayEndpointField.textField.text = SettingsController.gatewayEndpoint
} }
}
textField.onEditingFinished: { BasicButtonType {
textField.text = textField.text.replace(/^\s+|\s+$/g, '') id: saveButton
if (textField.text !== SettingsController.gatewayEndpoint) {
SettingsController.gatewayEndpoint = textField.text Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Save")
clickedFunc: function() {
var trimmed = gatewayEndpointField.textField.text.replace(/^\s+|\s+$/g, '')
gatewayEndpointField.textField.text = trimmed
if (trimmed !== SettingsController.gatewayEndpoint) {
SettingsController.gatewayEndpoint = trimmed
} }
PageController.showNotificationMessage(qsTr("Settings saved"))
} }
} }
} }

View File

@@ -99,7 +99,7 @@ PageType {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: AmneziaStyle.color.mutedGray color: AmneziaStyle.color.mutedGray
font.pixelSize: 12 font.pixelSize: 12
text: qsTr("We will create an account for your trial subscription and send important subscription updates to this email.") text: qsTr("We will create an account for your trial subscription and send important subscription updates to this email address")
} }
} }
} }

View File

@@ -278,7 +278,7 @@ PageType {
id: amneziaVpn id: amneziaVpn
property string title: qsTr("VPN by Amnezia") property string title: qsTr("VPN by Amnezia")
property string description: qsTr("The easiest way to connect to VPN") property string description: qsTr("The easiest way to connect to the VPN")
property string imageSource: "qrc:/images/controls/amnezia.svg" property string imageSource: "qrc:/images/controls/amnezia.svg"
property bool featuredAmneziaConnection: true property bool featuredAmneziaConnection: true
property bool isVisible: true property bool isVisible: true

View File

@@ -94,7 +94,7 @@ PageType {
visible: title === qsTr("Password or SSH private key") visible: title === qsTr("Password or SSH private key")
backGroundColor: AmneziaStyle.color.translucentWhite backGroundColor: AmneziaStyle.color.translucentWhite
iconPath: "qrc:/images/controls/alert-circle.svg" iconPath: "qrc:/images/controls/alert-circle.svg"
textString: qsTr("SSH key requirements: supported ED25519 or RSA in PEM. Paste the private key including BEGIN/END lines. If your key doesnt work, generate a compatible one.") textString: qsTr("SSH key requirements: supported key types are ED25519 and RSA in PEM format. Paste the private key, including the BEGIN/END lines. If your key doesnt work, generate a compatible one")
} }
} }