124 | (&MainWindow::checkCurrentIndex));
125 | connect(ui->connectionView, &QTableView::doubleClicked,
126 | this, &MainWindow::onEdit);
127 |
128 | /* set custom context menu */
129 | ui->connectionView->setContextMenuPolicy(Qt::CustomContextMenu);
130 | connect(ui->connectionView, &QTableView::customContextMenuRequested,
131 | this, &MainWindow::onCustomContextMenuRequested);
132 |
133 | checkCurrentIndex();
134 |
135 | // Restore mainWindow's geometry and state
136 | restoreGeometry(configHelper->getMainWindowGeometry());
137 | restoreState(configHelper->getMainWindowState());
138 | ui->connectionView->horizontalHeader()->restoreGeometry(configHelper->getTableGeometry());
139 | ui->connectionView->horizontalHeader()->restoreState(configHelper->getTableState());
140 | }
141 |
142 | MainWindow::~MainWindow()
143 | {
144 | configHelper->save(*model);
145 | configHelper->setTableGeometry(ui->connectionView->horizontalHeader()->saveGeometry());
146 | configHelper->setTableState(ui->connectionView->horizontalHeader()->saveState());
147 | configHelper->setMainWindowGeometry(saveGeometry());
148 | configHelper->setMainWindowState(saveState());
149 |
150 | // delete ui after everything in case it's deleted while still needed for
151 | // the functions written above
152 | delete ui;
153 | }
154 |
155 | const QUrl MainWindow::issueUrl =
156 | QUrl("https://github.com/shadowsocks/shadowsocks-qt5/issues");
157 |
158 | void MainWindow::startAutoStartConnections()
159 | {
160 | configHelper->startAllAutoStart(*model);
161 | }
162 |
163 | void MainWindow::onImportGuiJson()
164 | {
165 | QString file = QFileDialog::getOpenFileName(
166 | this,
167 | tr("Import Connections from gui-config.json"),
168 | QString(),
169 | "GUI Configuration (gui-config.json)");
170 | if (!file.isNull()) {
171 | configHelper->importGuiConfigJson(model, file);
172 | }
173 | }
174 |
175 | void MainWindow::onExportGuiJson()
176 | {
177 | QString file = QFileDialog::getSaveFileName(
178 | this,
179 | tr("Export Connections as gui-config.json"),
180 | QString("gui-config.json"),
181 | "GUI Configuration (gui-config.json)");
182 | if (!file.isNull()) {
183 | configHelper->exportGuiConfigJson(*model, file);
184 | }
185 | }
186 |
187 | void MainWindow::onSaveManually()
188 | {
189 | configHelper->save(*model);
190 | }
191 |
192 | void MainWindow::onAddManually()
193 | {
194 | Connection *newCon = new Connection;
195 | newProfile(newCon);
196 | }
197 |
198 | void MainWindow::onAddScreenQRCode()
199 | {
200 | QString uri = QRCodeCapturer::scanEntireScreen();
201 | if (uri.isNull()) {
202 | QMessageBox::critical(
203 | this,
204 | tr("QR Code Not Found"),
205 | tr("Can't find any QR code image that contains "
206 | "valid URI on your screen(s)."));
207 | } else {
208 | Connection *newCon = new Connection(uri, this);
209 | newProfile(newCon);
210 | }
211 | }
212 |
213 | void MainWindow::onAddScreenQRCodeCapturer()
214 | {
215 | QRCodeCapturer *capturer = new QRCodeCapturer(this);
216 | connect(capturer, &QRCodeCapturer::closed,
217 | capturer, &QRCodeCapturer::deleteLater);
218 | connect(capturer, &QRCodeCapturer::qrCodeFound,
219 | this, &MainWindow::onQRCodeCapturerResultFound,
220 | Qt::DirectConnection);
221 | capturer->show();
222 | }
223 |
224 | void MainWindow::onAddQRCodeFile()
225 | {
226 | QString qrFile =
227 | QFileDialog::getOpenFileName(this,
228 | tr("Open QR Code Image File"),
229 | QString(),
230 | "Images (*.png *jpg *jpeg *xpm)");
231 | if (!qrFile.isNull()) {
232 | QImage img(qrFile);
233 | QString uri = URIHelper::decodeImage(img);
234 | if (uri.isNull()) {
235 | QMessageBox::critical(this,
236 | tr("QR Code Not Found"),
237 | tr("Can't find any QR code image that "
238 | "contains valid URI on your screen(s)."));
239 | } else {
240 | Connection *newCon = new Connection(uri, this);
241 | newProfile(newCon);
242 | }
243 | }
244 | }
245 |
246 | void MainWindow::onAddFromURI()
247 | {
248 | URIInputDialog *inputDlg = new URIInputDialog(this);
249 | connect(inputDlg, &URIInputDialog::finished,
250 | inputDlg, &URIInputDialog::deleteLater);
251 | connect(inputDlg, &URIInputDialog::acceptedURI, [&](const QString &uri){
252 | Connection *newCon = new Connection(uri, this);
253 | newProfile(newCon);
254 | });
255 | inputDlg->exec();
256 | }
257 |
258 | void MainWindow::onAddFromConfigJSON()
259 | {
260 | QString file = QFileDialog::getOpenFileName(this, tr("Open config.json"),
261 | QString(), "JSON (*.json)");
262 | if (!file.isNull()) {
263 | Connection *con = configHelper->configJsonToConnection(file);
264 | if (con) {
265 | newProfile(con);
266 | }
267 | }
268 | }
269 |
270 | void MainWindow::onDelete()
271 | {
272 | if (model->removeRow(proxyModel->mapToSource(
273 | ui->connectionView->currentIndex()).row())) {
274 | configHelper->save(*model);
275 | }
276 | checkCurrentIndex();
277 | }
278 |
279 | void MainWindow::onEdit()
280 | {
281 | editRow(proxyModel->mapToSource(ui->connectionView->currentIndex()).row());
282 | }
283 |
284 | void MainWindow::onShare()
285 | {
286 | QByteArray uri = model->getItem(
287 | proxyModel->mapToSource(ui->connectionView->currentIndex()).
288 | row())->getConnection()->getURI();
289 | ShareDialog *shareDlg = new ShareDialog(uri, this);
290 | connect(shareDlg, &ShareDialog::finished,
291 | shareDlg, &ShareDialog::deleteLater);
292 | shareDlg->exec();
293 | }
294 |
295 | void MainWindow::onConnect()
296 | {
297 | int row = proxyModel->mapToSource(ui->connectionView->currentIndex()).row();
298 | Connection *con = model->getItem(row)->getConnection();
299 | if (con->isValid()) {
300 | con->start();
301 | } else {
302 | QMessageBox::critical(this, tr("Invalid"),
303 | tr("The connection's profile is invalid!"));
304 | }
305 | }
306 |
307 | void MainWindow::onForceConnect()
308 | {
309 | int row = proxyModel->mapToSource(ui->connectionView->currentIndex()).row();
310 | Connection *con = model->getItem(row)->getConnection();
311 | if (con->isValid()) {
312 | model->disconnectConnectionsAt(con->getProfile().localAddress,
313 | con->getProfile().localPort);
314 | con->start();
315 | } else {
316 | QMessageBox::critical(this, tr("Invalid"),
317 | tr("The connection's profile is invalid!"));
318 | }
319 | }
320 |
321 | void MainWindow::onDisconnect()
322 | {
323 | int row = proxyModel->mapToSource(ui->connectionView->currentIndex()).row();
324 | model->getItem(row)->getConnection()->stop();
325 | }
326 |
327 | void MainWindow::onConnectionStatusChanged(const int row, const bool running)
328 | {
329 | if (proxyModel->mapToSource(
330 | ui->connectionView->currentIndex()).row() == row) {
331 | ui->actionConnect->setEnabled(!running);
332 | ui->actionDisconnect->setEnabled(running);
333 | }
334 | }
335 |
336 | void MainWindow::onLatencyTest()
337 | {
338 | model->getItem(proxyModel->mapToSource(ui->connectionView->currentIndex()).
339 | row())->testLatency();
340 | }
341 |
342 | void MainWindow::onMoveUp()
343 | {
344 | QModelIndex proxyIndex = ui->connectionView->currentIndex();
345 | int currentRow = proxyModel->mapToSource(proxyIndex).row();
346 | int targetRow = proxyModel->mapToSource(
347 | proxyModel->index(proxyIndex.row() - 1,
348 | proxyIndex.column(),
349 | proxyIndex.parent())
350 | ).row();
351 | model->move(currentRow, targetRow);
352 | checkCurrentIndex();
353 | }
354 |
355 | void MainWindow::onMoveDown()
356 | {
357 | QModelIndex proxyIndex = ui->connectionView->currentIndex();
358 | int currentRow = proxyModel->mapToSource(proxyIndex).row();
359 | int targetRow = proxyModel->mapToSource(
360 | proxyModel->index(proxyIndex.row() + 1,
361 | proxyIndex.column(),
362 | proxyIndex.parent())
363 | ).row();
364 | model->move(currentRow, targetRow);
365 | checkCurrentIndex();
366 | }
367 |
368 | void MainWindow::onGeneralSettings()
369 | {
370 | SettingsDialog *sDlg = new SettingsDialog(configHelper, this);
371 | connect(sDlg, &SettingsDialog::finished,
372 | sDlg, &SettingsDialog::deleteLater);
373 | if (sDlg->exec()) {
374 | configHelper->save(*model);
375 | configHelper->setStartAtLogin();
376 | }
377 | }
378 |
379 | void MainWindow::newProfile(Connection *newCon)
380 | {
381 | EditDialog *editDlg = new EditDialog(newCon, this);
382 | connect(editDlg, &EditDialog::finished, editDlg, &EditDialog::deleteLater);
383 | if (editDlg->exec()) {//accepted
384 | model->appendConnection(newCon);
385 | configHelper->save(*model);
386 | } else {
387 | newCon->deleteLater();
388 | }
389 | }
390 |
391 | void MainWindow::editRow(int row)
392 | {
393 | Connection *con = model->getItem(row)->getConnection();
394 | EditDialog *editDlg = new EditDialog(con, this);
395 | connect(editDlg, &EditDialog::finished, editDlg, &EditDialog::deleteLater);
396 | if (editDlg->exec()) {
397 | configHelper->save(*model);
398 | }
399 | }
400 |
401 | void MainWindow::checkCurrentIndex()
402 | {
403 | checkCurrentIndex(ui->connectionView->currentIndex());
404 | }
405 |
406 | void MainWindow::checkCurrentIndex(const QModelIndex &_index)
407 | {
408 | QModelIndex index = proxyModel->mapToSource(_index);
409 | const bool valid = index.isValid();
410 | ui->actionTestLatency->setEnabled(valid);
411 | ui->actionEdit->setEnabled(valid);
412 | ui->actionDelete->setEnabled(valid);
413 | ui->actionShare->setEnabled(valid);
414 | ui->actionMoveUp->setEnabled(valid ? _index.row() > 0 : false);
415 | ui->actionMoveDown->setEnabled(valid ?
416 | _index.row() < model->rowCount() - 1 :
417 | false);
418 |
419 | if (valid) {
420 | const bool &running =
421 | model->getItem(index.row())->getConnection()->isRunning();
422 | ui->actionConnect->setEnabled(!running);
423 | ui->actionForceConnect->setEnabled(!running);
424 | ui->actionDisconnect->setEnabled(running);
425 | } else {
426 | ui->actionConnect->setEnabled(false);
427 | ui->actionForceConnect->setEnabled(false);
428 | ui->actionDisconnect->setEnabled(false);
429 | }
430 | }
431 |
432 | void MainWindow::onAbout()
433 | {
434 | QString text = QString("Shadowsocks-Qt5
Version %1
"
435 | "Using libQtShadowsocks %2
"
436 | "Copyright © 2014-2018 Symeon Huang "
437 | "("
438 | "@librehat)
"
439 | "License: "
440 | "GNU Lesser General Public License Version 3
"
441 | "Project Hosted at "
442 | ""
443 | "GitHub
")
444 | .arg(QStringLiteral(APP_VERSION))
445 | .arg(QSS::Common::version());
446 | QMessageBox::about(this, tr("About"), text);
447 | }
448 |
449 | void MainWindow::onReportBug()
450 | {
451 | QDesktopServices::openUrl(issueUrl);
452 | }
453 |
454 | void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
455 | {
456 | this->checkCurrentIndex(ui->connectionView->indexAt(pos));
457 | ui->menuConnection->popup(ui->connectionView->viewport()->mapToGlobal(pos));
458 | }
459 |
460 | void MainWindow::onFilterToggled(bool show)
461 | {
462 | if (show) {
463 | ui->filterLineEdit->setFocus();
464 | }
465 | }
466 |
467 | void MainWindow::onFilterTextChanged(const QString &text)
468 | {
469 | proxyModel->setFilterWildcard(text);
470 | }
471 |
472 | void MainWindow::onQRCodeCapturerResultFound(const QString &uri)
473 | {
474 | QRCodeCapturer* capturer = qobject_cast(sender());
475 | // Disconnect immediately to avoid duplicate signals
476 | disconnect(capturer, &QRCodeCapturer::qrCodeFound,
477 | this, &MainWindow::onQRCodeCapturerResultFound);
478 | Connection *newCon = new Connection(uri, this);
479 | newProfile(newCon);
480 | }
481 |
482 | void MainWindow::hideEvent(QHideEvent *e)
483 | {
484 | QMainWindow::hideEvent(e);
485 | notifier->onWindowVisibleChanged(false);
486 | }
487 |
488 | void MainWindow::showEvent(QShowEvent *e)
489 | {
490 | QMainWindow::showEvent(e);
491 | notifier->onWindowVisibleChanged(true);
492 | this->setFocus();
493 | }
494 |
495 | void MainWindow::closeEvent(QCloseEvent *e)
496 | {
497 | if (e->spontaneous()) {
498 | e->ignore();
499 | hide();
500 | } else {
501 | QMainWindow::closeEvent(e);
502 | }
503 | }
504 |
505 | void MainWindow::setupActionIcon()
506 | {
507 | ui->actionConnect->setIcon(QIcon::fromTheme("network-connect",
508 | QIcon::fromTheme("network-vpn")));
509 | ui->actionDisconnect->setIcon(QIcon::fromTheme("network-disconnect",
510 | QIcon::fromTheme("network-offline")));
511 | ui->actionEdit->setIcon(QIcon::fromTheme("document-edit",
512 | QIcon::fromTheme("accessories-text-editor")));
513 | ui->actionShare->setIcon(QIcon::fromTheme("document-share",
514 | QIcon::fromTheme("preferences-system-sharing")));
515 | ui->actionTestLatency->setIcon(QIcon::fromTheme("flag",
516 | QIcon::fromTheme("starred")));
517 | ui->actionImportGUIJson->setIcon(QIcon::fromTheme("document-import",
518 | QIcon::fromTheme("insert-text")));
519 | ui->actionExportGUIJson->setIcon(QIcon::fromTheme("document-export",
520 | QIcon::fromTheme("document-save-as")));
521 | ui->actionManually->setIcon(QIcon::fromTheme("edit-guides",
522 | QIcon::fromTheme("accessories-text-editor")));
523 | ui->actionURI->setIcon(QIcon::fromTheme("text-field",
524 | QIcon::fromTheme("insert-link")));
525 | ui->actionQRCode->setIcon(QIcon::fromTheme("edit-image-face-recognize",
526 | QIcon::fromTheme("insert-image")));
527 | ui->actionScanQRCodeCapturer->setIcon(ui->actionQRCode->icon());
528 | ui->actionGeneralSettings->setIcon(QIcon::fromTheme("configure",
529 | QIcon::fromTheme("preferences-desktop")));
530 | ui->actionReportBug->setIcon(QIcon::fromTheme("tools-report-bug",
531 | QIcon::fromTheme("help-faq")));
532 | }
533 |
534 | bool MainWindow::isInstanceRunning() const
535 | {
536 | return instanceRunning;
537 | }
538 |
539 | void MainWindow::initSingleInstance()
540 | {
541 | const QString serverName = QCoreApplication::applicationName();
542 | QLocalSocket socket;
543 | socket.connectToServer(serverName);
544 | if (socket.waitForConnected(500)) {
545 | instanceRunning = true;
546 | if (configHelper->isOnlyOneInstance()) {
547 | qWarning() << "An instance of ss-qt5 is already running";
548 | }
549 | QByteArray username = qgetenv("USER");
550 | if (username.isEmpty()) {
551 | username = qgetenv("USERNAME");
552 | }
553 | socket.write(username);
554 | socket.waitForBytesWritten();
555 | return;
556 | }
557 |
558 | /* Can't connect to server, indicating it's the first instance of the user */
559 | instanceServer = new QLocalServer(this);
560 | instanceServer->setSocketOptions(QLocalServer::WorldAccessOption);
561 | connect(instanceServer, &QLocalServer::newConnection,
562 | this, &MainWindow::onSingleInstanceConnect);
563 | if (instanceServer->listen(serverName)) {
564 | /* Remove server in case of crashes */
565 | if (instanceServer->serverError() == QAbstractSocket::AddressInUseError &&
566 | QFile::exists(instanceServer->serverName())) {
567 | QFile::remove(instanceServer->serverName());
568 | instanceServer->listen(serverName);
569 | }
570 | }
571 | }
572 |
573 | void MainWindow::onSingleInstanceConnect()
574 | {
575 | QLocalSocket *socket = instanceServer->nextPendingConnection();
576 | if (!socket) {
577 | return;
578 | }
579 |
580 | if (socket->waitForReadyRead(1000)) {
581 | QByteArray username = qgetenv("USER");
582 | if (username.isEmpty()) {
583 | username = qgetenv("USERNAME");
584 | }
585 |
586 | QByteArray recvUsername = socket->readAll();
587 | if (recvUsername == username) {
588 | // Only show the window if it's the same user
589 | show();
590 | } else {
591 | qWarning("Another user is trying to run another instance of ss-qt5");
592 | }
593 | }
594 | socket->deleteLater();
595 | }
596 |
--------------------------------------------------------------------------------
/src/i18n/ss-qt5_zh_TW.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ConnectionItem
6 |
7 |
8 | Connected
9 | 已連線
10 |
11 |
12 |
13 | Disconnected
14 | 已斷線
15 |
16 |
17 |
18 | Timeout
19 | 逾時
20 |
21 |
22 |
23 | Error
24 | 錯誤
25 |
26 |
27 |
28 | Unknown
29 | 不明
30 |
31 |
32 |
33 | s
34 | 秒
35 |
36 |
37 |
38 | ms
39 | 毫秒
40 |
41 |
42 |
43 | connected
44 | 已連線
45 |
46 |
47 |
48 | disconnected
49 | 已斷線
50 |
51 |
52 |
53 | timed out
54 | 逾時
55 |
56 |
57 |
58 | latency test failed
59 | 延遲測試失敗
60 |
61 |
62 |
63 | Failed to start
64 | 啟動失敗
65 |
66 |
67 |
68 | ConnectionTableModel
69 |
70 |
71 | Name
72 | 名稱
73 |
74 |
75 |
76 | Server
77 | 伺服器
78 |
79 |
80 |
81 | Status
82 | 狀態
83 |
84 |
85 |
86 | Latency
87 | 延遲
88 |
89 |
90 |
91 | Local Port
92 | 本機埠
93 |
94 |
95 |
96 | Term Usage
97 | 本期使用量
98 |
99 |
100 |
101 | Total Usage
102 | 使用量總計
103 |
104 |
105 |
106 | Reset Date
107 | 重設日期
108 |
109 |
110 |
111 | Last Used
112 | 上次使用
113 |
114 |
115 |
116 | EditDialog
117 |
118 |
119 | Profile Editor
120 | 設定檔編輯器
121 |
122 |
123 |
124 | Local Server Type
125 | 本機伺服器型別
126 |
127 |
128 |
129 | Timeout
130 | 逾時
131 |
132 |
133 |
134 | [Deprecated] Turn on one-time authentication and header verification (need server support)
135 | [棄用]開啟單次驗證與標頭驗證(需要伺服器支援)
136 |
137 |
138 | Turn on one-time authentication and header verification (need server support)
139 | 開啟單次驗證與標頭驗證(需要伺服器支援)
140 |
141 |
142 |
143 | One-time authentication
144 | 單次驗證
145 |
146 |
147 |
148 | Encryption Method
149 | 加密方法
150 |
151 |
152 |
153 | Local Port
154 | 本機埠
155 |
156 |
157 |
158 | Local Address
159 | 本機位址
160 |
161 |
162 |
163 | Password
164 | 密碼
165 |
166 |
167 |
168 | Server Port
169 | 伺服器埠
170 |
171 |
172 |
173 | Server Address
174 | 伺服器位址
175 |
176 |
177 |
178 | Profile Name
179 | 設定檔名稱
180 |
181 |
182 |
183 | Auto connect on application start
184 | 程式啟動時自動連線
185 |
186 |
187 |
188 | Debug
189 | 偵錯
190 |
191 |
192 |
193 | Log Level
194 | 記錄檔等級
195 |
196 |
197 |
198 | Automation
199 | 自動化
200 |
201 |
202 |
203 | Reset Data Usage after
204 | 重設資料使用量之後
205 |
206 |
207 |
208 | LogDialog
209 |
210 |
211 | Log Viewer
212 | 記錄檔檢視器
213 |
214 |
215 |
216 | Save log as a plain text file
217 | 儲存記錄檔為文字檔
218 |
219 |
220 |
221 | Save As...
222 | 另存新檔...
223 |
224 |
225 |
226 | Clear
227 | 清除
228 |
229 |
230 |
231 | Save Log As
232 | 另存記錄檔
233 |
234 |
235 |
236 | MainWindow
237 |
238 |
239 | About
240 | 關於
241 |
242 |
243 |
244 | Import Connections from gui-config.json
245 | 自 gui-config.json 匯入連線
246 |
247 |
248 |
249 | Export Connections as gui-config.json
250 | 匯出連線為 gui-config.json
251 |
252 |
253 |
254 |
255 | QR Code Not Found
256 | 找不到 QR 碼
257 |
258 |
259 |
260 |
261 | Can't find any QR code image that contains valid URI on your screen(s).
262 | 在你的螢幕上無法找到任何包含有效 URI 的 QR 碼圖片。
263 |
264 |
265 |
266 | Open QR Code Image File
267 | 開啟 QR 碼圖檔
268 |
269 |
270 |
271 | Open config.json
272 | 開啟 config.json
273 |
274 |
275 |
276 |
277 | Invalid
278 | 無效
279 |
280 |
281 |
282 |
283 | The connection's profile is invalid!
284 | 此連線的設定檔無效!
285 |
286 |
287 |
288 | Connection Manager
289 | 連線管理員
290 |
291 |
292 |
293 | &Connection
294 | &連線
295 |
296 |
297 |
298 | &Add
299 | &新增
300 |
301 |
302 |
303 | Fi&le
304 | &檔案
305 |
306 |
307 |
308 | Settin&gs
309 | &設定
310 |
311 |
312 | Help
313 | 說明
314 |
315 |
316 |
317 | &Manually
318 | &手動
319 |
320 |
321 |
322 | Add connection manually
323 | 手動新增連線
324 |
325 |
326 |
327 | &From QR Code Image File
328 | &來自 QR 碼圖檔
329 |
330 |
331 |
332 | From QR code image file
333 | 來自 QR 碼圖檔
334 |
335 |
336 |
337 | View &Log
338 | &檢視記錄檔
339 |
340 |
341 |
342 | &Scan QR Code on Screen
343 | &掃描螢幕上的 QR 碼
344 |
345 |
346 |
347 | Input to filter
348 | 輸入以篩選
349 |
350 |
351 |
352 | Show Toolbar
353 | 顯示工具列
354 |
355 |
356 |
357 | &Help
358 | 說明(&H)
359 |
360 |
361 |
362 | &URI
363 | &URI
364 |
365 |
366 |
367 | Add connection from URI
368 | 自 URI 新增連線
369 |
370 |
371 |
372 | &Delete
373 | &刪除
374 |
375 |
376 |
377 | &Edit
378 | &編輯
379 |
380 |
381 |
382 | &Connect
383 | &連線
384 |
385 |
386 |
387 | D&isconnect
388 | &中斷連線
389 |
390 |
391 |
392 | &Quit
393 | &結束
394 |
395 |
396 |
397 | Ctrl+Q
398 |
399 |
400 |
401 |
402 | &About
403 | &關於
404 |
405 |
406 |
407 | About &Qt
408 | 關於 &Qt
409 |
410 |
411 |
412 | &General Settings
413 | &一般設定
414 |
415 |
416 |
417 | &Share
418 | &分享
419 |
420 |
421 |
422 | &Report Bug
423 | &回報 Bug
424 |
425 |
426 |
427 | Test the latency of selected connection
428 | 測試已選連線的延遲
429 |
430 |
431 |
432 | Test All C&onnections Latency
433 | 測試&所有連線的延遲
434 |
435 |
436 |
437 | &Show Filter Bar
438 | &顯示篩選列
439 |
440 |
441 |
442 | Ctrl+F
443 |
444 |
445 |
446 |
447 | &Export as gui-config.json
448 | &匯出為 gui-config.json
449 |
450 |
451 |
452 | Scan &QR Code using Capturer
453 | &使用捕捉器掃描 QR 碼
454 |
455 |
456 |
457 | Scan QR Code using Capturer
458 | 使用捕捉器掃描 QR 碼
459 |
460 |
461 |
462 | &Force Connect
463 | 強迫連線(&E)
464 |
465 |
466 | Force Connect
467 | 強迫連線
468 |
469 |
470 |
471 | Connect to this connection and disconnect any connections currently using the same local port
472 | 連線至此連線並且中斷使用了相同本機埠的連線
473 |
474 |
475 |
476 | From &config.json
477 | 自 &config.json
478 |
479 |
480 |
481 | &Save Manually
482 | &手動儲存
483 |
484 |
485 |
486 | Ctrl+Shift+S
487 |
488 |
489 |
490 |
491 | &Move Up
492 | &向上移動
493 |
494 |
495 |
496 | Mo&ve Down
497 | &向下移動
498 |
499 |
500 |
501 | &Import Connections from gui-config.json
502 | &自 gui-config.json 匯入連線
503 |
504 |
505 |
506 | Import connections from old version configuration file
507 | 自舊版設定檔匯入連線
508 |
509 |
510 |
511 | &Test Latency
512 | &測試延遲
513 |
514 |
515 |
516 | QObject
517 |
518 | Failed to communicate with previously running instance of Shadowsocks-Qt5 (PID: %1). It might already crashed.
519 | 與之前執行的 Shadowsocks-Qt5 執行個體(PID: %1)通訊失敗。或許已損毀。
520 |
521 |
522 | Error
523 | 錯誤
524 |
525 |
526 | Another instance of Shadowsocks-Qt5 (PID: %1) is already running.
527 | 另一個 Shadowsocks-Qt5 (PID: %1) 的執行個體已在執行。
528 |
529 |
530 |
531 | Unnamed Profile
532 | 未命名的設定檔
533 |
534 |
535 |
536 | QRCodeCapturer
537 |
538 | QR Code Capturer
539 | QR 碼捕捉器
540 |
541 |
542 |
543 | QR Capturer
544 | QR 碼捕捉器
545 |
546 |
547 |
548 | QRWidget
549 |
550 |
551 | Generating QR code failed.
552 | QR 碼產生失敗。
553 |
554 |
555 |
556 | SettingsDialog
557 |
558 |
559 | General Settings
560 | 一般設定
561 |
562 |
563 |
564 | Toolbar Style
565 | 工具列樣式
566 |
567 |
568 |
569 | Icons Only
570 | 僅圖示
571 |
572 |
573 |
574 | Text Only
575 | 僅文字
576 |
577 |
578 |
579 | Text Alongside Icons
580 | 文字在圖示邊
581 |
582 |
583 |
584 | Text Under Icons
585 | 文字在圖示下
586 |
587 |
588 |
589 | System Style
590 | 系統樣式
591 |
592 |
593 |
594 | Allow only one instance running
595 | 僅允許一個執行個體執行
596 |
597 |
598 |
599 | Hide window on startup
600 | 啟動時隱藏視窗
601 |
602 |
603 |
604 | Need to restart the application for this change to take effect
605 | 需要重新啟動程式方能使此變更生效
606 |
607 |
608 |
609 | Use native menu bar
610 | 使用原生選單列
611 |
612 |
613 |
614 | Start at login
615 |
616 |
617 |
618 |
619 | ShareDialog
620 |
621 |
622 | Share Profile
623 | 分享設定檔
624 |
625 |
626 |
627 | Save QR code as an Image file
628 | 儲存 QR 碼為圖檔
629 |
630 |
631 |
632 | Save QR Code
633 | 儲存 QR 碼
634 |
635 |
636 |
637 | StatusNotifier
638 |
639 |
640 |
641 | Minimise
642 | 最小化
643 |
644 |
645 |
646 | Quit
647 | 結束
648 |
649 |
650 |
651 |
652 | Restore
653 | 還原
654 |
655 |
656 |
657 | URIInputDialog
658 |
659 |
660 | URI Input Dialog
661 | URI 輸入對話方塊
662 |
663 |
664 |
665 | Please input ss:// URI
666 | 請輸入 ss:// URI
667 |
668 |
669 |
670 |
--------------------------------------------------------------------------------
/src/i18n/ss-qt5_zh_CN.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ConnectionItem
6 |
7 |
8 | Connected
9 | 已连接
10 |
11 |
12 |
13 | Disconnected
14 | 未连接
15 |
16 |
17 |
18 | Timeout
19 | 超时
20 |
21 |
22 |
23 | Error
24 | 错误
25 |
26 |
27 |
28 | Unknown
29 | 未知
30 |
31 |
32 |
33 | s
34 | 秒
35 |
36 |
37 |
38 | ms
39 | 毫秒
40 |
41 |
42 |
43 | connected
44 | 已连接
45 |
46 |
47 |
48 | disconnected
49 | 已断开
50 |
51 |
52 |
53 | timed out
54 | 超时
55 |
56 |
57 |
58 | latency test failed
59 | 延迟测试失败
60 |
61 |
62 |
63 | Failed to start
64 | 无法启动
65 |
66 |
67 |
68 | ConnectionTableModel
69 |
70 |
71 | Name
72 | 名称
73 |
74 |
75 |
76 | Server
77 | 服务器
78 |
79 |
80 |
81 | Status
82 | 状态
83 |
84 |
85 |
86 | Latency
87 | 延迟
88 |
89 |
90 |
91 | Local Port
92 | 本地端口
93 |
94 |
95 |
96 | Term Usage
97 | 本期用量
98 |
99 |
100 |
101 | Total Usage
102 | 累计用量
103 |
104 |
105 |
106 | Reset Date
107 | 重置日期
108 |
109 |
110 |
111 | Last Used
112 | 上次使用
113 |
114 |
115 |
116 | EditDialog
117 |
118 |
119 | Profile Editor
120 | 配置编辑器
121 |
122 |
123 |
124 | Local Server Type
125 | 本地服务器类型
126 |
127 |
128 |
129 | Timeout
130 | 超时
131 |
132 |
133 |
134 | [Deprecated] Turn on one-time authentication and header verification (need server support)
135 | [弃用]开启一次验证和消息头验证(需要服务器支持)
136 |
137 |
138 | Turn on one-time authentication and header verification (need server support)
139 | 开启一次验证和消息头验证(需要服务器支持)
140 |
141 |
142 |
143 | One-time authentication
144 | 一次验证
145 |
146 |
147 |
148 | Encryption Method
149 | 加密方式
150 |
151 |
152 |
153 | Local Port
154 | 本地端口
155 |
156 |
157 |
158 | Local Address
159 | 本地地址
160 |
161 |
162 |
163 | Password
164 | 密钥
165 |
166 |
167 |
168 | Server Port
169 | 服务器端口
170 |
171 |
172 |
173 | Server Address
174 | 服务器地址
175 |
176 |
177 |
178 | Profile Name
179 | 配置名称
180 |
181 |
182 |
183 | Auto connect on application start
184 | 程序启动时自动连接
185 |
186 |
187 |
188 | Debug
189 | 调试
190 |
191 |
192 |
193 | Log Level
194 | 日志级别
195 |
196 |
197 |
198 | Automation
199 | 自动化
200 |
201 |
202 |
203 | Reset Data Usage after
204 | 重置数据流量
205 |
206 |
207 |
208 | LogDialog
209 |
210 |
211 | Log Viewer
212 | 日志查看器
213 |
214 |
215 |
216 | Save log as a plain text file
217 | 保存日志为文本文件
218 |
219 |
220 |
221 | Save As...
222 | 保存为...
223 |
224 |
225 |
226 | Clear
227 | 清空
228 |
229 |
230 |
231 | Save Log As
232 | 保存日志为
233 |
234 |
235 |
236 | MainWindow
237 |
238 |
239 | About
240 | 关于
241 |
242 |
243 |
244 | Import Connections from gui-config.json
245 | 从gui-config.json导入连接
246 |
247 |
248 |
249 | Export Connections as gui-config.json
250 | 将所有连接信息导出为gui-config.json
251 |
252 |
253 |
254 |
255 | QR Code Not Found
256 | 未找到二维码
257 |
258 |
259 |
260 |
261 | Can't find any QR code image that contains valid URI on your screen(s).
262 | 无法在您的屏幕上找到任何包含有效URI的二维码图像。
263 |
264 |
265 |
266 | Open QR Code Image File
267 | 打开二维码图像文件
268 |
269 |
270 |
271 | Open config.json
272 | 打开 config.json
273 |
274 |
275 |
276 |
277 | Invalid
278 | 无效
279 |
280 |
281 |
282 |
283 | The connection's profile is invalid!
284 | 当前连接的配置无效!
285 |
286 |
287 |
288 | Connection Manager
289 | 连接编辑器
290 |
291 |
292 |
293 | &Connection
294 | 连接(&C)
295 |
296 |
297 |
298 | &Add
299 | 添加(&A)
300 |
301 |
302 |
303 | Fi&le
304 | 文件(&F)
305 |
306 |
307 |
308 | Settin&gs
309 | 设置(&S)
310 |
311 |
312 | Help
313 | 帮助(&H)
314 |
315 |
316 |
317 | &Manually
318 | 手动(&M)
319 |
320 |
321 |
322 | Add connection manually
323 | 手动添加连接
324 |
325 |
326 |
327 | &From QR Code Image File
328 | 自二维码图像文件(&Q)
329 |
330 |
331 |
332 | From QR code image file
333 | 自二维码图像文件
334 |
335 |
336 |
337 | View &Log
338 | 查看日志(&L)
339 |
340 |
341 |
342 | &Scan QR Code on Screen
343 | 扫描屏幕上的二维码(&S)
344 |
345 |
346 |
347 | Input to filter
348 | 输入以过滤
349 |
350 |
351 |
352 | Show Toolbar
353 | 显示工具栏
354 |
355 |
356 |
357 | &Help
358 | 帮助(&H)
359 |
360 |
361 |
362 | &URI
363 | &URI
364 |
365 |
366 |
367 | Add connection from URI
368 | 从 URI 添加连接
369 |
370 |
371 |
372 | &Delete
373 | 删除(&D)
374 |
375 |
376 |
377 | &Edit
378 | 编辑(&E)
379 |
380 |
381 |
382 | &Connect
383 | 连接(&C)
384 |
385 |
386 |
387 | D&isconnect
388 | 断开连接(&D)
389 |
390 |
391 |
392 | &Quit
393 | 退出(&Q)
394 |
395 |
396 |
397 | Ctrl+Q
398 |
399 |
400 |
401 |
402 | &About
403 | 关于(&A)
404 |
405 |
406 |
407 | About &Qt
408 | 关于 &Qt
409 |
410 |
411 |
412 | &General Settings
413 | 常规设置(&G)
414 |
415 |
416 |
417 | &Share
418 | 分享(&S)
419 |
420 |
421 |
422 | &Report Bug
423 | 报告错误(&R)
424 |
425 |
426 |
427 | Test the latency of selected connection
428 | 测试所选连接的延迟
429 |
430 |
431 |
432 | Test All C&onnections Latency
433 | 测试所有连接的延迟(&O)
434 |
435 |
436 |
437 | &Show Filter Bar
438 | 显示过滤栏(&S)
439 |
440 |
441 |
442 | Ctrl+F
443 |
444 |
445 |
446 |
447 | &Export as gui-config.json
448 | 导出为gui-config.json (&E)
449 |
450 |
451 |
452 | Scan &QR Code using Capturer
453 | 使用捕获器扫描二维码(&C)
454 |
455 |
456 |
457 | Scan QR Code using Capturer
458 | 使用捕获器扫描二维码
459 |
460 |
461 |
462 | &Force Connect
463 | 强制连接(&F)
464 |
465 |
466 | Force Connect
467 | 强制连接
468 |
469 |
470 |
471 | Connect to this connection and disconnect any connections currently using the same local port
472 | 连接到该连接并断开占用了相同本地端口的连接
473 |
474 |
475 |
476 | From &config.json
477 | 自 &config.json
478 |
479 |
480 |
481 | &Save Manually
482 | 手动保存(&S)
483 |
484 |
485 |
486 | Ctrl+Shift+S
487 |
488 |
489 |
490 |
491 | &Move Up
492 | 上移(&U)
493 |
494 |
495 |
496 | Mo&ve Down
497 | 下移(&V)
498 |
499 |
500 |
501 | &Import Connections from gui-config.json
502 | 从 gui-config.json导入连接(&I)
503 |
504 |
505 |
506 | Import connections from old version configuration file
507 | 从旧版配置文件导入连接
508 |
509 |
510 |
511 | &Test Latency
512 | 测试延迟(&T)
513 |
514 |
515 |
516 | QObject
517 |
518 | Failed to communicate with previously running instance of Shadowsocks-Qt5 (PID: %1). It might already crashed.
519 | 无法与先前运行的Shadowsocks-Qt5实例(PID: %1)通讯。可能已经崩溃了。
520 |
521 |
522 | Error
523 | 错误
524 |
525 |
526 | Another instance of Shadowsocks-Qt5 (PID: %1) is already running.
527 | 另一个 Shadowsocks-Qt5 (PID: %1) 的实例已经在运行了。
528 |
529 |
530 |
531 | Unnamed Profile
532 | 未命名配置
533 |
534 |
535 |
536 | QRCodeCapturer
537 |
538 | QR Code Capturer
539 | 二维码捕获器
540 |
541 |
542 |
543 | QR Capturer
544 | 二维码捕获器
545 |
546 |
547 |
548 | QRWidget
549 |
550 |
551 | Generating QR code failed.
552 | 二维码生成失败。
553 |
554 |
555 |
556 | SettingsDialog
557 |
558 |
559 | General Settings
560 | 常规设置
561 |
562 |
563 |
564 | Toolbar Style
565 | 工具栏风格
566 |
567 |
568 |
569 | Icons Only
570 | 仅图标
571 |
572 |
573 |
574 | Text Only
575 | 仅文本
576 |
577 |
578 |
579 | Text Alongside Icons
580 | 文本在图标侧
581 |
582 |
583 |
584 | Text Under Icons
585 | 文本在图标下
586 |
587 |
588 |
589 | System Style
590 | 系统风格
591 |
592 |
593 |
594 | Allow only one instance running
595 | 仅允许一个实例运行
596 |
597 |
598 |
599 | Hide window on startup
600 | 启动时隐藏窗口
601 |
602 |
603 |
604 | Need to restart the application for this change to take effect
605 | 需重启程序以生效
606 |
607 |
608 |
609 | Use native menu bar
610 | 使用原生菜单栏
611 |
612 |
613 |
614 | Start at login
615 | 登录时启动
616 |
617 |
618 |
619 | ShareDialog
620 |
621 |
622 | Share Profile
623 | 分享配置
624 |
625 |
626 |
627 | Save QR code as an Image file
628 | 保存二维码为图像文件
629 |
630 |
631 |
632 | Save QR Code
633 | 保存二维码
634 |
635 |
636 |
637 | StatusNotifier
638 |
639 |
640 |
641 | Minimise
642 | 最小化
643 |
644 |
645 |
646 | Quit
647 | 退出
648 |
649 |
650 |
651 |
652 | Restore
653 | 恢复
654 |
655 |
656 |
657 | URIInputDialog
658 |
659 |
660 | URI Input Dialog
661 | URI输入对话框
662 |
663 |
664 |
665 | Please input ss:// URI
666 | 请输入 ss:// URI
667 |
668 |
669 |
670 |
--------------------------------------------------------------------------------