mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
feat: import custom language implementation from 64Gram
This commit is contained in:
parent
2e9f8bfec4
commit
d24411fde5
13 changed files with 296 additions and 30 deletions
|
@ -100,6 +100,8 @@ PRIVATE
|
|||
ayu/ayu_state.h
|
||||
ayu/ayu_settings.cpp
|
||||
ayu/ayu_settings.h
|
||||
ayu/ayu_lang.cpp
|
||||
ayu/ayu_lang.h
|
||||
ayu/boxes/confirmation_box.cpp
|
||||
ayu/boxes/confirmation_box.h
|
||||
ayu/boxes/edit_deleted_mark.cpp
|
||||
|
|
|
@ -3842,3 +3842,37 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_mac_hold_to_quit" = "Hold {text} to Quit";
|
||||
|
||||
// Keys finished
|
||||
|
||||
|
||||
// AyuGram keys generated
|
||||
|
||||
"ayu_AyuPreferences" = "AyuGram Preferences";
|
||||
"ayu_GhostEssentialsHeader" = "Ghost essentials";
|
||||
"ayu_SendReadPackets" = "Send read status";
|
||||
"ayu_SendOnlinePackets" = "Send online status";
|
||||
"ayu_SendUploadProgress" = "Send typing & upload status";
|
||||
"ayu_SendOfflinePacketAfterOnline" = "Immediate offline after online";
|
||||
"ayu_MarkReadAfterSend" = "Send read status after reply";
|
||||
"ayu_UseScheduledMessages" = "Schedule messages";
|
||||
"ayu_SpyEssentialsHeader" = "Spy essentials";
|
||||
"ayu_KeepDeletedMessages" = "Keep deleted messages";
|
||||
"ayu_KeepMessagesHistory" = "Keep edits history";
|
||||
"ayu_QoLTogglesHeader" = "QoL toggles";
|
||||
"ayu_RealForwardTime" = "Show real forward time";
|
||||
"ayu_ShowFromChannel" = "Show «channel» label";
|
||||
"ayu_KeepAliveService" = "Keep Alive Service";
|
||||
"ayu_EnableAds" = "Enable ads";
|
||||
"ayu_CustomizationHeader" = "Customization";
|
||||
"ayu_DeletedMarkText" = "Deleted mark";
|
||||
"ayu_ShowGhostToggleInDrawer" = "Show ghost mode toggle";
|
||||
"ayu_CleanDatabase" = "Clean database";
|
||||
"ayu_CleanDatabaseNotification" = "AyuGram database cleaned";
|
||||
"ayu_EnableGhostMode" = "Enable Ghost";
|
||||
"ayu_DisableGhostMode" = "Disable Ghost";
|
||||
"ayu_GhostModeEnabled" = "Ghost mode turned on";
|
||||
"ayu_GhostModeDisabled" = "Ghost mode turned off";
|
||||
"ayu_EditsHistoryTitle" = "Edits history";
|
||||
"ayu_EditsHistoryMenuText" = "History";
|
||||
"ayu_ReadUntilMenuText" = "Read until";
|
||||
"ayu_LikelyOfflineStatus" = "offline ?";
|
||||
"ayu_SettingsWatermark" = "AyuGram developed and maintained by Radolyn Labs";
|
||||
|
|
119
Telegram/SourceFiles/ayu/ayu_lang.cpp
Normal file
119
Telegram/SourceFiles/ayu/ayu_lang.cpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include "ayu_lang.h"
|
||||
|
||||
#include "qjsondocument.h"
|
||||
#include "lang/lang_instance.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
|
||||
CustomLangPack *CustomLangPack::instance = nullptr;
|
||||
|
||||
CustomLangPack::CustomLangPack() = default;
|
||||
|
||||
void CustomLangPack::initInstance() {
|
||||
if (!instance)
|
||||
instance = new CustomLangPack;
|
||||
}
|
||||
|
||||
CustomLangPack *CustomLangPack::currentInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
void CustomLangPack::fetchCustomLangPack(const QString& langPackId, const QString& langPackBaseId) {
|
||||
LOG(("Current Language pack ID: %1, Base ID: %2").arg(langPackId, langPackBaseId));
|
||||
|
||||
const auto proxy = Core::App().settings().proxy().isEnabled() ? Core::App().settings().proxy().selected() : MTP::ProxyData();
|
||||
if (proxy.type == MTP::ProxyData::Type::Socks5 || proxy.type == MTP::ProxyData::Type::Http) {
|
||||
QNetworkProxy LocaleProxy = MTP::ToNetworkProxy(MTP::ToDirectIpProxy(proxy));
|
||||
networkManager.setProxy(LocaleProxy);
|
||||
}
|
||||
|
||||
QUrl url;
|
||||
if (!langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
|
||||
url.setUrl(qsl("https://raw.githubusercontent.com/AyuGram/localization/translations/desktop/%1.json").arg(langPackId));
|
||||
} else {
|
||||
url.setUrl(qsl("https://raw.githubusercontent.com/AyuGram/localization/translations/desktop/%1.json").arg(needFallback ? langPackBaseId : langPackId));
|
||||
}
|
||||
_chkReply = networkManager.get(QNetworkRequest(url));
|
||||
connect(_chkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(fetchError(QNetworkReply::NetworkError)));
|
||||
connect(_chkReply, SIGNAL(finished()), this, SLOT(fetchFinished()));
|
||||
LOG(("Fetching %1 lang pack...").arg(needFallback ? (langPackBaseId.isEmpty() ? langPackId : langPackBaseId) : langPackId));
|
||||
}
|
||||
|
||||
void CustomLangPack::fetchFinished() {
|
||||
if (!_chkReply) return;
|
||||
|
||||
QString langPackBaseId = Lang::GetInstance().baseId();
|
||||
QString langPackId = Lang::GetInstance().id();
|
||||
auto statusCode = _chkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (statusCode == 404 && !langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
|
||||
LOG(("AyuGram Language pack not found! Fallback to main language: %1...").arg(langPackBaseId));
|
||||
needFallback = true;
|
||||
_chkReply->disconnect();
|
||||
fetchCustomLangPack("", langPackBaseId);
|
||||
}
|
||||
else {
|
||||
QByteArray result = _chkReply->readAll().trimmed();
|
||||
QJsonParseError error{};
|
||||
QJsonDocument str = QJsonDocument::fromJson(result, &error);
|
||||
if (error.error == QJsonParseError::NoError) {
|
||||
parseLangFile(str);
|
||||
} else {
|
||||
LOG(("Incorrect JSON File. Fallback to default language: English..."));
|
||||
loadDefaultLangFile();
|
||||
}
|
||||
|
||||
_chkReply = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CustomLangPack::fetchError(QNetworkReply::NetworkError e) {
|
||||
LOG(("Network error: %1").arg(e));
|
||||
|
||||
if (e == QNetworkReply::NetworkError::ContentNotFoundError) {
|
||||
QString langPackBaseId = Lang::GetInstance().baseId();
|
||||
QString langPackId = Lang::GetInstance().id();
|
||||
|
||||
if (!langPackId.isEmpty() && !langPackBaseId.isEmpty() && !needFallback) {
|
||||
LOG(("AyuGram Language pack not found! Fallback to main language: %1...").arg(langPackBaseId));
|
||||
needFallback = true;
|
||||
_chkReply->disconnect();
|
||||
fetchCustomLangPack("", langPackBaseId);
|
||||
} else {
|
||||
LOG(("AyuGram Language pack not found! Fallback to default language: English..."));
|
||||
loadDefaultLangFile();
|
||||
_chkReply = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomLangPack::loadDefaultLangFile() {
|
||||
QFile file(":/localization/en.json");
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QJsonDocument str = QJsonDocument::fromJson(file.readAll());
|
||||
QJsonObject json = str.object();
|
||||
for (const QString& key : json.keys()) {
|
||||
Lang::GetInstance().applyValue(key.toUtf8(), json.value(key).toString().toUtf8());
|
||||
}
|
||||
Lang::GetInstance().updatePluralRules();
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void CustomLangPack::parseLangFile(QJsonDocument str) {
|
||||
QJsonObject json = str.object();
|
||||
for (const QString& brokenKey : json.keys()) {
|
||||
auto key = qsl("ayu_") + brokenKey;
|
||||
auto val = json.value(brokenKey).toString().toUtf8();
|
||||
|
||||
Lang::GetInstance().resetValue(key.toUtf8());
|
||||
Lang::GetInstance().applyValue(key.toUtf8(), val);
|
||||
if (key.contains("#other")) {
|
||||
Lang::GetInstance().resetValue(key.toUtf8().replace("#other", "#few"));
|
||||
Lang::GetInstance().resetValue(key.toUtf8().replace("#other", "#few"));
|
||||
Lang::GetInstance().applyValue(key.toUtf8().replace("#other", "#few"), val);
|
||||
Lang::GetInstance().applyValue(key.toUtf8().replace("#other", "#many"), val);
|
||||
}
|
||||
}
|
||||
Lang::GetInstance().updatePluralRules();
|
||||
}
|
30
Telegram/SourceFiles/ayu/ayu_lang.h
Normal file
30
Telegram/SourceFiles/ayu/ayu_lang.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtXml/QDomDocument>
|
||||
|
||||
class CustomLangPack : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(CustomLangPack)
|
||||
|
||||
public:
|
||||
static CustomLangPack *currentInstance();
|
||||
static void initInstance();
|
||||
static CustomLangPack *instance;
|
||||
|
||||
void fetchCustomLangPack(const QString& langPackId, const QString& langPackBaseId);
|
||||
void loadDefaultLangFile();
|
||||
void parseLangFile(QJsonDocument str);
|
||||
|
||||
public Q_SLOTS:
|
||||
void fetchFinished();
|
||||
void fetchError(QNetworkReply::NetworkError e);
|
||||
|
||||
private:
|
||||
CustomLangPack();
|
||||
~CustomLangPack() = default;
|
||||
|
||||
QNetworkAccessManager networkManager;
|
||||
QNetworkReply *_chkReply = nullptr;
|
||||
bool needFallback = false;
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#include "context_menu.h"
|
||||
#include "history/history_inner_widget.h"
|
||||
#include "lang_auto.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
@ -36,7 +37,7 @@ namespace AyuUi {
|
|||
|
||||
void AyuPopupMenu::addReadUntilAction(HistoryItem *item) const {
|
||||
const auto history = item->history();
|
||||
_ayuSubMenu->addAction(QString("Read until"), [=]() {
|
||||
_ayuSubMenu->addAction(tr::ayu_ReadUntilMenuText(tr::now), [=]() {
|
||||
AyuState::setAllowSendReadPacket(true);
|
||||
history->session().data().histories().readInboxOnNewMessage(item);
|
||||
}, &st::menuIconShowInChat);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/settings/settings_ayu.h"
|
||||
|
||||
#include "lang_auto.h"
|
||||
#include "mainwindow.h"
|
||||
#include "settings/settings_common.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
|
@ -24,7 +25,7 @@
|
|||
namespace Settings {
|
||||
|
||||
rpl::producer<QString> Ayu::title() {
|
||||
return rpl::single(QString("AyuGram Settings"));
|
||||
return tr::ayu_AyuPreferences();
|
||||
}
|
||||
|
||||
Ayu::Ayu(
|
||||
|
@ -38,11 +39,12 @@ namespace Settings {
|
|||
not_null<Window::SessionController *> controller) {
|
||||
auto settings = &AyuSettings::getInstance();
|
||||
|
||||
AddSubsectionTitle(container, rpl::single(QString("General")));
|
||||
AddSkip(container);
|
||||
AddSubsectionTitle(container, tr::ayu_GhostEssentialsHeader());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send read packets")),
|
||||
tr::ayu_SendReadPackets(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendReadPackets)
|
||||
|
@ -56,7 +58,7 @@ namespace Settings {
|
|||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send online packets")),
|
||||
tr::ayu_SendOnlinePackets(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendOnlinePackets)
|
||||
|
@ -70,21 +72,7 @@ namespace Settings {
|
|||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send offline packet after online")),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendOfflinePacketAfterOnline)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->sendOfflinePacketAfterOnline);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_sendOfflinePacketAfterOnline(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Send typing & upload progress")),
|
||||
tr::ayu_SendUploadProgress(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendUploadProgress)
|
||||
|
@ -98,7 +86,21 @@ namespace Settings {
|
|||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Use scheduled messages to keep offline")),
|
||||
tr::ayu_SendOfflinePacketAfterOnline(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->sendOfflinePacketAfterOnline)
|
||||
)->toggledValue(
|
||||
) | rpl::filter([=](bool enabled) {
|
||||
return (enabled != settings->sendOfflinePacketAfterOnline);
|
||||
}) | rpl::start_with_next([=](bool enabled) {
|
||||
settings->set_sendOfflinePacketAfterOnline(enabled);
|
||||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
tr::ayu_UseScheduledMessages(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->useScheduledMessages)
|
||||
|
@ -110,9 +112,14 @@ namespace Settings {
|
|||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
|
||||
AddSubsectionTitle(container, tr::ayu_SpyEssentialsHeader());
|
||||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Keep deleted messages")),
|
||||
tr::ayu_KeepDeletedMessages(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->keepDeletedMessages)
|
||||
|
@ -126,7 +133,7 @@ namespace Settings {
|
|||
|
||||
AddButton(
|
||||
container,
|
||||
rpl::single(QString("Keep messages' history")),
|
||||
tr::ayu_KeepMessagesHistory(),
|
||||
st::settingsButtonNoIcon
|
||||
)->toggleOn(
|
||||
rpl::single(settings->keepMessagesHistory)
|
||||
|
@ -138,11 +145,16 @@ namespace Settings {
|
|||
Local::writeSettings();
|
||||
}, container->lifetime());
|
||||
|
||||
AddDivider(container);
|
||||
AddSkip(container);
|
||||
|
||||
AddSubsectionTitle(container, tr::ayu_CustomizationHeader());
|
||||
|
||||
auto currentDeletedMark = lifetime().make_state<rpl::variable<QString>>();
|
||||
|
||||
auto btn = AddButtonWithLabel(
|
||||
container,
|
||||
rpl::single(QString("Deleted Mark")),
|
||||
tr::ayu_DeletedMarkText(),
|
||||
currentDeletedMark->changes(),
|
||||
st::settingsButtonNoIcon
|
||||
);
|
||||
|
@ -160,7 +172,7 @@ namespace Settings {
|
|||
|
||||
auto btn2 = AddButtonWithLabel(
|
||||
container,
|
||||
rpl::single(QString("Edited Mark")),
|
||||
rpl::single(QString("Edited mark")),
|
||||
currentEditedMark->changes(),
|
||||
st::settingsButtonNoIcon
|
||||
);
|
||||
|
@ -174,7 +186,7 @@ namespace Settings {
|
|||
});
|
||||
*currentEditedMark = settings->editedMark;
|
||||
|
||||
AddDividerText(container, rpl::single(QString("AyuGram developed and maintained by Radolyn Labs")));
|
||||
AddDividerText(container, tr::ayu_SettingsWatermark());
|
||||
}
|
||||
|
||||
void Ayu::setupContent(not_null<Window::SessionController *> controller) {
|
||||
|
|
|
@ -105,12 +105,14 @@ public:
|
|||
|| (_base && _base->isNonDefaultPlural(key));
|
||||
}
|
||||
|
||||
void resetValue(const QByteArray &key);
|
||||
void applyValue(const QByteArray &key, const QByteArray &value);
|
||||
void updatePluralRules();
|
||||
|
||||
private:
|
||||
void setBaseId(const QString &baseId, const QString &pluralId);
|
||||
|
||||
void applyDifferenceToMe(const MTPDlangPackDifference &difference);
|
||||
void applyValue(const QByteArray &key, const QByteArray &value);
|
||||
void resetValue(const QByteArray &key);
|
||||
void reset(const Language &language);
|
||||
void fillFromCustomContent(
|
||||
const QString &absolutePath,
|
||||
|
@ -122,7 +124,6 @@ private:
|
|||
const QString &absolutePath,
|
||||
const QString &relativePath,
|
||||
const QByteArray &content);
|
||||
void updatePluralRules();
|
||||
void updateChoosingStickerReplacement();
|
||||
|
||||
Instance *_derived = nullptr;
|
||||
|
|
|
@ -395,7 +395,7 @@ void SetupSections(
|
|||
Calls::Id(),
|
||||
{ &st::settingsIconCalls, kIconGreen });
|
||||
addSection(
|
||||
rpl::single(QString("AyuGram Settings")),
|
||||
tr::ayu_AyuPreferences(),
|
||||
Ayu::Id(),
|
||||
{ &st::settingsPremiumIconStar, kIconPurple });
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtCore/QDirIterator>
|
||||
|
||||
#include "ayu/ayu_settings.h"
|
||||
#include "ayu/ayu_lang.h"
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
#include <unistd.h>
|
||||
|
@ -1131,6 +1132,14 @@ void readLangPack() {
|
|||
if (langpack.stream.status() == QDataStream::Ok) {
|
||||
Lang::GetInstance().fillFromSerialized(data, langpack.version);
|
||||
}
|
||||
QString langPackBaseId = Lang::GetInstance().baseId();
|
||||
QString langPackId = Lang::GetInstance().id();
|
||||
if (langPackId.isEmpty()) {
|
||||
LOG(("Lang ID not found! Re-use old language pack..."));
|
||||
return;
|
||||
}
|
||||
CustomLangPack::initInstance();
|
||||
CustomLangPack::currentInstance()->fetchCustomLangPack(langPackId, langPackBaseId);
|
||||
}
|
||||
|
||||
void writeLangPack() {
|
||||
|
|
1
ayu-scripts/.gitignore
vendored
Normal file
1
ayu-scripts/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
venv
|
3
ayu-scripts/desktop-specific.json
Normal file
3
ayu-scripts/desktop-specific.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"ayu_SettingsWatermark": "AyuGram developed and maintained by Radolyn Labs"
|
||||
}
|
9
ayu-scripts/requirements.txt
Normal file
9
ayu-scripts/requirements.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
beautifulsoup4==4.12.2
|
||||
bs4==0.0.1
|
||||
certifi==2023.5.7
|
||||
charset-normalizer==3.1.0
|
||||
idna==3.4
|
||||
lxml==4.9.2
|
||||
requests==2.31.0
|
||||
soupsieve==2.4.1
|
||||
urllib3==2.0.2
|
45
ayu-scripts/sync-translations.py
Normal file
45
ayu-scripts/sync-translations.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
import json
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
import bs4
|
||||
import requests
|
||||
|
||||
if os.path.exists('desktop-specific.json'):
|
||||
os.chdir('../')
|
||||
|
||||
req = requests.get(
|
||||
'https://raw.githubusercontent.com/AyuGram/AyuGram4A/rewrite/TMessagesProj/src/main/res/values/ayu.xml'
|
||||
)
|
||||
|
||||
tree = bs4.BeautifulSoup(req.text, 'xml')
|
||||
|
||||
strings = {}
|
||||
for string in tree.find_all('string'):
|
||||
t = string.attrs['name']
|
||||
strings[f'ayu_{t}'] = string.text
|
||||
|
||||
with open('./ayu-scripts/desktop-specific.json') as f:
|
||||
data = json.load(f)
|
||||
|
||||
strings.update(data)
|
||||
|
||||
req = requests.get(
|
||||
'https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/langs/lang.strings'
|
||||
)
|
||||
|
||||
data = req.text
|
||||
|
||||
data += '''
|
||||
|
||||
// AyuGram keys generated
|
||||
|
||||
'''
|
||||
|
||||
for k, v in strings.items():
|
||||
data += f'"{k}" = "{v}";\n'
|
||||
|
||||
with open(os.path.realpath('./Telegram/Resources/langs/lang.strings'), 'w', encoding='utf-8') as f:
|
||||
f.write(data)
|
||||
|
||||
print('Done.')
|
Loading…
Add table
Reference in a new issue