فصل هفتم: بازآفرینی کلاینت دسکتاپ Nextcloud: پارسی، جلالی، و امن¶
هدف فصل: کلاینتی که قلب پارسی دارد¶
تصور کنید کلاینت دسکتاپ Nextcloud شما به زبان پارسی سخن میگوید، تاریخها را با تقویم جلالی نمایش میدهد، و با احراز هویت محلی، امنیت را به سطح بالاتری میبرد! در این فصل، کلاینت دسکتاپ Nextcloud (v3.17.3) را با فارسیسازی رابط کاربری، ادغام تقویم جلالی، و افزودن احراز هویت محلی مبتنی بر سیستمعامل ارتقا میدهیم. هدف؟ خلق یک تجربه بومی و امن برای کاربران ایرانی که همگامسازی فایلها را به یک لذت پارسی تبدیل میکند. آمادهید تا کلاینت را به یک شاهکار تبدیل کنید؟
۷.۱ فارسیسازی: رابط کاربری به زبان پارسی¶
۷.۱.۱ ایجاد فایل ترجمه¶
فایل: desktop/translations/fa.ts
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="fa_IR">
<context>
<name>MainWindow</name>
<message>
<source>Sync</source>
<translation>همگامسازی</translation>
</message>
<message>
<source>Settings</source>
<translation>تنظیمات</translation>
</message>
<message>
<source>File</source>
<translation>فایل</translation>
</message>
<message>
<source>Quit</source>
<translation>خروج</translation>
</message>
</context>
<context>
<name>TrayIcon</name>
<message>
<source>Open Nextcloud</source>
<translation>باز کردن Nextcloud</translation>
</message>
<message>
<source>Syncing</source>
<translation>در حال همگامسازی</translation>
</message>
</context>
</TS>
۷.۱.۲ کامپایل ترجمهها¶
cd desktop
lrelease translations/fa.ts -o translations/fa.qm
۷.۱.۳ بارگذاری ترجمهها¶
فایل: desktop/src/gui/main.cpp
#include <QApplication>
#include <QTranslator>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QTranslator translator;
if (translator.load("fa", ":/translations")) {
app.installTranslator(&translator);
}
// ادامه کد...
return app.exec();
}
تست سریع:
- زبان سیستم را به
fa_IRتغییر دهید. - کلاینت را اجرا کنید و مطمئن شوید متنها به فارسی هستند.
۷.۲ جلالیسازی: نمایش تاریخهای شمسی¶
۷.۲.۱ تعریف کلاس جلالی¶
فایل: desktop/src/common/jalalidate.h
#ifndef JALALIDATE_H
#define JALALIDATE_H
#include <QDate>
class JalaliDate {
public:
static QDate toJalali(const QDate& gregorian);
static QDate toGregorian(int jy, int jm, int jd);
static QString formatJalali(const QDate& gregorian, const QString& format = "yyyy/MM/dd");
};
#endif
فایل: desktop/src/common/jalalidate.cpp
#include "jalalidate.h"
#include <jdf.h>
QDate JalaliDate::toJalali(const QDate& gregorian) {
int jy, jm, jd;
gregorian_to_jalali(gregorian.year(), gregorian.month(), gregorian.day(), &jy, &jm, &jd);
return QDate(jy, jm, jd);
}
QDate JalaliDate::toGregorian(int jy, int jm, int jd) {
int gy, gm, gd;
jalali_to_gregorian(jy, jm, jd, &gy, &gm, &gd);
return QDate(gy, gm, gd);
}
QString JalaliDate::formatJalali(const QDate& gregorian, const QString& format) {
int jy, jm, jd;
gregorian_to_jalali(gregorian.year(), gregorian.month(), gregorian.day(), &jy, &jm, &jd);
QString result = format;
result.replace("yyyy", QString::number(jy, 10));
result.replace("MM", QString::number(jm, 10).rightJustified(2, '0'));
result.replace("dd", QString::number(jd, 10).rightJustified(2, '0'));
return result;
}
وابستگی:
git clone https://github.com/ashkandi/jdf.git
۷.۲.۲ ادغام در رابط کاربری¶
فایل: desktop/src/gui/syncstatus.cpp
#include "jalalidate.h"
#include <QLabel>
void SyncStatus::updateStatus(const QDateTime& lastSync) {
QString jalaliDate = JalaliDate::formatJalali(lastSync.date(), "yyyy/MM/dd HH:mm");
statusLabel->setText(QString("آخرین همگامسازی: %1").arg(jalaliDate));
}
۷.۳ احراز هویت محلی: امنیت در دستان سیستمعامل¶
۷.۳.۱ تعریف دیالوگ احراز هویت¶
فایل: desktop/src/gui/localauthdialog.h
#ifndef LOCALAUTHDIALOG_H
#define LOCALAUTHDIALOG_H
#include <QDialog>
#include <QLineEdit>
#include <QPushButton>
class LocalAuthDialog : public QDialog {
Q_OBJECT
public:
explicit LocalAuthDialog(QWidget* parent = nullptr);
QString getCredentials() const;
private slots:
void onAuthAttempt();
private:
QLineEdit* usernameEdit;
QLineEdit* passwordEdit;
QPushButton* authButton;
};
#endif
فایل: desktop/src/gui/localauthdialog.cpp
#include "localauthdialog.h"
#include <QKeychain>
#include <QVBoxLayout>
LocalAuthDialog::LocalAuthDialog(QWidget* parent) : QDialog(parent) {
setWindowTitle("احراز هویت محلی");
usernameEdit = new QLineEdit(this);
usernameEdit->setPlaceholderText("نام کاربری");
passwordEdit = new QLineEdit(this);
passwordEdit->setPlaceholderText("رمز عبور");
passwordEdit->setEchoMode(QLineEdit::Password);
authButton = new QPushButton("تأیید", this);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(usernameEdit);
layout->addWidget(passwordEdit);
layout->addWidget(authButton);
connect(authButton, &QPushButton::clicked, this, &LocalAuthDialog::onAuthAttempt);
QKeychain::ReadPasswordJob job("nextcloud");
job.setKey("user_credentials");
connect(&job, &QKeychain::ReadPasswordJob::finished, this, [&](QKeychain::Job* job) {
if (!job->error()) {
passwordEdit->setText(job->textData());
}
});
job.start();
}
void LocalAuthDialog::onAuthAttempt() {
QKeychain::WritePasswordJob job("nextcloud");
job.setKey("user_credentials");
job.setTextData(passwordEdit->text());
job.start();
accept();
}
QString LocalAuthDialog::getCredentials() const {
return QString("%1:%2").arg(usernameEdit->text(), passwordEdit->text());
}
۷.۳.۲ ادغام با کلاینت¶
فایل: desktop/src/gui/main.cpp
#include "localauthdialog.h"
void authenticateUser() {
LocalAuthDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
QString credentials = dialog.getCredentials();
// استفاده از credentials
}
}
وابستگی:
git clone https://github.com/frankosterfeld/qtkeychain.git
۷.۴ بیلد: آمادهسازی کلاینت¶
- نصب وابستگیها:
sudo apt install qt5-default qt5keychain-dev libssl-dev
- بیلد پروژه:
cd desktop
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
- نصب:
sudo make install
۷.۵ تست: لحظه حقیقت¶
- اجرای کلاینت:
./build/nextcloud
- تست فارسیسازی:
- زبان سیستم را به
fa_IRتنظیم کنید. -
بررسی کنید که متنها به فارسی هستند.
-
تست جلالیسازی:
-
تاریخهای همگامسازی را چک کنید (مثل ۱۴۰۴/۰۱/۰۱).
-
تست احراز هویت:
- دیالوگ احراز هویت را باز کنید.
- credentials را در Keychain بررسی کنید.
تستهای لبه:
- سال کبیسه جلالی.
- اجرای کلاینت بدون QtKeychain.
- تغییر زبان به انگلیسی.
نکات حرفهای¶
- دسترسیپذیری: از Qt Accessibility Inspector استفاده کنید.
- کشینگ تاریخها:
static QMap<QString, QString> jalaliCache;
QString JalaliDate::formatJalali(const QDate& gregorian, const QString& format) {
QString key = QString("%1_%2").arg(gregorian.toString(), format);
if (jalaliCache.contains(key)) return jalaliCache[key];
QString result = /* محاسبات */;
jalaliCache[key] = result;
return result;
}
- مستندسازی: در
README.fa.mdتوضیح دهید. - تجربه کاربر:
QSettings settings("nextcloud", "client");
settings.setValue("calendar_type", "jalali");