Commit 5577fb23 authored by 神楽坂玲奈's avatar 神楽坂玲奈

i18n

parent 4fd5e106
......@@ -34,10 +34,17 @@
"root": "",
"sourceRoot": "src",
"prefix": "app",
"i18n": {
"sourceLocale": "zh-Hans",
"locales": {
"en-US": "src/locale/messages.en-US.xlf"
}
},
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"localize": ["zh-Hans"],
"allowedCommonJsDependencies": [
"glob",
"aria2",
......
'use strict';
// 处理提权
function handleElevate() {
// for debug
if (process.argv[1] === '.') {
process.argv[1] = process.argv[2];
process.argv[2] = process.argv[3];
}
if (process.argv[1] === '-e') {
if (process.platform === 'darwin') {
require('electron').app.dock.hide();
}
let elevate = JSON.parse(Buffer.from(process.argv[2], 'base64').toString());
require('net').connect(elevate['ipc'], function() {
process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + require('os').EOL, callback);
this.on('end', () => process.emit('disconnect'));
require('readline').createInterface({ input: this }).on('line', (line) => process.emit('message', JSON.parse(line)));
process.argv = elevate['arguments'][1];
require('./' + elevate['arguments'][0]);
});
return true;
}
}
if (handleElevate()) {
return;
}
const { ipcMain, app, shell, BrowserWindow, Menu, Tray, Notification } = require('electron');
const { autoUpdater } = require('electron-updater');
const isDev = require('electron-is-dev');
const child_process = require('child_process');
const path = require('path');
require('@electron/remote/main').initialize();
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
// aria2c启动失败则为null
let aria2c;
// 单实例
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
}
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
if (!mainWindow.isVisible()) {
mainWindow.show();
}
mainWindow.focus();
}
});
// 调试模式
if (!process.env['NODE_ENV']) {
process.env['NODE_ENV'] = isDev ? 'development' : 'production';
}
// 自动更新
let updateWindow;
global.autoUpdater = autoUpdater;
// if (process.env['NODE_ENV'] == 'production' && process.platform == 'darwin') {
// autoUpdater.setFeedURL("https://wudizhanche.mycard.moe/update/darwin/" + app.getVersion());
// }
// else{
// setTimeout(()=>{
// autoUpdater.emit('checking-for-update')
// }, 5000)
// setTimeout(()=>{
// autoUpdater.emit('error', '1')
// }, 6000)
// }
autoUpdater.on('error', (event) => {
global.update_status = 'error';
console.log('autoUpdater', 'error', event);
});
autoUpdater.on('checking-for-update', () => {
global.update_status = 'checking-for-update';
console.log('autoUpdater', 'checking-for-update');
});
autoUpdater.on('update-available', () => {
global.update_status = 'update-available';
console.log('autoUpdater', 'update-available');
});
autoUpdater.on('update-not-available', () => {
global.update_status = 'update-not-available';
console.log('autoUpdater', 'update-not-available');
});
autoUpdater.on('update-downloaded', (event) => {
global.update_status = 'update-downloaded';
console.log('autoUpdater', 'update-downloaded', event);
updateWindow = new BrowserWindow({
width: 640,
height: 360
});
updateWindow.loadURL(`file://${__dirname}/update.html`);
updateWindow.webContents.on('new-window', function(e, url) {
e.preventDefault();
shell.openExternal(url);
});
updateWindow.on('closed', function() {
updateWindow = null;
});
ipcMain.on('update', (event, arg) => {
autoUpdater.quitAndInstall();
});
});
// Aria2c
function createAria2c() {
let aria2c_path;
switch (process.platform) {
case 'win32':
if (process.env['NODE_ENV'] === 'production') {
aria2c_path = path.join(process.resourcesPath, 'bin', 'aria2c.exe');
} else {
aria2c_path = path.join('bin', 'aria2c.exe');
}
break;
case 'darwin':
if (process.env['NODE_ENV'] === 'production') {
aria2c_path = path.join(process.resourcesPath, 'bin', 'aria2c');
} else {
aria2c_path = path.join('bin', 'aria2c');
}
break;
case 'linux':
aria2c_path = '/usr/bin/aria2c';
break;
default:
throw 'unsupported platform';
}
aria2c = child_process.spawn(aria2c_path, [
'--enable-rpc',
'--rpc-allow-origin-all',
'--rpc-listen-port=6800',
'--continue',
'--split=10',
'--min-split-size=1M',
'--max-connection-per-server=10',
'--remove-control-file',
'--allow-overwrite'
], { stdio: 'ignore' });
}
// 主窗口
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 1024,
height: 640,
minWidth: 1024,
minHeight: 640,
frame: process.platform === 'darwin',
webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true },
// transparent: process.platform != 'darwin',
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined
});
// and load the index.html of the app.
if (isDev) {
mainWindow.loadURL('http://localhost:4200/');
} else {
mainWindow.loadFile('dist/mycard/index.html');
}
mainWindow.webContents.on('new-window', function(e, url) {
e.preventDefault();
shell.openExternal(url);
});
// Open the DevTools.
if (process.env['NODE_ENV'] === 'development') {
mainWindow.webContents.openDevTools();
}
// Emitted when the window is closed.
mainWindow.on('closed', function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
let tray;
function createTray() {
tray = new Tray(path.join(__dirname, 'images', 'icon.ico'));
tray.on('click', (event) => {
console.log(event);
if (event.metaKey) {
mainWindow.webContents.openDevTools();
} else {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
});
const contextMenu = Menu.buildFromTemplate([
// {label: '游戏', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
// {label: '社区', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
// {label: '切换账号', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
{
label: '显示主界面', type: 'normal', click: () => {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
},
{
label: '退出', type: 'normal', click: app.quit
}
]);
tray.setToolTip('MyCard');
tray.setContextMenu(contextMenu);
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
createWindow();
if (process.platform === 'win32') {
createTray();
}
createAria2c();
aria2c.on('error', (err) => {
new Notification({ title: 'MyCard', body: '启动aria2失败,可能是被杀毒软件误删。游戏下载和更新功能将不可用。' }).show();
console.error(err);
aria2c = null;
});
if (process.env['NODE_ENV'] === 'production') {
/*let updateTempPath = '~/.cache/mycard-updater'
if (process.platform === 'win32') {
updateTempPath = `${process.env.LOCALAPPDATA}\\mycard-updater`
} else if (process.platform === 'darwin') {
updateTempPath = '~/Library/Application Support/Caches/mycard-updater'
}
try {
await require('fs').promises.mkdir(updateTempPath, {recursive: true});
} catch(e) {}*/
await autoUpdater.checkForUpdates();
}
});
// Quit when all windows are closed.
app.on('window-all-closed', function() {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', function() {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
app.on('quit', () => {
// windows 在非 detach 模式下会自动退出子进程
if (process.platform !== 'win32' && aria2c) {
aria2c.kill();
}
});
'use strict';
// 处理提权
function handleElevate() {
// for debug
if (process.argv[1] === '.') {
process.argv[1] = process.argv[2];
process.argv[2] = process.argv[3];
}
if (process.argv[1] === '-e') {
if (process.platform === 'darwin') {
require('electron').app.dock.hide();
}
let elevate = JSON.parse(Buffer.from(process.argv[2], 'base64').toString());
require('net').connect(elevate['ipc'], function () {
process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + require('os').EOL, callback);
this.on('end', () => process.emit('disconnect'));
require('readline')
.createInterface({ input: this })
.on('line', (line) => process.emit('message', JSON.parse(line)));
process.argv = elevate['arguments'][1];
require('./' + elevate['arguments'][0]);
});
return true;
}
}
if (handleElevate()) {
return;
}
const { ipcMain, app, shell, BrowserWindow, Menu, Tray, Notification } = require('electron');
const { autoUpdater } = require('electron-updater');
const { localStorage } = require('electron-browser-storage');
const isDev = require('electron-is-dev');
const child_process = require('child_process');
const path = require('path');
require('@electron/remote/main').initialize();
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
// aria2c启动失败则为null
let aria2c;
// 单实例
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
}
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
if (!mainWindow.isVisible()) {
mainWindow.show();
}
mainWindow.focus();
}
});
// 调试模式
if (!process.env['NODE_ENV']) {
process.env['NODE_ENV'] = isDev ? 'development' : 'production';
}
// 自动更新
let updateWindow;
global.autoUpdater = autoUpdater;
// if (process.env['NODE_ENV'] == 'production' && process.platform == 'darwin') {
// autoUpdater.setFeedURL("https://wudizhanche.mycard.moe/update/darwin/" + app.getVersion());
// }
// else{
// setTimeout(()=>{
// autoUpdater.emit('checking-for-update')
// }, 5000)
// setTimeout(()=>{
// autoUpdater.emit('error', '1')
// }, 6000)
// }
autoUpdater.on('error', (event) => {
global.update_status = 'error';
console.log('autoUpdater', 'error', event);
});
autoUpdater.on('checking-for-update', () => {
global.update_status = 'checking-for-update';
console.log('autoUpdater', 'checking-for-update');
});
autoUpdater.on('update-available', () => {
global.update_status = 'update-available';
console.log('autoUpdater', 'update-available');
});
autoUpdater.on('update-not-available', () => {
global.update_status = 'update-not-available';
console.log('autoUpdater', 'update-not-available');
});
autoUpdater.on('update-downloaded', (event) => {
global.update_status = 'update-downloaded';
console.log('autoUpdater', 'update-downloaded', event);
updateWindow = new BrowserWindow({
width: 640,
height: 360,
});
updateWindow.loadURL(`file://${__dirname}/update.html`);
updateWindow.webContents.on('new-window', function (e, url) {
e.preventDefault();
shell.openExternal(url);
});
updateWindow.on('closed', function () {
updateWindow = null;
});
ipcMain.on('update', (event, arg) => {
autoUpdater.quitAndInstall();
});
});
// Aria2c
function createAria2c() {
let aria2c_path;
switch (process.platform) {
case 'win32':
if (process.env['NODE_ENV'] === 'production') {
aria2c_path = path.join(process.resourcesPath, 'bin', 'aria2c.exe');
} else {
aria2c_path = path.join('bin', 'aria2c.exe');
}
break;
case 'darwin':
if (process.env['NODE_ENV'] === 'production') {
aria2c_path = path.join(process.resourcesPath, 'bin', 'aria2c');
} else {
aria2c_path = path.join('bin', 'aria2c');
}
break;
case 'linux':
aria2c_path = '/usr/bin/aria2c';
break;
default:
throw 'unsupported platform';
}
aria2c = child_process.spawn(
aria2c_path,
[
'--enable-rpc',
'--rpc-allow-origin-all',
'--rpc-listen-port=6800',
'--continue',
'--split=10',
'--min-split-size=1M',
'--max-connection-per-server=10',
'--remove-control-file',
'--allow-overwrite',
],
{ stdio: 'ignore' }
);
}
async function getLocale() {
const store = await localStorage.getItem('locale');
if (store) return store;
return app.getLocale().startsWith('zh') ? 'zh-Hans' : 'en-US';
}
// 主窗口
async function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 1024,
height: 640,
minWidth: 1024,
minHeight: 640,
frame: process.platform === 'darwin',
webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true },
// transparent: process.platform != 'darwin',
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined,
});
// and load the index.html of the app.
if (isDev) {
mainWindow.loadURL('http://localhost:4200/');
} else {
mainWindow.loadFile(path.join('dist/mycard', await getLocale(), 'index.html'));
}
mainWindow.webContents.on('new-window', function (e, url) {
e.preventDefault();
shell.openExternal(url);
});
// Open the DevTools.
if (process.env['NODE_ENV'] === 'development') {
mainWindow.webContents.openDevTools();
}
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
let tray;
function createTray() {
tray = new Tray(path.join(__dirname, isDev ? 'src' : 'dist/mycard/zh-Hans', 'assets/icon.ico'));
tray.on('click', (event) => {
console.log(event);
if (event.metaKey) {
mainWindow.webContents.openDevTools();
} else {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
});
const contextMenu = Menu.buildFromTemplate([
// {label: '游戏', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
// {label: '社区', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
// {label: '切换账号', type: 'normal', click: (menuItem, browserWindow, event)=>{}},
{
label: '显示主界面',
type: 'normal',
click: () => {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
},
},
{
label: '退出',
type: 'normal',
click: app.quit,
},
]);
tray.setToolTip('MyCard');
tray.setContextMenu(contextMenu);
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
createWindow();
if (process.platform === 'win32') {
createTray();
}
createAria2c();
aria2c.on('error', (err) => {
new Notification({ title: 'MyCard', body: '启动aria2失败,可能是被杀毒软件误删。游戏下载和更新功能将不可用。' }).show();
console.error(err);
aria2c = null;
});
if (process.env['NODE_ENV'] === 'production') {
/*let updateTempPath = '~/.cache/mycard-updater'
if (process.platform === 'win32') {
updateTempPath = `${process.env.LOCALAPPDATA}\\mycard-updater`
} else if (process.platform === 'darwin') {
updateTempPath = '~/Library/Application Support/Caches/mycard-updater'
}
try {
await require('fs').promises.mkdir(updateTempPath, {recursive: true});
} catch(e) {}*/
await autoUpdater.checkForUpdates();
}
});
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
app.on('quit', () => {
// windows 在非 detach 模式下会自动退出子进程
if (process.platform !== 'win32' && aria2c) {
aria2c.kill();
}
});
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -13,6 +13,12 @@
"main": "main.js",
"description": "萌卡客户端",
"author": "zh99998 <zh99998@gmail.com>",
"dependencies": {
"@electron/remote": "^1.2.1",
"electron-browser-storage": "^1.0.7",
"electron-is-dev": "^2.0.0",
"electron-updater": "^4.3.9"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^12.1.1",
"@angular/animations": "~12.2.5",
......@@ -26,41 +32,93 @@
"@angular/platform-browser": "~12.2.5",
"@angular/platform-browser-dynamic": "~12.2.5",
"@angular/router": "~12.2.5",
"@types/bootstrap": "^5.1.4",
"@types/mousetrap": "^1.6.8",
"@types/node": "^16.4.13",
"bootstrap": "^5.1.0",
"copy-webpack-plugin": "^9.0.1",
"electron": "^13.3.0",
"electron-builder": "^22.11.7",
"mousetrap": "^1.6.5",
"rxjs": "^7.3.0",
"tslib": "^2.3.0",
"typescript": "~4.3.5",
"zone.js": "~0.11.4"
},
"dependencies": {
"@electron/remote": "^1.2.1",
"@fortawesome/fontawesome-free": "^5.15.4",
"@types/bootstrap": "^5.1.4",
"@types/ini": "^1.3.30",
"@types/jquery": "^3.5.6",
"@types/mousetrap": "^1.6.8",
"@types/mustache": "^4.1.2",
"@types/node": "^16.4.13",
"aria2": "^3.0.1",
"bootstrap": "^5.1.0",
"candy": "https://github.com/moecube/candy/releases/download/v2.2.0/candy.tar.gz",
"candy-shop": "github:candy-chat/candy-plugins",
"electron-is-dev": "^2.0.0",
"electron-updater": "^4.3.9",
"copy-webpack-plugin": "^9.0.1",
"electron": "^14.0.0",
"electron-builder": "^22.11.7",
"electron-builder-notarize": "^1.2.0",
"exports-loader": "^3.0.0",
"imports-loader": "^3.0.0",
"ini": "^2.0.0",
"jquery": "^3.6.0",
"jquery-i18n": "github:recurser/jquery-i18n",
"mousetrap": "^1.6.5",
"mustache": "^4.2.0",
"reconnecting-websocket": "^4.4.0",
"rxjs": "^7.3.0",
"strophe.js": "^1.4.2",
"strophejs-plugin-caps": "^1.1.3",
"strophejs-plugin-disco": "^0.0.2",
"strophejs-plugin-muc": "^1.1.0",
"strophejs-plugin-roster": "^1.1.0"
"strophejs-plugin-roster": "^1.1.0",
"tslib": "^2.3.0",
"typescript": "4.3",
"zone.js": "~0.11.4"
},
"build": {
"productName": "MyCard",
"appId": "com.mycard.mycard",
"publish": [
{
"provider": "generic",
"url": "https://cdn02.moecube.com:444/downloads"
}
],
"asar": false,
"files": [
"main.js",
"dist/mycard"
],
"extraResources": [
"bin"
],
"win": {
"verifyUpdateCodeSignature": false
},
"linux": {
"target": [
{
"target": "AppImage"
}
]
},
"appImage": {
"publish": [
{
"provider": "generic",
"url": "https://cdn02.moecube.com:444/downloads"
}
]
},
"afterSign": "electron-builder-notarize",
"mac": {
"hardenedRuntime": true,
"entitlements": "./node_modules/electron-builder-notarize/entitlements.mac.inherit.plist"
},
"dmg": {
"contents": [
{
"x": 448,
"y": 344,
"type": "link",
"path": "/Applications"
},
{
"x": 192,
"y": 344,
"type": "file"
}
]
}
}
}
import { ChangeDetectorRef, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, Inject, Input, LOCALE_ID, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { AppsService } from '../apps.service';
import { InstallOption } from '../shared/install-option';
import { SettingsService } from '../settings.service';
......@@ -22,7 +22,7 @@ declare const Notification: any;
@Component({
selector: 'app-detail',
templateUrl: 'app-detail.component.html',
styleUrls: ['app-detail.component.css']
styleUrls: ['app-detail.component.css'],
})
export class AppDetailComponent implements OnInit, OnChanges {
@Input()
......@@ -44,23 +44,32 @@ export class AppDetailComponent implements OnInit, OnChanges {
payment = 'alipay';
creating_order = false;
constructor(public appsService: AppsService, private settingsService: SettingsService, private downloadService: DownloadService, private ref: ChangeDetectorRef, private el: ElementRef, private loginService: LoginService) {
this.tags = this.settingsService.getLocale().startsWith('zh') ? {
'recommend': '推荐',
'mysterious': '迷之物体',
'touhou': '东方 Project',
'touhou_pc98': '东方旧作',
'language': '语言包',
'ygopro': 'YGOPro'
} : {
'recommend': 'Recommended',
'mysterious': 'Something',
'touhou': 'Touhou Project',
'touhou_pc98': 'Touhou old series',
'language': 'Language Pack',
'ygopro': 'YGOPro'
};
constructor(
public appsService: AppsService,
private settingsService: SettingsService,
private downloadService: DownloadService,
private ref: ChangeDetectorRef,
private el: ElementRef,
private loginService: LoginService,
@Inject(LOCALE_ID) private locale: string
) {
this.tags = locale.startsWith('zh')
? {
recommend: '推荐',
mysterious: '迷之物体',
touhou: '东方 Project',
touhou_pc98: '东方旧作',
language: '语言包',
ygopro: 'YGOPro',
}
: {
recommend: 'Recommended',
mysterious: 'Something',
touhou: 'Touhou Project',
touhou_pc98: 'Touhou old series',
language: 'Language Pack',
ygopro: 'YGOPro',
};
}
async ngOnChanges(changes: SimpleChanges) {
......@@ -108,8 +117,7 @@ export class AppDetailComponent implements OnInit, OnChanges {
if (reference.isLanguage()) {
// 对于语言包,只有在语言包的locales比游戏本身的更加合适的时候才默认勾选
// 这里先偷个懒,中文环境勾选中文语言包,非中文环境勾选非中文语言包
this.referencesInstall[reference.id] =
reference.locales[0].startsWith('zh') === this.settingsService.getLocale().startsWith('zh');
this.referencesInstall[reference.id] = reference.locales[0].startsWith('zh') === this.locale.startsWith('zh');
} else {
this.referencesInstall[reference.id] = true;
}
......@@ -129,10 +137,8 @@ export class AppDetailComponent implements OnInit, OnChanges {
}
async installMod(mod: App) {
let option = new InstallOption(mod, path.dirname(mod.parent!.local!.path));
await this.install(mod, option, {});
}
async uninstall(app: App) {
......@@ -181,7 +187,7 @@ export class AppDetailComponent implements OnInit, OnChanges {
this.availableLibraries.splice(index, 1);
}
} else {
this.settingsService.setDefaultLibrary({ path: this.installOption.installLibrary, 'default': true });
this.settingsService.setDefaultLibrary({ path: this.installOption.installLibrary, default: true });
}
this.installOption.installLibrary = this.settingsService.getDefaultLibrary().path;
}
......
import { ApplicationRef, EventEmitter, Injectable, NgZone } from '@angular/core';
import { ApplicationRef, EventEmitter, Inject, Injectable, LOCALE_ID, NgZone } from '@angular/core';
import child_process from 'child_process';
import { ChildProcess } from 'child_process';
import crypto from 'crypto';
......@@ -20,8 +20,7 @@ import { AppsJson } from './shared/apps-json-type';
import os from 'os';
import Timer = NodeJS.Timer;
import { HttpClient } from '@angular/common/http';
import {lastValueFrom, map, Observable, Observer, timeout} from 'rxjs';
import { lastValueFrom, map, Observable, Observer, timeout } from 'rxjs';
const Logger = {
info: (...message: any[]) => {
......@@ -29,7 +28,7 @@ const Logger = {
},
error: (...message: any[]) => {
console.error('AppService [ERROR]: ', ...message);
}
},
};
interface InstallTask {
......@@ -52,10 +51,9 @@ interface Connection {
declare const System: any;
@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class AppsService {
eventEmitter = new EventEmitter<void>();
map: Map<string, string> = new Map();
connections = new Map<App, Connection>();
......@@ -81,9 +79,15 @@ export class AppsService {
private apps: Map<string, App>;
constructor(private http: HttpClient, private settingsService: SettingsService, private ref: ApplicationRef,
private downloadService: DownloadService, private ngZone: NgZone, private loginService: LoginService) {
}
constructor(
private http: HttpClient,
private settingsService: SettingsService,
private ref: ApplicationRef,
private downloadService: DownloadService,
private ngZone: NgZone,
private loginService: LoginService,
@Inject(LOCALE_ID) private locale: string
) {}
get lastVisited(): App | undefined {
let id = localStorage.getItem('last_visited');
......@@ -104,11 +108,13 @@ export class AppsService {
let keysURL = 'https://sapi.moecube.com:444/keys';
try {
let data = await lastValueFrom(this.http.get<AppsJson.App[]>(appsURL).pipe(timeout(5000)));
let keys_data = await lastValueFrom(this.http.get<any[]>(keysURL, {
params: {
user_id: this.loginService.user.email
}
}));
let keys_data = await lastValueFrom(
this.http.get<any[]>(keysURL, {
params: {
user_id: this.loginService.user.email,
},
})
);
for (let item of keys_data) {
let app = data.find((app: any) => app.id === item.app_id);
if (app) {
......@@ -183,19 +189,15 @@ export class AppsService {
// "installLibrary": "D:\\MyCardLibrary"
// },
// ]
// {
// library: "D:\\MyCardLibrary",
// apps: ["th105", "th105-lang-zh-CN", "th123", "th123-lang-zh-CN", "directx"]
// }
// 文件在 D:\MyCardLibrary\cache\th105.tar.xz, D:\MyCardLibrary\cache\th105-lang-zh-CN.tar.xz ...
// TODO: 安装那些app,不需要下载。安装成功后删除 bundle.json
} catch (error) {
}
} catch (error) {}
}
async migrate_v2_ygopro() {
// 导入萌卡 v2 的 YGOPRO
let app = this.apps.get('ygopro')!;
......@@ -222,8 +224,7 @@ export class AppsService {
await this.createDirectory(_library);
this.settingsService.addLibrary(_library, true);
library = _library;
} catch (error) {
}
} catch (error) {}
}
}
if (!library) {
......@@ -234,8 +235,7 @@ export class AppsService {
await this.importApp(app, legacy_ygopro_path, option);
localStorage.setItem('migrate_v2_ygopro', 'true');
}
} catch (error) {
}
} catch (error) {}
}
async migreate_library() {
......@@ -250,7 +250,6 @@ export class AppsService {
loadAppsList = (data: any): Map<string, App> => {
let apps = new Map<string, App>();
let locale = this.settingsService.getLocale();
let platform = process.platform;
for (let item of data) {
......@@ -277,7 +276,8 @@ export class AppsService {
// 去除无关语言
for (let key of ['name', 'description', 'news', 'developers', 'publishers']) {
if (app[key]) {
app[key] = app[key][locale] || app[key]['zh-CN'] || Object.values(app[key])[0];
app[key]['zh-Hans'] = app[key]['zh-CN'];
app[key] = app[key][this.locale] || app[key]['zh-Hans'] || Object.values(app[key])[0];
}
}
......@@ -308,7 +308,6 @@ export class AppsService {
}
apps.set(item.id, app);
}
// 设置App关系
......@@ -347,26 +346,28 @@ export class AppsService {
'en-US': 'English',
'zh-CN': 'Simplified Chinese',
'zh-TW': 'Traditional Chinese',
'language_pack': 'Language Pack'
language_pack: 'Language Pack',
},
'zh-CN': {
'zh-Hans': {
'en-US': '英文',
'zh-CN': '简体中文',
'zh-TW': '繁体中文',
'language_pack': '语言包'
}
language_pack: '语言包',
},
};
if (!app.name && app.parent && app.isLanguage()) {
app.name = `${app.parent.name} ${lang[locale].language_pack} (${app.locales.map((l) => lang[locale][l]).join(', ')})`;
app.name = `${app.parent.name} ${lang[this.locale].language_pack} (${app.locales.map((l) => lang[this.locale][l]).join(', ')})`;
}
}
return apps;
};
allReady(app: App) {
return app.isReady() &&
return (
app.isReady() &&
app.findDependencies().every((dependency) => dependency.isReady()) &&
this.findChildren(app).every((child) => (child.isInstalled() && child.isReady()) || !child.isInstalled());
this.findChildren(app).every((child) => (child.isInstalled() && child.isReady()) || !child.isInstalled())
);
}
async copyFile(src: string, dst: string): Promise<any> {
......@@ -411,8 +412,7 @@ export class AppsService {
});
app.status.total = sortedFiles.length;
// 刷新进度
let interval = setInterval(() => {
}, 500);
let interval = setInterval(() => {}, 500);
await new Promise((resolve, reject) => {
this.ngZone.runOutsideAngular(async () => {
try {
......@@ -427,7 +427,6 @@ export class AppsService {
} catch (e) {
} finally {
app.status.progress += 1;
}
}
}
......@@ -510,8 +509,7 @@ export class AppsService {
let localFiles: Map<string, string> | undefined;
if (verify) {
// 刷新进度条
let interval = setInterval(() => {
}, 500);
let interval = setInterval(() => {}, 500);
app.status.total = latestFiles.size;
await new Promise((resolve, reject) => {
this.ngZone.runOutsideAngular(async () => {
......@@ -653,12 +651,9 @@ export class AppsService {
async doUpdate(app: App, changedFiles?: Set<string>, deletedFiles?: Set<string>) {
if (changedFiles && changedFiles.size > 0) {
Logger.info('Update changed files: ', changedFiles);
let locale = this.settingsService.getLocale();
if (!['zh-CN', 'en-US', 'ja-JP'].includes(locale)) {
locale = 'en-US';
}
const locale = ['zh-Hans', 'en-US', 'ja-JP'].includes(this.locale) ? this.locale : 'en-US';
let updateUrl = App.updateUrl(app, process.platform, locale, os.arch());
let metalink = await lastValueFrom(this.http.post(updateUrl, changedFiles, {responseType: 'text'}));
let metalink = await lastValueFrom(this.http.post(updateUrl, changedFiles, { responseType: 'text' }));
let downloadDir = path.join(path.dirname(app.local!.path), 'downloading');
let downloadId = await this.downloadService.addMetalink(metalink, downloadDir);
await this.downloadService.progress(downloadId, (status: DownloadStatus) => {
......@@ -670,17 +665,20 @@ export class AppsService {
let downloadFiles = await this.downloadService.getFiles(downloadId);
app.status.total = 0;
// 刷新进度条
let interval = setInterval(() => {
}, 500);
let interval = setInterval(() => {}, 500);
for (let downloadFile of downloadFiles) {
await new Promise((resolve, reject) => {
this.extract(downloadFile, app.local!.path).subscribe((file) => {
app.status.progressMessage = file;
}, (error) => {
reject(error);
}, () => {
resolve(null);
});
this.extract(downloadFile, app.local!.path).subscribe(
(file) => {
app.status.progressMessage = file;
},
(error) => {
reject(error);
},
() => {
resolve(null);
}
);
});
}
clearInterval(interval);
......@@ -691,11 +689,9 @@ export class AppsService {
await this.deleteFile(path.join(app.local!.path, deletedFile));
}
}
}
async install(app: App, option: InstallOption) {
const tryToInstall = async (task: InstallTask): Promise<void> => {
if (!task.app.readyForInstall()) {
await new Promise((resolve, reject) => {
......@@ -710,14 +706,11 @@ export class AppsService {
}
await this.doInstall(task);
};
const addDownloadTask = async (_app: App, dir: string): Promise<{ app: App, files: string[] }> => {
let locale = this.settingsService.getLocale();
if (!['zh-CN', 'en-US', 'ja-JP'].includes(locale)) {
locale = 'en-US';
}
const addDownloadTask = async (_app: App, dir: string): Promise<{ app: App; files: string[] }> => {
const locale = ['zh-Hans', 'en-US', 'ja-JP'].includes(this.locale) ? this.locale : 'en-US';
let metalinkUrl = App.downloadUrl(_app, process.platform, locale, os.arch());
_app.status.status = 'downloading';
let metalink = await lastValueFrom(this.http.get(metalinkUrl,{responseType: 'text'}));
let metalink = await lastValueFrom(this.http.get(metalinkUrl, { responseType: 'text' }));
let downloadId = await this.downloadService.addMetalink(metalink, dir);
try {
await this.downloadService.progress(downloadId, (status: DownloadStatus) => {
......@@ -756,7 +749,6 @@ export class AppsService {
installTasks.push(task);
}
await Promise.all(installTasks);
} catch (e) {
for (let a of apps) {
if (!a.isReady()) {
......@@ -771,7 +763,7 @@ export class AppsService {
findChildren(app: App): App[] {
let children: App[] = [];
for (let child of this.apps.values()) {
if (child.parent === app || child.dependencies && child.dependencies.has(app.id)) {
if (child.parent === app || (child.dependencies && child.dependencies.has(app.id))) {
children.push(child);
}
}
......@@ -811,7 +803,9 @@ export class AppsService {
async network(app: App, server: any) {
if (!this.maotama) {
this.maotama = new Promise((resolve, reject) => {
let child = (process.platform === 'linux' ? child_process : sudo).fork('maotama', [], { stdio: ['inherit', 'inherit', 'inherit', 'ipc'] }); // it's very shit of Linux electron-sudo
let child = (process.platform === 'linux' ? child_process : sudo).fork('maotama', [], {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
}); // it's very shit of Linux electron-sudo
child.once('message', () => resolve(child));
child.once('error', reject);
child.once('exit', reject);
......@@ -845,7 +839,7 @@ export class AppsService {
id = setInterval(() => {
child.send({
action: 'connect',
arguments: [app.network.port, port, address]
arguments: [app.network.port, port, address],
});
}, 200);
break;
......@@ -876,10 +870,8 @@ export class AppsService {
// tarPath: string;
// installingId: string = '';
// installQueue: Map<string,InstallTask> = new Map();
// 调用前提:应用的依赖均已 Ready,应用处于下载完待安装的状态(waiting)。
// TODO: 要把Task系统去掉吗
async doInstall(task: InstallTask) {
......@@ -887,12 +879,12 @@ export class AppsService {
if (!app.isWaiting()) {
console.error('doUninstall', '应用不处于等待安装状态', app);
throw('应用不处于等待安装状态');
throw '应用不处于等待安装状态';
}
if (!app.readyForInstall()) {
console.error('doInstall', '应用依赖不齐备', app);
throw('应用依赖不齐备');
throw '应用依赖不齐备';
}
try {
......@@ -903,8 +895,7 @@ export class AppsService {
app.status.status = 'installing';
app.status.total = allFiles.size;
app.status.progress = 0;
let interval = setInterval(() => {
}, 500);
let interval = setInterval(() => {}, 500);
if (app.parent) {
// mod需要安装到parent路径
installDir = app.parent.local!.path;
......@@ -948,7 +939,8 @@ export class AppsService {
},
() => {
resolve(null);
});
}
);
});
}
clearInterval(interval);
......@@ -967,7 +959,6 @@ export class AppsService {
} finally {
this.eventEmitter.emit();
}
}
// 移除mkdirp函数,在这里自己实现
......@@ -986,7 +977,8 @@ export class AppsService {
}
});
});
} catch (error) { // 路径不存在,先尝试递归上级目录,再创建自己
} catch (error) {
// 路径不存在,先尝试递归上级目录,再创建自己
await this.createDirectory(path.dirname(dir));
return new Promise<boolean>((resolve, reject) => {
fs.mkdir(dir, (error) => {
......@@ -998,9 +990,11 @@ export class AppsService {
});
});
}
if (stats.isDirectory()) { // 路径存在并且已经是目录,成功返回
if (stats.isDirectory()) {
// 路径存在并且已经是目录,成功返回
return false;
} else { // 路径存在并且不是目录,失败。
} else {
// 路径存在并且不是目录,失败。
throw `#{dir} exists and is not a directory`;
}
}
......@@ -1014,7 +1008,7 @@ export class AppsService {
Logger.info('Start to extract... Command Line: ' + this.tarPath, tarArgs.join(' '));
let tarProcess = child_process.spawn(this.tarPath, tarArgs);
let rl = readline.createInterface({
input: this.getTarStream(tarProcess)
input: this.getTarStream(tarProcess),
});
rl.on('line', (input: string) => {
const line = input.split(' ', 2).pop()!;
......@@ -1032,8 +1026,7 @@ export class AppsService {
observer.error(code);
}
});
return () => {
};
return () => {};
});
}
......@@ -1059,7 +1052,7 @@ export class AppsService {
cwd: appPath,
env: env,
stdio: 'inherit',
shell: true
shell: true,
});
child.on('error', (error) => {
reject(error);
......@@ -1117,28 +1110,26 @@ export class AppsService {
}
async getChecksumFile(app: App): Promise<Map<string, string>> {
let locale = this.settingsService.getLocale();
if (!['zh-CN', 'en-US', 'ja-JP'].includes(locale)) {
locale = 'en-US';
}
const locale = ['zh-Hans', 'en-US', 'ja-JP'].includes(this.locale) ? this.locale : 'en-US';
let checksumUrl = App.checksumUrl(app, process.platform, locale, os.arch());
return lastValueFrom(this.http.get(checksumUrl,{responseType: 'text'}).pipe(map((response) => {
let map = new Map<string, string>();
for (let line of response.split('\n')) {
if (line !== '') {
let [checksum, filename] = line.split(' ', 2);
// checksum文件里没有文件夹,这里添加上
map.set(path.dirname(filename), '');
map.set(filename, checksum);
}
}
return map;
})));
return lastValueFrom(
this.http.get(checksumUrl, { responseType: 'text' }).pipe(
map((response) => {
let map = new Map<string, string>();
for (let line of response.split('\n')) {
if (line !== '') {
let [checksum, filename] = line.split(' ', 2);
// checksum文件里没有文件夹,这里添加上
map.set(path.dirname(filename), '');
map.set(filename, checksum);
}
}
return map;
})
)
);
}
deleteFile(file: string): Promise<string> {
return new Promise((resolve, reject) => {
fs.lstat(file, (err, stats) => {
......@@ -1191,8 +1182,7 @@ export class AppsService {
app.status.total = files.length;
// 500毫秒手动刷新,避免文件过多产生的性能问题
let interval = setInterval(() => {
}, 500);
let interval = setInterval(() => {}, 500);
await new Promise((resolve, reject) => {
this.ngZone.runOutsideAngular(async () => {
try {
......@@ -1214,7 +1204,6 @@ export class AppsService {
} catch (e) {
reject(e);
}
});
});
clearInterval(interval);
......@@ -1235,9 +1224,9 @@ export class AppsService {
y: y,
frame: process.platform === 'darwin',
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined,
parent: remote.getCurrentWindow()
parent: remote.getCurrentWindow(),
});
littleWindow.on('closed', function() {
littleWindow.on('closed', function () {
littleWindow = null!;
});
let urlt = new URL(url, window.location.toString());
......@@ -1247,6 +1236,5 @@ export class AppsService {
remote.ipcMain.on('massage', () => {
alert('from littleWindow');
});
}
}
......@@ -25,7 +25,7 @@ window['jQuery'] = $;
import Mustache from 'mustache';
import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { Component, ElementRef, Inject, Input, LOCALE_ID, OnChanges, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { LoginService } from '../login/login.service';
import { SettingsService } from '../settings.service';
import { App } from '../shared/app';
......@@ -262,7 +262,12 @@ export class CandyComponent implements OnInit, OnChanges {
// ismax_window:Boolean=false;
height_default_window: string = '230px';
constructor(private loginService: LoginService, private settingsService: SettingsService, private element: ElementRef) {}
constructor(
private loginService: LoginService,
private settingsService: SettingsService,
private element: ElementRef,
@Inject(LOCALE_ID) private locale: string
) {}
ngOnInit() {
this.jid = this.loginService.user.username + '@mycard.moe';
......@@ -307,7 +312,7 @@ export class CandyComponent implements OnInit, OnChanges {
},
view: {
assets: 'candy/res/', // copy-webpack-plugin
language: this.settingsService.getLocale().startsWith('zh') ? 'cn' : 'en',
language: this.locale.startsWith('zh') ? 'cn' : 'en',
enableXHTML: true,
},
});
......
/**
* Created by zh99998 on 16/9/2.
*/
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core';
import { AppsService } from '../apps.service';
import { LoginService } from '../login/login.service';
import { App, Category } from '../shared/app';
......@@ -16,10 +16,9 @@ const ReconnectingWebSocket = require('reconnecting-websocket');
@Component({
selector: 'lobby',
templateUrl: 'lobby.component.html',
styleUrls: ['lobby.component.css']
styleUrls: ['lobby.component.css'],
})
export class LobbyComponent implements OnInit {
currentApp: App;
resizing: HTMLElement | undefined;
offset: number;
......@@ -29,9 +28,13 @@ export class LobbyComponent implements OnInit {
//private messages: WebSocket;
constructor(private appsService: AppsService, private loginService: LoginService,
private settingsService: SettingsService, private ref: ChangeDetectorRef) {
}
constructor(
private appsService: AppsService,
private loginService: LoginService,
private settingsService: SettingsService,
private ref: ChangeDetectorRef,
@Inject(LOCALE_ID) private locale: string
) {}
get grouped_apps(): any {
// @ts-ignore
......@@ -51,7 +54,6 @@ export class LobbyComponent implements OnInit {
} else {
tags = ['runtime'];
}
}
for (const tag of tags) {
if (!result[tag]) {
......@@ -80,7 +82,7 @@ export class LobbyComponent implements OnInit {
}
}
// 特化个 YGOPRO 国际服聊天室。其他的暂时没需求。
if (!this.settingsService.getLocale().startsWith('zh')) {
if (!this.locale.startsWith('zh')) {
this.apps.get('ygopro')!.conference = 'ygopro-international';
}
this.ref.detectChanges();
......@@ -96,7 +98,6 @@ export class LobbyComponent implements OnInit {
this.currentApp = this.apps.get(this.currentApp.id)!;
}; */
// $(this.search.nativeElement).typeahead(<any>{
// minLength: 1,
// highlight: true
......
......@@ -77,9 +77,9 @@
<div class='form-group row'>
<label class='col-sm-2 col-form-label' for='locale' i18n>语言</label>
<div class='col-sm-10'>
<select [(ngModel)]='locale' class='form-control' id='locale' name='locale'>
<select [(ngModel)]='localeNew' class='form-control' id='locale' name='locale'>
<option value='en-US'>English</option>
<option value='zh-CN'>简体中文</option>
<option value='zh-Hans'>简体中文</option>
</select>
</div>
</div>
......
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core';
import { shell } from 'electron';
import * as remote from '@electron/remote';
import $ from 'jquery';
......@@ -32,7 +32,7 @@ export class MyCardComponent implements OnInit {
update_downloaded: ElementRef;
update_elements: Map<string, ElementRef>;
locale: string;
localeNew: string = this.locale;
resizing: HTMLElement | null;
......@@ -73,7 +73,11 @@ export class MyCardComponent implements OnInit {
// });
}
constructor(public loginService: LoginService, private ref: ChangeDetectorRef, private settingsService: SettingsService) {
constructor(
public loginService: LoginService,
private ref: ChangeDetectorRef,
@Inject(LOCALE_ID) public locale: string
) {
// renderer.listenGlobal('window', 'message', (event) => {
// console.log(event);
// // Do something with 'event'
......@@ -98,8 +102,6 @@ export class MyCardComponent implements OnInit {
autoUpdater.on('update-downloaded', (event) => {
this.set_update_status('update-downloaded');
});
this.locale = this.settingsService.getLocale();
}
update_retry() {
......@@ -128,8 +130,8 @@ export class MyCardComponent implements OnInit {
}
submit() {
if (this.locale !== this.settingsService.getLocale()) {
localStorage.setItem(SettingsService.SETTING_LOCALE, this.locale);
if (this.localeNew !== this.locale) {
localStorage.setItem(SettingsService.SETTING_LOCALE, this.localeNew);
remote.app.relaunch();
remote.app.quit();
}
......
/**
* Created by weijian on 2016/10/24.
*/
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
import path from 'path';
import { app } from '@electron/remote';
import {app} from '@electron/remote';
export interface Library {
'default': boolean;
......@@ -23,12 +23,8 @@ export class SettingsService {
}
];
static SETTING_LOCALE = 'locale';
static defaultLocale = app.getLocale();
locale: string;
libraries: Library[];
getLibraries() {
if (!this.libraries) {
let data = localStorage.getItem(SettingsService.SETTING_LIBRARY);
......@@ -51,7 +47,7 @@ export class SettingsService {
l.default = false;
});
}
libraries.push({ 'default': isDefault, path: libraryPath });
libraries.push({'default': isDefault, path: libraryPath});
this.libraries = libraries;
localStorage.setItem(SettingsService.SETTING_LIBRARY, JSON.stringify(libraries));
}
......@@ -76,22 +72,4 @@ export class SettingsService {
throw('no default library found');
}
}
getLocale(): string {
if (!this.locale) {
let locale = localStorage.getItem(SettingsService.SETTING_LOCALE);
if (!locale) {
this.locale = SettingsService.defaultLocale;
localStorage.setItem(SettingsService.SETTING_LOCALE, SettingsService.defaultLocale);
} else {
this.locale = locale;
}
}
return this.locale;
}
setLocale(locale: string) {
this.locale = locale;
localStorage.setItem(SettingsService.SETTING_LOCALE, locale);
}
}
......@@ -108,7 +108,7 @@ export class App {
static getQuerySuffix(platform: string, locale: string, arch: string) {
const params = new URLSearchParams();
params.set('platform', platform);
params.set('locale', locale);
params.set('locale', locale === 'zh-Hans' ? 'zh-CN' : 'zh-Hans');
params.set('arch', arch);
return params.toString();
}
......
import {LOCALE_ID, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core';
import * as remote from '@electron/remote';
export async function getTranslationProviders (): Promise<Object[]> {
let locale = localStorage.getItem('locale');
if (!locale) {
locale = remote.app.getLocale();
localStorage.setItem('locale', locale);
}
const noProviders: Object[] = [];
if (!locale || locale === 'zh-CN') {
return noProviders;
}
const translationFile = `./locale/messages.${locale}.xlf`;
try {
let translations = await getTranslationsWithSystemJs(translationFile);
return [
{provide: TRANSLATIONS, useValue: translations},
{provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
{provide: LOCALE_ID, useValue: locale}
];
} catch (error) {
return noProviders;
}
}
declare const System: any;
function getTranslationsWithSystemJs (file: string) {
return System.import(file + '!text'); // relies on text plugin
}
/**
* Created by zh99998 on 16/9/2.
*/
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
import {
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
Inject,
Input,
LOCALE_ID,
OnDestroy,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { clipboard, shell } from 'electron';
import * as remote from '@electron/remote'
import * as remote from '@electron/remote';
import fs from 'fs-extra';
import $ from 'jquery';
import path from 'path';
......@@ -16,7 +28,7 @@ import fg from 'fast-glob';
import { HttpClient } from '@angular/common/http';
import WillNavigateEvent = Electron.WillNavigateEvent;
import Timer = NodeJS.Timer;
import {lastValueFrom, Subscription} from 'rxjs';
import { lastValueFrom, Subscription } from 'rxjs';
interface SystemConf {
use_d3d: string;
......@@ -61,10 +73,10 @@ interface Room {
id?: string;
title?: string;
server?: Server;
'private'?: boolean;
private?: boolean;
options: Options;
arena?: string;
users?: { username: string, position: number }[];
users?: { username: string; position: number }[];
}
interface Options {
......@@ -106,7 +118,6 @@ interface YGOProData {
servers: Server[];
}
let matching: Subscription | undefined;
let matching_arena: string | undefined;
let match_started_at: Date;
......@@ -115,7 +126,7 @@ let match_started_at: Date;
moduleId: module.id,
selector: 'ygopro',
templateUrl: 'ygopro.component.html',
styleUrls: ['ygopro.component.css']
styleUrls: ['ygopro.component.css'],
})
export class YGOProComponent implements OnInit, OnDestroy {
@Input()
......@@ -153,7 +164,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
lastDeckFormat: RegExp;
default_options: Options = {
mode: 1,
rule: this.settingsService.getLocale().startsWith('zh') ? 0 : 1,
rule: this.locale.startsWith('zh') ? 0 : 1,
start_lp: 8000,
start_lp_tag: 16000,
start_hand: 5,
......@@ -163,7 +174,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
no_shuffle_deck: false,
lflist: 0,
time_limit: 180,
auto_death: false
auto_death: false,
};
room: Room = { title: this.loginService.user.username + '的房间', options: Object.assign({}, this.default_options) };
rooms: Room[] = [];
......@@ -178,7 +189,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
single: true,
match: true,
tag: true,
windbot: false
windbot: false,
};
matching: Subscription | undefined;
matching_arena: string | undefined;
......@@ -188,8 +199,14 @@ export class YGOProComponent implements OnInit, OnDestroy {
join_password: string;
host_password = (this.loginService.user.external_id ^ 0x54321).toString();
constructor(private http: HttpClient, public appsService: AppsService, private loginService: LoginService,
public settingsService: SettingsService, private ref: ChangeDetectorRef) {
constructor(
private http: HttpClient,
public appsService: AppsService,
private loginService: LoginService,
public settingsService: SettingsService,
private ref: ChangeDetectorRef,
@Inject(LOCALE_ID) public locale: string
) {
switch (process.platform) {
// linux should have fonts set by default
case 'linux':
......@@ -197,13 +214,13 @@ export class YGOProComponent implements OnInit, OnDestroy {
'/usr/share/fonts/truetype/DroidSansFallbackFull.ttf',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc',
'/usr/share/fonts/google-noto-cjk/NotoSansCJK-Bold.ttc',
'/usr/share/fonts/noto-cjk/NotoSansCJK-Bold.ttc'
'/usr/share/fonts/noto-cjk/NotoSansCJK-Bold.ttc',
];
this.textfont = [
'/usr/share/fonts/truetype/DroidSansFallbackFull.ttf',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
'/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc',
'/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc'
'/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc',
];
break;
case 'darwin':
......@@ -215,7 +232,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
this.textfont = [
path.join(process.env['SystemRoot']!, 'Fonts', 'msyh.ttc'),
path.join(process.env['SystemRoot']!, 'Fonts', 'msyh.ttf'),
path.join(process.env['SystemRoot']!, 'Fonts', 'simsun.ttc')
path.join(process.env['SystemRoot']!, 'Fonts', 'simsun.ttc'),
];
break;
}
......@@ -239,35 +256,39 @@ export class YGOProComponent implements OnInit, OnDestroy {
}
refresh_replay_rooms() {
this.replay_rooms_show = this.replay_rooms.filter((room) => {
if (!room.arena && room.server && room.server !== this.currentServer) {
return false;
}
return ((this.replay_rooms_filter.athletic && room.arena === 'athletic') ||
(this.replay_rooms_filter.entertain && room.arena === 'entertain') ||
(this.replay_rooms_filter.single && room.options.mode === 0 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.match && room.options.mode === 1 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.tag && room.options.mode === 2 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.windbot && room.id!.startsWith('AI#')));
}).sort((a, b) => {
// if (a.arena === 'athletic' && b.arena === 'athletic') {
// return a.dp - b.dp;
// } else if (a.arena === 'entertain' && b.arena === 'entertain') {
// return a.exp - b.exp;
// }
let [a_priority, b_priority] = [a, b].map((room) => {
if (room.arena === 'athletic') {
return 0;
} else if (room.arena === 'entertain') {
return 1;
} else if (room.id!.startsWith('AI#')) {
return 5;
} else {
return room.options.mode + 2;
this.replay_rooms_show = this.replay_rooms
.filter((room) => {
if (!room.arena && room.server && room.server !== this.currentServer) {
return false;
}
return (
(this.replay_rooms_filter.athletic && room.arena === 'athletic') ||
(this.replay_rooms_filter.entertain && room.arena === 'entertain') ||
(this.replay_rooms_filter.single && room.options.mode === 0 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.match && room.options.mode === 1 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.tag && room.options.mode === 2 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.windbot && room.id!.startsWith('AI#'))
);
})
.sort((a, b) => {
// if (a.arena === 'athletic' && b.arena === 'athletic') {
// return a.dp - b.dp;
// } else if (a.arena === 'entertain' && b.arena === 'entertain') {
// return a.exp - b.exp;
// }
let [a_priority, b_priority] = [a, b].map((room) => {
if (room.arena === 'athletic') {
return 0;
} else if (room.arena === 'entertain') {
return 1;
} else if (room.id!.startsWith('AI#')) {
return 5;
} else {
return room.options.mode + 2;
}
});
return a_priority - b_priority;
});
return a_priority - b_priority;
});
}
getYGOProData(app: App) {
......@@ -288,17 +309,10 @@ export class YGOProComponent implements OnInit, OnDestroy {
async ngOnInit() {
const ygoproData = this.getYGOProData(this.app);
this.servers = ygoproData.servers;
this.selectableServers = this.servers.filter(s => !s.hidden);
this.selectableServers = this.servers.filter((s) => !s.hidden);
this.currentServer = this.selectableServers[0];
// this.reloadCurrentServer();
let locale: string;
if (this.settingsService.getLocale().startsWith('zh')) {
locale = 'zh-CN';
} else {
locale = 'en-US';
}
if (ygoproData.ygopro.lastDeckFormat) {
// console.log(`Deck format pattern: ${ygoproData.ygopro.lastDeckFormat}`)
this.lastDeckFormat = new RegExp(ygoproData.ygopro.lastDeckFormat);
......@@ -312,42 +326,50 @@ export class YGOProComponent implements OnInit, OnDestroy {
modal.on('show.bs.modal', () => {
this.rooms_loading = true;
this.connections = this.servers.filter(server => server.custom).map((server) => {
let url = new URL(server.url!);
url['searchParams'].set('filter', 'waiting');
let connection = new WebSocket(url.toString());
connection.onclose = (event: CloseEvent) => {
this.rooms = this.rooms.filter(room => room.server !== server);
this.refresh_rooms();
};
connection.onerror = (event) => {
console.log('error', server.id, event);
this.rooms = this.rooms.filter(room => room.server !== server);
this.refresh_rooms();
};
connection.onmessage = (event) => {
let message = JSON.parse(event.data);
switch (message.event) {
case 'init':
this.rooms_loading = false;
this.rooms = this.rooms.filter(room => room.server !== server).concat(
message.data.map((room: Room) => Object.assign({ server: server }, room))
);
break;
case 'create':
this.rooms.push(Object.assign({ server: server }, message.data));
break;
case 'update':
Object.assign(this.rooms.find(room => room.server === server && room.id === message.data.id), message.data);
break;
case 'delete':
this.rooms.splice(this.rooms.findIndex(room => room.server === server && room.id === message.data), 1);
}
this.refresh_rooms();
this.ref.detectChanges();
};
return connection;
});
this.connections = this.servers
.filter((server) => server.custom)
.map((server) => {
let url = new URL(server.url!);
url['searchParams'].set('filter', 'waiting');
let connection = new WebSocket(url.toString());
connection.onclose = (event: CloseEvent) => {
this.rooms = this.rooms.filter((room) => room.server !== server);
this.refresh_rooms();
};
connection.onerror = (event) => {
console.log('error', server.id, event);
this.rooms = this.rooms.filter((room) => room.server !== server);
this.refresh_rooms();
};
connection.onmessage = (event) => {
let message = JSON.parse(event.data);
switch (message.event) {
case 'init':
this.rooms_loading = false;
this.rooms = this.rooms
.filter((room) => room.server !== server)
.concat(message.data.map((room: Room) => Object.assign({ server: server }, room)));
break;
case 'create':
this.rooms.push(Object.assign({ server: server }, message.data));
break;
case 'update':
Object.assign(
this.rooms.find((room) => room.server === server && room.id === message.data.id),
message.data
);
break;
case 'delete':
this.rooms.splice(
this.rooms.findIndex((room) => room.server === server && room.id === message.data),
1
);
}
this.refresh_rooms();
this.ref.detectChanges();
};
return connection;
});
});
modal.on('hide.bs.modal', () => {
......@@ -361,42 +383,56 @@ export class YGOProComponent implements OnInit, OnDestroy {
let replay_modal = $('#game-replay-modal');
replay_modal.on('show.bs.modal', () => {
this.replay_connections = this.servers.filter(server => server.replay).map((server) => {
let url = new URL(server.url!);
url['searchParams'].set('filter', 'started');
let connection = new WebSocket(url.toString());
connection.onclose = () => {
this.replay_rooms = this.replay_rooms.filter(room => room.server !== server);
this.refresh_replay_rooms();
};
connection.onmessage = (event) => {
let message = JSON.parse(event.data);
switch (message.event) {
case 'init':
this.replay_rooms = this.replay_rooms.filter(room => room.server !== server).concat(
message.data.map((room: Room) => Object.assign({
server: server,
'private': /^\d+$/.test(room.title!)
}, room))
);
break;
case 'create':
this.replay_rooms.push(Object.assign({
server: server,
'private': /^\d+$/.test(message.data.title!)
}, message.data));
break;
case 'delete':
this.replay_rooms.splice(
this.replay_rooms.findIndex(room => room.server === server && room.id === message.data),
1
);
}
this.refresh_replay_rooms();
this.ref.detectChanges();
};
return connection;
});
this.replay_connections = this.servers
.filter((server) => server.replay)
.map((server) => {
let url = new URL(server.url!);
url['searchParams'].set('filter', 'started');
let connection = new WebSocket(url.toString());
connection.onclose = () => {
this.replay_rooms = this.replay_rooms.filter((room) => room.server !== server);
this.refresh_replay_rooms();
};
connection.onmessage = (event) => {
let message = JSON.parse(event.data);
switch (message.event) {
case 'init':
this.replay_rooms = this.replay_rooms
.filter((room) => room.server !== server)
.concat(
message.data.map((room: Room) =>
Object.assign(
{
server: server,
private: /^\d+$/.test(room.title!),
},
room
)
)
);
break;
case 'create':
this.replay_rooms.push(
Object.assign(
{
server: server,
private: /^\d+$/.test(message.data.title!),
},
message.data
)
);
break;
case 'delete':
this.replay_rooms.splice(
this.replay_rooms.findIndex((room) => room.server === server && room.id === message.data),
1
);
}
this.refresh_replay_rooms();
this.ref.detectChanges();
};
return connection;
});
});
replay_modal.on('hide.bs.modal', () => {
......@@ -408,7 +444,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
let watchDropdownMenu = $('#watch-filter');
watchDropdownMenu.on('change', 'input[type=\'checkbox\']', (event) => {
watchDropdownMenu.on('change', "input[type='checkbox']", (event) => {
// $(event.target).closest("label").toggleClass("active", (<HTMLInputElement> event.target).checked);
this.refresh_replay_rooms();
});
......@@ -429,7 +465,6 @@ export class YGOProComponent implements OnInit, OnDestroy {
});
}
async refresh(init?: boolean) {
this.decks = await this.get_decks();
this.decks_grouped = this.deckGroup();
......@@ -462,16 +497,18 @@ export class YGOProComponent implements OnInit, OnDestroy {
// https://mycard.moe/ygopro/api/user?username=ozxdno
try {
let points = await lastValueFrom(this.http.get<any>('https://mycard.moe/ygopro/api/user', {
params: {
username: this.loginService.user.username
}
}));
let points = await lastValueFrom(
this.http.get<any>('https://mycard.moe/ygopro/api/user', {
params: {
username: this.loginService.user.username,
},
})
);
this.points.emit(points);
} catch (error) {
console.log(error);
}
};
}
async get_decks(): Promise<string[]> {
try {
......@@ -483,13 +520,18 @@ export class YGOProComponent implements OnInit, OnDestroy {
}
deckGroup(): [string, string[]][] {
return Object.entries(_.mapValues(_.groupBy(this.decks, p => path.dirname(p)), g => g.map(p => path.basename(p, '.ydk'))));
return Object.entries(
_.mapValues(
_.groupBy(this.decks, (p) => path.dirname(p)),
(g) => g.map((p) => path.basename(p, '.ydk'))
)
);
}
async get_replays(): Promise<string[]> {
try {
let files: string[] = await fs.readdir(this.app.ygoproReplayPath!);
return files.filter(file => path.extname(file) === '.yrp').map(file => path.basename(file, '.yrp'));
return files.filter((file) => path.extname(file) === '.yrp').map((file) => path.basename(file, '.yrp'));
} catch (error) {
console.error(`Load replay fail: ${error.toString()}`);
return [];
......@@ -509,8 +551,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
if (confirm('确认删除?')) {
try {
await fs.unlink(path.join(this.app.ygoproDeckPath!, deck + '.ydk'));
} catch (error) {
}
} catch (error) {}
return this.refresh();
}
}
......@@ -543,7 +584,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
} catch (e) {
return;
}
};
}
/*
save_system_conf(data: SystemConf) {
......@@ -562,7 +603,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
await this.save_system_conf(system_conf);*/
// return this.start_game(['-h', server.address, '-p', server.port.toString(), '-w', name, '-n', this.loginService.user.username, '-d', this.current_deck, '-j']);
return this.start_game('main', { server, password: name, username: this.loginService.user.username, deck: this.current_deck });
};
}
async edit_deck(deck: string) {
/*let system_conf = await this.load_system_conf();
......@@ -610,101 +651,104 @@ export class YGOProComponent implements OnInit, OnDestroy {
win.restore();
});
try {
lastValueFrom(this.http.get<any>('https://mycard.moe/ygopro/api/history', {
params: {
page: 1,
username: this.loginService.user.username,
type: 0,
page_num: 1
}
}))
.then((d) => {
start_time = d.data[0].start_time;
});
lastValueFrom(
this.http.get<any>('https://mycard.moe/ygopro/api/history', {
params: {
page: 1,
username: this.loginService.user.username,
type: 0,
page_num: 1,
},
})
).then((d) => {
start_time = d.data[0].start_time;
});
} catch (error) {
console.log(error);
}
try {
lastValueFrom(this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', { params: { username: this.loginService.user.username } }))
.then((d2) => {
exp_rank_ex = d2.exp_rank;
arena_rank_ex = d2.arena_rank;
});
lastValueFrom(
this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', { params: { username: this.loginService.user.username } })
).then((d2) => {
exp_rank_ex = d2.exp_rank;
arena_rank_ex = d2.arena_rank;
});
} catch (error) {
console.log(error);
}
});
try {
await lastValueFrom(this.http.get<any>('https://mycard.moe/ygopro/api/history', {
params: {
page: 1,
username: this.loginService.user.username,
// username: "星光pokeboy",
type: 0,
page_num: 1
}
}))
.then((d) => {
data = d.data[0];
data.myname = this.loginService.user.username;
});
await lastValueFrom(
this.http.get<any>('https://mycard.moe/ygopro/api/history', {
params: {
page: 1,
username: this.loginService.user.username,
// username: "星光pokeboy",
type: 0,
page_num: 1,
},
})
).then((d) => {
data = d.data[0];
data.myname = this.loginService.user.username;
});
await lastValueFrom(this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', {
params: {
username: this.loginService.user.username
await lastValueFrom(
this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', {
params: {
username: this.loginService.user.username,
},
})
).then((data2) => {
data.athletic_win = data2.athletic_win;
data.athletic_lose = data2.athletic_lose;
data.entertain_win = data2.entertain_win;
data.entertain_lose = data2.entertain_lose;
data.exp_rank = data2.exp_rank;
data.arena_rank = data2.arena_rank;
data.exp_rank_ex = exp_rank_ex;
data.arena_rank_ex = arena_rank_ex;
if (start_time !== data.start_time) {
this.appsService.showResult('app/end_YGOPro_single.html', data, 202, 222);
}
}))
.then((data2) => {
data.athletic_win = data2.athletic_win;
data.athletic_lose = data2.athletic_lose;
data.entertain_win = data2.entertain_win;
data.entertain_lose = data2.entertain_lose;
data.exp_rank = data2.exp_rank;
data.arena_rank = data2.arena_rank;
data.exp_rank_ex = exp_rank_ex;
data.arena_rank_ex = arena_rank_ex;
if (start_time !== data.start_time) {
this.appsService.showResult('app/end_YGOPro_single.html', data, 202, 222);
}
});
});
} catch (error) {
console.log(error);
}
};
}
create_room(room: Room) {
let options_buffer = Buffer.alloc(6);
// 建主密码 https://docs.google.com/document/d/1rvrCGIONua2KeRaYNjKBLqyG9uybs9ZI-AmzZKNftOI/edit
options_buffer.writeUInt8(((room.private ? 2 : 1) << 4) |
(room.options.duel_rule << 1) |
(room.options.auto_death ? 0x1 : 0), 1);
options_buffer.writeUInt8(((room.private ? 2 : 1) << 4) | (room.options.duel_rule << 1) | (room.options.auto_death ? 0x1 : 0), 1);
options_buffer.writeUInt8(
room.options.rule << 5 |
room.options.mode << 3 |
(room.options.no_check_deck ? 1 << 1 : 0) |
(room.options.no_shuffle_deck ? 1 : 0)
, 2);
(room.options.rule << 5) |
(room.options.mode << 3) |
(room.options.no_check_deck ? 1 << 1 : 0) |
(room.options.no_shuffle_deck ? 1 : 0),
2
);
options_buffer.writeUInt16LE(room.options.start_lp, 3);
options_buffer.writeUInt8(room.options.start_hand << 4 | room.options.draw_count, 5);
options_buffer.writeUInt8((room.options.start_hand << 4) | room.options.draw_count, 5);
let checksum = 0;
for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(i);
}
options_buffer.writeUInt8(checksum & 0xFF, 0);
options_buffer.writeUInt8(checksum & 0xff, 0);
let secret = this.loginService.user.external_id % 65535 + 1;
let secret = (this.loginService.user.external_id % 65535) + 1;
for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
}
let password = options_buffer.toString('base64') + (room.private ? this.host_password :
room.title!.replace(/\s/, String.fromCharCode(0xFEFF)));
let password =
options_buffer.toString('base64') + (room.private ? this.host_password : room.title!.replace(/\s/, String.fromCharCode(0xfeff)));
// let room_id = crypto.createHash('md5').update(password + this.loginService.user.username).digest('base64')
// .slice(0, 10).replace('+', '-').replace('/', '_');
if (room.private) {
new Notification('YGOPro 私密房间已建立', {
body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`
body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`,
});
}
this.join(password, this.currentServer);
......@@ -724,14 +768,13 @@ export class YGOProComponent implements OnInit, OnDestroy {
for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(i);
}
options_buffer.writeUInt8(checksum & 0xFF, 0);
options_buffer.writeUInt8(checksum & 0xff, 0);
let secret = this.loginService.user.external_id % 65535 + 1;
let secret = (this.loginService.user.external_id % 65535) + 1;
for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
}
let name = options_buffer.toString('base64') + room.id;
this.join(name, room.server!);
......@@ -744,14 +787,14 @@ export class YGOProComponent implements OnInit, OnDestroy {
for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(i);
}
options_buffer.writeUInt8(checksum & 0xFF, 0);
options_buffer.writeUInt8(checksum & 0xff, 0);
let secret = this.loginService.user.external_id % 65535 + 1;
let secret = (this.loginService.user.external_id % 65535) + 1;
for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
}
let name = options_buffer.toString('base64') + password.replace(/\s/, String.fromCharCode(0xFEFF));
let name = options_buffer.toString('base64') + password.replace(/\s/, String.fromCharCode(0xfeff));
this.join(name, this.currentServer);
}
......@@ -759,33 +802,39 @@ export class YGOProComponent implements OnInit, OnDestroy {
request_match(arena = 'entertain') {
match_started_at = new Date();
this.matching_arena = matching_arena = arena;
this.matching = matching = this.http.post<any>('https://sapi.moecube.com:444/ygopro/match', null, {
headers: {
Authorization: 'Basic ' + Buffer.from(this.loginService.user.username + ':' + this.loginService.user.external_id).toString('base64')
},
params: {
arena,
locale: this.settingsService.getLocale()
}
})
.subscribe((data) => {
this.join(data['password'], { id: '_match', address: data['address'], port: data['port'] });
}, (error) => {
alert(`匹配失败`);
this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined;
if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined;
}
}, () => {
this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined;
if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined;
this.matching = matching = this.http
.post<any>('https://sapi.moecube.com:444/ygopro/match', null, {
headers: {
Authorization:
'Basic ' + Buffer.from(this.loginService.user.username + ':' + this.loginService.user.external_id).toString('base64'),
},
params: {
arena,
locale: this.locale === 'zh-Hans' ? 'zh-CN' : this.locale,
},
})
.subscribe(
(data) => {
this.join(data['password'], { id: '_match', address: data['address'], port: data['port'] });
},
(error) => {
alert(`匹配失败`);
this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined;
if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined;
}
},
() => {
this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined;
if (this.match_interval) {
clearInterval(this.match_interval);
this.match_interval = undefined;
}
}
});
);
this.refresh_match();
this.match_interval = setInterval(() => {
......
<?xml version="1.0" ?><xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file datatype="plaintext" original="ng2.template" source-language="zh-CN" target-language="en-US">
<body>
<trans-unit datatype="html" id="86738bd5d32223ffbb690a7c71360ddf8e7b1b2e">
<source>竞技匹配</source>
<target>Ranked</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">3</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">13</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">271</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0bf938a69dc640aba46428d1cbbd2fef34c88daa">
<source>娱乐匹配</source>
<target>Unranked</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">14</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">272</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="5026868223e028297430142f8cafdf6dd6fcf004">
<source>自定义游戏</source>
<target>Custom</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">241</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3768b60a7e2625bb1fc2db37eb8c6b8e4bd99101">
<source>单人模式</source>
<target>Vs. Com</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">6</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">33</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">254</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">270</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="44e77a67a8818ad255773958c6b32c6280fb9faa">
<source>观战录像</source>
<target>Replay</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="157bc28ebe7ecf3f455852f64687ea580dfe23dc">
<source>预计时间</source>
<target>Estimated Wait</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="6968a638448b1f36c52a3b306541214acbf9d567">
<source>实际时间</source>
<target>Actual Wait</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="f6f3be110e7043e3cfe71a7bd75b8b3be79bff5d">
<source>取消</source>
<target>Cancel</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">17</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">46</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">238</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">288</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">341</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">81</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\network.component.ts</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="def237147323023c1f5ce0579345da19d4707fdb">
<source>卡组</source>
<target>Deck</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">21</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a842d4536fdee499a55c753c50810254347ced32">
<source>编辑</source>
<target>Edit</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="1e64bb9c96dfc2b9cb03179dd0c9f992e0645e5f">
<source>选择对手</source>
<target>Select Opponent</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">39</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a73f70f2c3126bd103eba9b300efb446ff353187">
<source>随机</source>
<target>Random</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">41</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="5018459a548611c5e7a8bb9f81f8871358089f69">
<source>正在读取游戏列表...</source>
<target>Loading Game List...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="dc0c986dacfc57a3254d4164784a43c8c78cd5ef">
<source>现在没有等待中的游戏,可以自行创建一个房间或者去匹配</source>
<target>There is no opening game available now, you can create a new game yourself, or play ranked game.</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">58</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e35d1bf7c735e8df55a62046cd2d9f820bf5bffd">
<source>游戏标题</source>
<target>Title</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">62</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">104</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">262</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3872a823a98042e4730861ab6f9344239d9deeb6">
<source>玩家</source>
<target>Player</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">63</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">263</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d62a2717a0381d996785271c61177711777ba63c">
<source>决斗模式</source>
<target>Duel mode</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">64</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">131</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d4038dd5d0e9d5139d425fc7bea40e40d965cc5b">
<source>额外选项</source>
<target>Additional Options</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">65</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">140</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">264</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e436a4a0da03320dc61ba35bfab390ab85a23d0c">
<source>单局模式</source>
<target>Single Duel</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">76</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">133</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">273</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2cf71acc936cf244cc5862b28efe461e91cb137d">
<source>比赛模式</source>
<target>Match</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">77</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">134</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">274</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="c2ed31e132c305b995382adce0f95ccdabadaa21">
<source>TAG</source>
<target>TAG</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">78</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">135</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">275</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="aec28732ff145abe493362d5e88bc6bad1019318">
<source><x id="INTERPOLATION"/>LP</source>
<target><x id="INTERPOLATION"/>LP</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">82</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">288</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="cd98842cdc11669a0738a361b22f43c0c673766b">
<source><x id="INTERPOLATION"/>初始</source>
<target><x id="INTERPOLATION"/>Start</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">83</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="9b3b12112efb752aa72374ffa6c8ca42a2d70a3d">
<source>初始起手数量</source>
<target>Draw count when the duel start</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">83</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="cd1d172d64a79d88e6e9b9bb2c622ce94dd5a929">
<source><x id="INTERPOLATION"/>抽卡</source>
<target><x id="INTERPOLATION"/>Draw</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">291</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="6a3e97dfd1992e61e97d2a2be2b2ddf13f318ac9">
<source>每回合抽卡数量</source>
<target>Draw count of each turn</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">84</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">291</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="785cc65c8db99887484b3b1067c45b32810c7c2a">
<source>旧规则</source>
<target>Old rules</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">85</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">165</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">292</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="350191538e68a92c731e26748aeeaefd6057999f">
<source>上个版本的大师规则</source>
<target>Previous Master Rule</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">85</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">292</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="b5be173f96718dfa737f1da31d9ffab5b803561e">
<source>不检查</source>
<target>Don't check</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0b515681fb332bd8b8b2546e947c1e2dd17eee1d">
<source>不检查卡组是否合规</source>
<target>Don't check if the deck is legal</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="517c8b6e5361bc32d7458a1e8b2bdbf09abb6f01">
<source>不洗卡</source>
<target>Don't shuffle</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">87</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">294</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="c8f90957413ee947f95851258a906b2507c5ec2a">
<source>任何时候都不洗切卡组</source>
<target>Don't shuffle the deck at any time</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">87</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">294</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="739d660c23ece9c643e11f84a5a9b989bc1bff92">
<source>在这输入你朋友的私密房间密码就可以进去了哦!</source>
<target>Enter the password of the private room...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="52cb37d4d51b8e9926dc9f8b3ebd87f7f9c28e0d">
<source>加入私密房间</source>
<target>Join private room</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">95</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="19923836b1ae79614782426a7a001d8ccfa27b5c">
<source>创建房间</source>
<target>Create</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">178</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="dbbe20b6bcb3ec318694afcfaa51c3cc8c4f6c14">
<source>最多 12 个字</source>
<target>Up to 12 characters</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">106</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="b086b473216334b81d0ca5f4086a8c500c6adfae">
<source>房间密码</source>
<target>Room password</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">110</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="5eadb60473a54773298ee679a4ce6a19d9c2f31c">
<source>复制</source>
<target>Copy</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">114</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\network.component.ts</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="681f5f7d8ca9f49149f4ddbcc3809e847da9abc2">
<source>房间密码已复制到剪贴板</source>
<target>Room password copied</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">113</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2ce9a108884cb5f7b73d734c07839a8a7c60c223">
<source>把这个分享给你的朋友</source>
<target>Share this to your friend</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="4b911deaa4defd0803635012281f3dd1112aabd1">
<source>卡片允许</source>
<target>Rule</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="93d3b6bb4f3a66efd8c49f9063f6c8d6a9e959bf">
<source>OCG</source>
<target>OCG</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">124</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="150cb34526cf737163beb63ab76e4809ac1367dd">
<source>TCG</source>
<target>TCG</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">125</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="be6d109c359b1d11b261280915e6b1706ca3ed9b">
<source>OCG & TCG</source>
<target>TCG/OCG</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">126</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2a3f48f9ea5e6aae92e249ac2b279dbc07a6127d">
<source>专有卡禁止</source>
<target>Unspecified</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">127</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="01cfbee3f1d69f5adae299b7b8c8d75034aef53b">
<source>初始 LP</source>
<target>Starting LP</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0d72e50857f1d2504e08f7886d4c9d35a46e3ed9">
<source>初始手牌数</source>
<target>Starting Hand</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">148</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="88cc5676c5322fd55c1df94ab487359100e6f9dd">
<source>每回合抽卡</source>
<target>Draw / Turn</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="7c29758dc53e9a5d62665d9fa4fadb28425b801f">
<source>私密房间</source>
<target>Private room</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">161</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="6e7470ddf4c35f6fab39b6ebeadb1780701a5469">
<source>不检查卡组</source>
<target>Don't check</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="4f104c680937cb724b069f62ab1ff60651c5bb06">
<source>不洗切卡组</source>
<target>Don't shuffle</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="84276d07f694b80bd5ea94d28283b6530248d02e">
<source>观战</source>
<target>Live</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">207</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d516b78557483a84288359494abde950d3887518">
<source>本地录像</source>
<target>Local</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">213</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="7047116f06b2fcb5e7f8e8589d1ef31628aff0fa">
<source>游戏模式</source>
<target>Game Mode</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">230</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="968e4d8a0f7b5eaaa1d588a738abdaa0ec389d16">
<source>匹配</source>
<target>Matchmaking</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">232</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="def75ea9acd3da49e6147241d1be818f8a7ce80b">
<source>
<x ctype="x-input" id="TAG_INPUT"/>
竞技匹配
</source>
<target>
<x ctype="x-input" id="TAG_INPUT"/>
Ranked
</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">233</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="f17779dfdda35219eee16c358b3cbe14ff789e3c">
<source>
<x ctype="x-input" id="TAG_INPUT"/>
娱乐匹配
</source>
<target>
<x ctype="x-input" id="TAG_INPUT"/>
Unranked
</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">237</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="25cdef61312547afc246b3429d94771c5ee2fa3b">
<source>
<x ctype="x-input" id="TAG_INPUT"/>
单局模式
</source>
<target>
<x ctype="x-input" id="TAG_INPUT"/>
Single mode
</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">242</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="18af41ff38726d95ec017e21f8da22c3a08ccb3a">
<source>
<x ctype="x-input" id="TAG_INPUT"/>
比赛模式
</source>
<target>
<x ctype="x-input" id="TAG_INPUT"/>
Match mode
</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">246</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="9fcb9c4a68f2af185ebc6717184d06939e6902fe">
<source>
<x ctype="x-input" id="TAG_INPUT"/>
TAG
</source>
<target>
<x ctype="x-input" id="TAG_INPUT"/>
TAG
</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2592afa29068412ddab43d6961c75827f8ca0d1f">
<source>
<x ctype="x-input" id="TAG_INPUT"/>
单人模式
</source>
<target>
<x ctype="x-input" id="TAG_INPUT"/>
Bot mode
</target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">255</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="eb9b7293445a26df2b986acef9687b87427eb81a">
<source><x id="INTERPOLATION"/> 的私密房间</source>
<target>Private Room of <x id="INTERPOLATION"/> </target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">278</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="5136f852d874c46bf808987470980a0f2560487e">
<source><x id="INTERPOLATION"/><x id="INTERPOLATION_1"/> 的决斗</source>
<target><x id="INTERPOLATION"/> Vs. <x id="INTERPOLATION_1"/></target>
<context-group purpose="location">
<context context-type="sourcefile">app\ygopro.component.ts</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="4fbedd55acdf8789c0d5bb10792a2775540c990b">
<source><x id="INTERPOLATION"/> 购买</source>
<target><x id="INTERPOLATION"/> Buy</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0415ea4132361a518cfb8b81e058f4238b85f071">
<source>安装试玩版</source>
<target>Install Trial Version</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a8cae935472a05e1c8c9be436bb7b1bdea96a54a">
<source>安装</source>
<target>Install</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">19</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">173</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">239</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e6194d8a9c8da57b667847cd80f1da563f2c2b1e">
<source>导入</source>
<target>Import</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">20</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="8bb533b37ee18bf8d09df19b4d7234b38f134909">
<source>正在下载</source>
<target>Downloading...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2fe99d94b20d6f8aba7814d8657037ec9d69d36c">
<source>正在安装...</source>
<target>Installing...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="bea72fe35b7b9933e126b6ee3a6828c307ccc3d4">
<source>正在卸载...</source>
<target>UnInstalling...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e5ee7e692c816893b6fd2f9375e6d8303cd794cd">
<source>等待安装...</source>
<target>Pending...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">29</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3d632d85701edba578ee10c6802c5fe49bca1d62">
<source>正在更新...</source>
<target>Updating</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">30</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d3852e0147360b29d0d6076e95dd1ad0098a60db">
<source>运行</source>
<target>Start</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="67adbad4f646bb8e1c440522bafea8fe5f7e6bfd">
<source>设置</source>
<target>Settings</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">43</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">38</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="409ab83692bb4c157cddafe70de9e95531be796e">
<source>排位成绩</source>
<target>Rank Result</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">73</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="eb22ba5ed7019f8799bc645c508108136ad54096">
<source>竞技排名</source>
<target>D.P Rank</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">77</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="78da696d0961bc2c3f10d9e6f5998161ba17b75f">
<source>娱乐排名</source>
<target>EXP Rank</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">79</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="c3e6d747b93851670dd03bc38346f8f7f6fee421">
<source>竞技胜率</source>
<target>Win Rate</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">83</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="ed1a1a97ab1b37a358ca132a5c87040a9af13693">
<source>经验</source>
<target>EXP</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">85</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0ce6333a9b6c85ccd57ecdbee84ef7f6f3f51ef4">
<source>胜场</source>
<target>Win</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">91</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a89a5c5567bbe1de398b978749b9a1bf6f1281bf">
<source>负场</source>
<target>Lose</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">95</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">97</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="41a0424d676209939f79f70c8ef8aa8a143d3451">
<source>平局</source>
<target>Draw</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">103</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3f4d682cd4fc7579e9ea6bd1bddec84dbc35fd50">
<source>总场</source>
<target>Total</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">107</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">109</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="f5f5d4874301c4b42cdbfab010c953631abbcec9">
<source>更多资料</source>
<target>More Info</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">114</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d894d6d2877894a61841bb27d0ed7a85419b58aa">
<source>开发</source>
<target>Developer</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">126</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="502c98fe1d2359937a3be80448a1343c43eb0e82">
<source>发行日期</source>
<target>Release Date</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="c221cbf6933c44b3c99740ed3f8715db7ce9791f">
<source>更新日期</source>
<target>Update Date</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="63346eb53d54138db02c1713ae58f73bb1b8786f">
<source>新闻</source>
<target>News</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">144</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="b1c134df688af90e436e49f6d3e9f6960f9497c6">
<source>了解更多</source>
<target>More Info</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">149</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3ebbe3f1c691ec3184ac8c7a5f360706501e6b50">
<source>名称</source>
<target>Name</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">161</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d58ff4f339ad18d82b08fb0615ba8c1cf373a4a2">
<source>操作</source>
<target>Action</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">162</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e090f6d9d8129a7b8b92387f05f37eb4b44c0b4e">
<source>卸载</source>
<target>Uninstall</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">170</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">190</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="8d0792a89fc399aafb40cc1228cb8c04a2056883">
<source>本地文件</source>
<target>Local Files</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">186</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="628c76783ac32e6c8b2ea9134397b8cb82a82cd6">
<source>浏览本地文件</source>
<target>Browse</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">188</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="6d582ed48c57c91fc7cf10f36f3869cd33808d1d">
<source>校验完整性</source>
<target>Verify</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">189</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="4809edca33b1a07d7d6e8905287d3825e676f2c8">
<source>安装 <x id="INTERPOLATION"/></source>
<target>Install <x id="INTERPOLATION"/></target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">204</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="f8e60167c7a0871ccf40ed2a0750311411dfd665">
<source>即将开始安装 <x id="INTERPOLATION"/></source>
<target>Preparing Installation <x id="INTERPOLATION"/></target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">210</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="63a6c9b023e9e9f8ddfba70b0e24931008fa2510">
<source>安装位置</source>
<target>Path</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0b96c54bf810c6deb2c32253bf16b86d3c90da94">
<source>快捷方式</source>
<target>Shortcuts</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">217</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="9a629bd93b2e21100857f30721b7ac44ce0a2e23">
<source>创建启动菜单快捷方式</source>
<target>Create Start Menu shortcut</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">220</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="8aa0a41ee6809b972d3904d96607ba5e6dc48fd9">
<source>创建 LaunchPad 快捷方式</source>
<target>Create Launchpad Shortcut</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">221</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="da32e99069864644f0419f67858d93815e029b02">
<source>创建开始菜单快捷方式</source>
<target>Create Start Menu Shortcut</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">222</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d8a2d9a9f8854ad118381e6e30a41dc1959a4f0b">
<source>创建桌面快捷方式</source>
<target>Create Desktop Shortcut</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">226</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2af1068491573803bc4756c4f94a689155370d9c">
<source>扩展内容</source>
<target>Expansion</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">228</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">278</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="2ba33dd61b1ac70666322680f248e5336b3ee69a">
<source>依赖:</source>
<target>Dependencies</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a15b7787a037bb540cc5d29cd8f955f836359a32">
<source>导入 <x id="INTERPOLATION"/></source>
<target>Import <x id="INTERPOLATION"/></target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="61b454cd8b58f72dcb818f8b3e71d636255d21a6">
<source>选择主程序 <x id="INTERPOLATION"/></source>
<target>Select program <x id="INTERPOLATION"/></target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">255</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e1dc3b38b5b1e156d04cde23cf30209d977faa3f">
<source>导入到</source>
<target>Import to</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">261</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="446a2e3833dd7f4122a0a3f2046e7b062b54d575">
<source>购买 <x id="INTERPOLATION"/></source>
<target>Buy <x id="INTERPOLATION"/></target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">300</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">353</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="6b296cbd1145fbf948c58a7afa5c4d200cdfd98b">
<source>购买</source>
<target>Buy</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">342</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="e81bc577e08b01e7ebe9351760c0c845b3bb2fb4">
<source>返回</source>
<target>Return</target>
<context-group purpose="location">
<context context-type="sourcefile">app\app-detail.component.ts</context>
<context context-type="linenumber">365</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="ef65da47763167a418e811d9007c53b896b50479">
<source>最小化</source>
<target>Minimize</target>
<context-group purpose="location">
<context context-type="sourcefile">app\candy.component.ts</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a4148531ad465c2e931b7e754db36872c37d81e9">
<source>取消最小化</source>
<target>Unminimize</target>
<context-group purpose="location">
<context context-type="sourcefile">app\candy.component.ts</context>
<context context-type="linenumber">6</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3b5d294cb083dfe7adeef5030777e93a14b3ba25">
<source>还原</source>
<target>Restore</target>
<context-group purpose="location">
<context context-type="sourcefile">app\candy.component.ts</context>
<context context-type="linenumber">7</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="5d721f211851b0df47f1b25a5cc0b66ba0c1d2ec">
<source>最大化</source>
<target>Maximize</target>
<context-group purpose="location">
<context context-type="sourcefile">app\candy.component.ts</context>
<context context-type="linenumber">8</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">43</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="18317f699a18335372324838e993a15aeb114d6d">
<source>搜索游戏</source>
<target>Search...</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">6</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="1761e51e36b01ae1e0012914bd58aa2a741d0401">
<source>已安装</source>
<target>Installed</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="69f3fab778e92fcec3a8c38d53d771a36e6d5230">
<source>推荐</source>
<target>Recommended</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">36</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="fc570ecca13755cb4a92e7513fbd55c2d412f23c">
<source>迷之物体</source>
<target>Something</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="0873cd6df2d1f1016e02526aa9ba32415c1a11d8">
<source>东方 Project</source>
<target>Touhou Project</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">54</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="785db32107cc0b47564b05381a1d782021d77c67">
<source>东方旧作</source>
<target>Touhou old series</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">63</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="817376261844eb7eb0c035ed0e3fce744a96b6d9">
<source>已安装的运行库</source>
<target>Installed Runtime Library</target>
<context-group purpose="location">
<context context-type="sourcefile">app\lobby.component.ts</context>
<context context-type="linenumber">72</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="ae5dccdf399fb229fb9f0153a7ec5c28a4579ca1">
<source>登录</source>
<target>Sign In</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="fbfb7c4354663a67786aa5aee748d1f38b8fe71c">
<source>游戏</source>
<target>Library</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">15</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="c4fc2b3584e7581cddb08bb1ebfa41e601195d5b">
<source>社区</source>
<target>Community</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">18</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a8bb0580a537d7a47ff0a2df6907b5f6acee50c6">
<source>更新出错,点击重试</source>
<target>Download update failed, click to retry</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">29</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="a75ff3d3253e8d65f703cf2a9384fc09532a73d5">
<source>正在检查更新</source>
<target>Checking for updates</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">30</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="21d13c0058fb50264b8e8a867dff4133861e5260">
<source>正在下载更新</source>
<target>Downloading updates</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="abd0524ada522c2ca41fa6ac06bbc6a887828d70">
<source>下载更新完成,点击安装</source>
<target>Update Downloaded, click to install</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">32</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="d2f3938b0b672d936a9b157211b6212d7f015c21">
<source>切换用户</source>
<target>Logout</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">37</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="065034046fe7863f3fe1a1f68e5767cf58bed3c1">
<source>关闭</source>
<target>Close</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="9d9335d175b40b85f2b98610af517a8b7509c089">
<source>MyCard 设置</source>
<target>MyCard Settings</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="b22ce2179c700e2499e1d402fb1d3f4392c7f6af">
<source>语言</source>
<target>Language</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">70</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="af09a0e18f4200fdb729133ddcd5bb43d52439aa">
<source>确定</source>
<target>OK</target>
<context-group purpose="location">
<context context-type="sourcefile">app\mycard.component.ts</context>
<context context-type="linenumber">82</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="3d6cad40e26f99e39bc6f5925a890ba83b67ce5b">
<source>联机</source>
<target>Network</target>
<context-group purpose="location">
<context context-type="sourcefile">app\network.component.ts</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit datatype="html" id="95d5e106e679433bec012420b1ab9334c294bc7e">
<source>选择服务器</source>
<target>Select Server</target>
<context-group purpose="location">
<context context-type="sourcefile">app\network.component.ts</context>
<context context-type="linenumber">14</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="zh-Hans" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="5500653310239843958" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{currentApp.price.cny | currency:&apos;CNY&apos;:true}}"/> 购买</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">10,11</context>
</context-group>
</trans-unit>
<trans-unit id="5915326978143211953" datatype="html">
<source>安装试玩版</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
</trans-unit>
<trans-unit id="4707791770500562346" datatype="html">
<source>安装</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">20</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">172</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">236</context>
</context-group>
</trans-unit>
<trans-unit id="415845270675092715" datatype="html">
<source>导入</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">21</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">280</context>
</context-group>
</trans-unit>
<trans-unit id="9010313379313785418" datatype="html">
<source>正在下载</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">27</context>
</context-group>
</trans-unit>
<trans-unit id="6082286595151641149" datatype="html">
<source>正在安装...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="7032677452406728492" datatype="html">
<source>正在卸载...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">29</context>
</context-group>
</trans-unit>
<trans-unit id="8749448380790856217" datatype="html">
<source>等待安装...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">30</context>
</context-group>
</trans-unit>
<trans-unit id="7891802793992098764" datatype="html">
<source>正在更新...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="389316235252336921" datatype="html">
<source>运行</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">41</context>
</context-group>
</trans-unit>
<trans-unit id="4347609548478415645" datatype="html">
<source>运行 (Roll)</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="1133636729557061267" datatype="html">
<source>设置</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">46</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="474096894300581680" datatype="html">
<source>排位成绩</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="4179652713647550108" datatype="html">
<source>D.P</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">80</context>
</context-group>
</trans-unit>
<trans-unit id="5279177279973241585" datatype="html">
<source>经验</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">82</context>
</context-group>
</trans-unit>
<trans-unit id="2347877564583563151" datatype="html">
<source>竞技胜率</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">86</context>
</context-group>
</trans-unit>
<trans-unit id="7658728715964102175" datatype="html">
<source>竞技排名</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">88</context>
</context-group>
</trans-unit>
<trans-unit id="35623199025907665" datatype="html">
<source>竞技胜场</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">92</context>
</context-group>
</trans-unit>
<trans-unit id="8092419159103709317" datatype="html">
<source>竞技总场</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">94</context>
</context-group>
</trans-unit>
<trans-unit id="1840105707810285770" datatype="html">
<source>竞技负场</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="7732285945658535910" datatype="html">
<source>娱乐排名</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">100</context>
</context-group>
</trans-unit>
<trans-unit id="7606011614433650186" datatype="html">
<source>竞技平局</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">104</context>
</context-group>
</trans-unit>
<trans-unit id="8184169664057644188" datatype="html">
<source>娱乐总场</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">106</context>
</context-group>
</trans-unit>
<trans-unit id="3375776879265544689" datatype="html">
<source>更多资料</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">111</context>
</context-group>
</trans-unit>
<trans-unit id="165615166529567628" datatype="html">
<source>开发</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="1112540783739452813" datatype="html">
<source>发行日期</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">131</context>
</context-group>
</trans-unit>
<trans-unit id="4816555401849304005" datatype="html">
<source>更新日期</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">134</context>
</context-group>
</trans-unit>
<trans-unit id="452832726000226757" datatype="html">
<source>新闻</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">141</context>
</context-group>
</trans-unit>
<trans-unit id="797303627345064587" datatype="html">
<source>了解更多</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">146</context>
</context-group>
</trans-unit>
<trans-unit id="5026774864970786200" datatype="html">
<source>扩展/运行库</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="6673753548733826795" datatype="html">
<source>名称</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="2261171107170127222" datatype="html">
<source>操作</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="1226257559652274916" datatype="html">
<source>卸载</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">169</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">189</context>
</context-group>
</trans-unit>
<trans-unit id="4348888876274124404" datatype="html">
<source>本地文件</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">185</context>
</context-group>
</trans-unit>
<trans-unit id="2248880859747378879" datatype="html">
<source>浏览本地文件</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">187</context>
</context-group>
</trans-unit>
<trans-unit id="9049670660333429404" datatype="html">
<source>校验完整性</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">188</context>
</context-group>
</trans-unit>
<trans-unit id="5445249716349822317" datatype="html">
<source>安装 <x id="INTERPOLATION" equiv-text="{{currentApp.name}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">203,204</context>
</context-group>
</trans-unit>
<trans-unit id="6818269250850850074" datatype="html">
<source>即将开始安装 <x id="INTERPOLATION" equiv-text="{{currentApp.name}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">207,208</context>
</context-group>
</trans-unit>
<trans-unit id="4592055951111798669" datatype="html">
<source>安装位置</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">208</context>
</context-group>
</trans-unit>
<trans-unit id="8178413225330419814" datatype="html">
<source>快捷方式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">214</context>
</context-group>
</trans-unit>
<trans-unit id="4186225594692368566" datatype="html">
<source>创建启动菜单快捷方式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">217</context>
</context-group>
</trans-unit>
<trans-unit id="5250566735006329348" datatype="html">
<source>创建 LaunchPad 快捷方式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">218</context>
</context-group>
</trans-unit>
<trans-unit id="3480330720511859635" datatype="html">
<source>创建开始菜单快捷方式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">219</context>
</context-group>
</trans-unit>
<trans-unit id="4328366364866150239" datatype="html">
<source>创建桌面快捷方式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">223</context>
</context-group>
</trans-unit>
<trans-unit id="6694116611099837910" datatype="html">
<source>扩展内容</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">225</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">269</context>
</context-group>
</trans-unit>
<trans-unit id="4429469421598844284" datatype="html">
<source>依赖:</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">230</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">274</context>
</context-group>
</trans-unit>
<trans-unit id="5601254587589034652" datatype="html">
<source>取消</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">235</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">279</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">330</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">89</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/network/network.component.html</context>
<context context-type="linenumber">11</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">17</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">55</context>
</context-group>
</trans-unit>
<trans-unit id="7879852782132394490" datatype="html">
<source>导入 <x id="INTERPOLATION" equiv-text="{{currentApp.name}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">246,247</context>
</context-group>
</trans-unit>
<trans-unit id="8518568536212574659" datatype="html">
<source>选择主程序 <x id="INTERPOLATION" equiv-text="{{currentApp.actions.get(&apos;main&apos;)!.execute}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">250,251</context>
</context-group>
</trans-unit>
<trans-unit id="2964776624685546926" datatype="html">
<source>导入到</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">252</context>
</context-group>
</trans-unit>
<trans-unit id="8419283066760619767" datatype="html">
<source>购买 <x id="INTERPOLATION" equiv-text="{{currentApp.name}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">291,292</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">342,343</context>
</context-group>
</trans-unit>
<trans-unit id="1768692559946731828" datatype="html">
<source>返回</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app-detail/app-detail.component.html</context>
<context context-type="linenumber">354</context>
</context-group>
</trans-unit>
<trans-unit id="1159850433378968616" datatype="html">
<source>最小化</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/candy/candy.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="4111029749754498927" datatype="html">
<source>取消最小化</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/candy/candy.component.html</context>
<context context-type="linenumber">6</context>
</context-group>
</trans-unit>
<trans-unit id="5564095526825103523" datatype="html">
<source>还原</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/candy/candy.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">52</context>
</context-group>
</trans-unit>
<trans-unit id="3892121313984875571" datatype="html">
<source>最大化</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/candy/candy.component.html</context>
<context context-type="linenumber">8</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="7191198831276862997" datatype="html">
<source>已安装</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
<trans-unit id="4739456952454331786" datatype="html">
<source>推荐</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="645420684477908071" datatype="html">
<source>YGOPro 各发行版</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="2012873046431930080" datatype="html">
<source>迷之物体</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">60</context>
</context-group>
</trans-unit>
<trans-unit id="3748550821511989776" datatype="html">
<source>东方 Project</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">70</context>
</context-group>
</trans-unit>
<trans-unit id="4558165836904030366" datatype="html">
<source>东方旧作</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">80</context>
</context-group>
</trans-unit>
<trans-unit id="9106868849521120254" datatype="html">
<source>已安装的运行库</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/lobby/lobby.component.html</context>
<context context-type="linenumber">90</context>
</context-group>
</trans-unit>
<trans-unit id="1496302481389750951" datatype="html">
<source>登录</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="6194392025996720530" datatype="html">
<source>游戏</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">15</context>
</context-group>
</trans-unit>
<trans-unit id="2399670672306168346" datatype="html">
<source>社区</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">18</context>
</context-group>
</trans-unit>
<trans-unit id="5726670458498387856" datatype="html">
<source>更新出错,点击重试</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">30</context>
</context-group>
</trans-unit>
<trans-unit id="7429301926080732854" datatype="html">
<source>正在检查更新</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">32</context>
</context-group>
</trans-unit>
<trans-unit id="1931653475765544724" datatype="html">
<source>正在下载更新</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">34</context>
</context-group>
</trans-unit>
<trans-unit id="6738142189836052467" datatype="html">
<source>下载更新完成,点击安装</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">36</context>
</context-group>
</trans-unit>
<trans-unit id="3060981724810040333" datatype="html">
<source>切换用户</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">42</context>
</context-group>
</trans-unit>
<trans-unit id="5300391254526469340" datatype="html">
<source>关闭</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">53</context>
</context-group>
</trans-unit>
<trans-unit id="5518426095406444021" datatype="html">
<source>MyCard 设置</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">71</context>
</context-group>
</trans-unit>
<trans-unit id="720166362468454188" datatype="html">
<source>语言</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">78</context>
</context-group>
</trans-unit>
<trans-unit id="4084906370576746110" datatype="html">
<source>确定</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/mycard/mycard.component.html</context>
<context context-type="linenumber">90</context>
</context-group>
</trans-unit>
<trans-unit id="5364594497612958612" datatype="html">
<source>联机</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/network/network.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
</trans-unit>
<trans-unit id="7733598902834788488" datatype="html">
<source>复制</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/network/network.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">129</context>
</context-group>
</trans-unit>
<trans-unit id="6164294463085760882" datatype="html">
<source>选择服务器</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/network/network.component.html</context>
<context context-type="linenumber">8</context>
</context-group>
</trans-unit>
<trans-unit id="4824324759710622444" datatype="html">
<source>竞技匹配</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">3</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">13</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">298</context>
</context-group>
</trans-unit>
<trans-unit id="3425812751501118970" datatype="html">
<source>娱乐匹配</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">14</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="2700828343529797979" datatype="html">
<source>自定义游戏</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">268</context>
</context-group>
</trans-unit>
<trans-unit id="3680979527155857706" datatype="html">
<source>单人模式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">6</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">44</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">281</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">297</context>
</context-group>
</trans-unit>
<trans-unit id="8780547140091220026" datatype="html">
<source>观战录像</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="1076873283561004736" datatype="html">
<source>预计时间</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="884552612554190387" datatype="html">
<source>实际时间</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">16</context>
</context-group>
</trans-unit>
<trans-unit id="5422030028584005658" datatype="html">
<source>卡组</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">28</context>
</context-group>
</trans-unit>
<trans-unit id="6441654809894181260" datatype="html">
<source>编辑</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">35</context>
</context-group>
</trans-unit>
<trans-unit id="6234071137144554591" datatype="html">
<source>选择对手</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">48</context>
</context-group>
</trans-unit>
<trans-unit id="4063633656871691707" datatype="html">
<source>随机</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">50</context>
</context-group>
</trans-unit>
<trans-unit id="3445215350395008585" datatype="html">
<source>正在读取游戏列表...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="4388468936178754358" datatype="html">
<source>现在没有等待中的游戏,可以自行创建一个房间或者去匹配</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">67</context>
</context-group>
</trans-unit>
<trans-unit id="2842531300820484520" datatype="html">
<source>游戏标题</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">71</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">119</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="5252295988449572424" datatype="html">
<source>玩家</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">72</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">290</context>
</context-group>
</trans-unit>
<trans-unit id="2574754555966894333" datatype="html">
<source>决斗模式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">73</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">148</context>
</context-group>
</trans-unit>
<trans-unit id="7087960680757699980" datatype="html">
<source>额外选项</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">74</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">167</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">291</context>
</context-group>
</trans-unit>
<trans-unit id="3256394240336086270" datatype="html">
<source>单局模式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">85</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">150</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">300</context>
</context-group>
</trans-unit>
<trans-unit id="634666435866131392" datatype="html">
<source>比赛模式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">86</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">151</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">301</context>
</context-group>
</trans-unit>
<trans-unit id="4185487056336991651" datatype="html">
<source>TAG</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">87</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">152</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">302</context>
</context-group>
</trans-unit>
<trans-unit id="1054010530477249383" datatype="html">
<source>允许OCG独有卡,不允许TCG独有卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">90</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">314</context>
</context-group>
</trans-unit>
<trans-unit id="6948439061215722524" datatype="html">
<source>OCG</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">90</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">139</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">314</context>
</context-group>
</trans-unit>
<trans-unit id="5456577403223298861" datatype="html">
<source>允许TCG独有卡,不允许OCG独有卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">315</context>
</context-group>
</trans-unit>
<trans-unit id="7425844741612948140" datatype="html">
<source>TCG</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">91</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">140</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">315</context>
</context-group>
</trans-unit>
<trans-unit id="1529798327406657672" datatype="html">
<source>只允许简体中文版已经发售的卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">92</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">316</context>
</context-group>
</trans-unit>
<trans-unit id="2267818139701047712" datatype="html">
<source>简中</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">92</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">316</context>
</context-group>
</trans-unit>
<trans-unit id="7262289931505309512" datatype="html">
<source>只允许自制卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">93</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">317</context>
</context-group>
</trans-unit>
<trans-unit id="5021480460351637552" datatype="html">
<source>自制卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">93</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">317</context>
</context-group>
</trans-unit>
<trans-unit id="8550618767979849346" datatype="html">
<source>不允许OCG或TCG独有卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">94</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">318</context>
</context-group>
</trans-unit>
<trans-unit id="5599262704116943724" datatype="html">
<source>专有卡禁止</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">94</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">143</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">318</context>
</context-group>
</trans-unit>
<trans-unit id="3894448366765893524" datatype="html">
<source>可以任意使用OCG或TCG卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">95</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">319</context>
</context-group>
</trans-unit>
<trans-unit id="6883268087772924122" datatype="html">
<source>所有卡片</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">95</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">144</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">319</context>
</context-group>
</trans-unit>
<trans-unit id="779667232609922270" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{room.options.start_lp}}"/>LP</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">96,97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">320,321</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">321,322</context>
</context-group>
</trans-unit>
<trans-unit id="3965007982822610601" datatype="html">
<source>初始起手数量</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">97</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">322</context>
</context-group>
</trans-unit>
<trans-unit id="3103543984539091718" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{room.options.start_hand}}"/>初始</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">97,98</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">322,323</context>
</context-group>
</trans-unit>
<trans-unit id="1369317458348130098" datatype="html">
<source>每回合抽卡数量</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">98</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">323</context>
</context-group>
</trans-unit>
<trans-unit id="6481542039857455479" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{room.options.draw_count}}"/>抽卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">98,99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">323,324</context>
</context-group>
</trans-unit>
<trans-unit id="8203916284365140769" datatype="html">
<source>上个版本的大师规则</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">324</context>
</context-group>
</trans-unit>
<trans-unit id="1847337342855187661" datatype="html">
<source>大师规则<x id="INTERPOLATION" equiv-text="{{room.options.duel_rule}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">99,100</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">324,325</context>
</context-group>
</trans-unit>
<trans-unit id="2675473716500688222" datatype="html">
<source>不检查卡组是否合规</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">100</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">325</context>
</context-group>
</trans-unit>
<trans-unit id="7817031351520622106" datatype="html">
<source>不检查</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">100</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">325</context>
</context-group>
</trans-unit>
<trans-unit id="8117967243387781433" datatype="html">
<source>任何时候都不洗切卡组</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">326</context>
</context-group>
</trans-unit>
<trans-unit id="7164009911029865975" datatype="html">
<source>不洗卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">101</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">326</context>
</context-group>
</trans-unit>
<trans-unit id="8987520460184616674" datatype="html">
<source>40分钟自动死三</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">102</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">327</context>
</context-group>
</trans-unit>
<trans-unit id="8273123049640290198" datatype="html">
<source>自动加时赛</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">102</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">327</context>
</context-group>
</trans-unit>
<trans-unit id="3213499068433545806" datatype="html">
<source>在这输入你朋友的私密房间密码就可以进去了哦!</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">109</context>
</context-group>
</trans-unit>
<trans-unit id="6242882390815461076" datatype="html">
<source>加入私密房间</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">110</context>
</context-group>
</trans-unit>
<trans-unit id="3485470170085225352" datatype="html">
<source>创建房间</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">116</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">209</context>
</context-group>
</trans-unit>
<trans-unit id="8344119123755884106" datatype="html">
<source>最多 12 个字</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">121</context>
</context-group>
</trans-unit>
<trans-unit id="2817309808333695922" datatype="html">
<source>房间密码</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">125</context>
</context-group>
</trans-unit>
<trans-unit id="4914023372400217583" datatype="html">
<source>房间密码已复制到剪贴板</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
<trans-unit id="2854060792150666632" datatype="html">
<source>把这个分享给你的朋友</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">132</context>
</context-group>
</trans-unit>
<trans-unit id="8501515438273095577" datatype="html">
<source>卡片允许</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="1520664020879989316" datatype="html">
<source>简体中文</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">141</context>
</context-group>
</trans-unit>
<trans-unit id="6124004585691027507" datatype="html">
<source>决斗规则</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">156</context>
</context-group>
</trans-unit>
<trans-unit id="5441993665700464258" datatype="html">
<source>大师规则1</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">158</context>
</context-group>
</trans-unit>
<trans-unit id="490449615328529184" datatype="html">
<source>大师规则2</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">159</context>
</context-group>
</trans-unit>
<trans-unit id="3624883058235374614" datatype="html">
<source>大师规则3</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="5534170980237645324" datatype="html">
<source>新大师规则</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">161</context>
</context-group>
</trans-unit>
<trans-unit id="818290259604468436" datatype="html">
<source>大师规则2020</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">162</context>
</context-group>
</trans-unit>
<trans-unit id="6535415149987755770" datatype="html">
<source>初始 LP</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">169</context>
</context-group>
</trans-unit>
<trans-unit id="6688677629216699320" datatype="html">
<source>初始手牌数</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">175</context>
</context-group>
</trans-unit>
<trans-unit id="1114928212757744379" datatype="html">
<source>每回合抽卡</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="364093220592294913" datatype="html">
<source>私密房间</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">188</context>
</context-group>
</trans-unit>
<trans-unit id="2877278598832955537" datatype="html">
<source>不检查卡组</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">196</context>
</context-group>
</trans-unit>
<trans-unit id="2354766923141567251" datatype="html">
<source>不洗切卡组</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">200</context>
</context-group>
</trans-unit>
<trans-unit id="1572245821199187696" datatype="html">
<source>40分自动加时赛</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">204</context>
</context-group>
</trans-unit>
<trans-unit id="9034101245367763141" datatype="html">
<source>观战</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">234</context>
</context-group>
</trans-unit>
<trans-unit id="8205455238047337952" datatype="html">
<source>本地录像</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">240</context>
</context-group>
</trans-unit>
<trans-unit id="5502924714960106302" datatype="html">
<source>游戏模式</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">257</context>
</context-group>
</trans-unit>
<trans-unit id="6820701675056797573" datatype="html">
<source>匹配</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">259</context>
</context-group>
</trans-unit>
<trans-unit id="3642846748955560947" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="&lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; [(ngModel)]=&quot;replay_rooms_filter.athletic&quot;&gt;"/> 竞技匹配 </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">261,263</context>
</context-group>
</trans-unit>
<trans-unit id="2494656030774940731" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="&lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; [(ngModel)]=&quot;replay_rooms_filter.entertain&quot;&gt;"/> 娱乐匹配 </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">265,267</context>
</context-group>
</trans-unit>
<trans-unit id="1551859094705611422" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="&lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; [(ngModel)]=&quot;replay_rooms_filter.single&quot;&gt;"/> 单局模式 </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">270,272</context>
</context-group>
</trans-unit>
<trans-unit id="8062928554703635061" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="&lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; [(ngModel)]=&quot;replay_rooms_filter.match&quot;&gt;"/> 比赛模式 </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">274,276</context>
</context-group>
</trans-unit>
<trans-unit id="4039664336266986759" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="&lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; [(ngModel)]=&quot;replay_rooms_filter.tag&quot;&gt;"/> TAG </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">278,280</context>
</context-group>
</trans-unit>
<trans-unit id="6802193244859447309" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="&lt;input type=&quot;checkbox&quot; class=&quot;form-check-input&quot; [(ngModel)]=&quot;replay_rooms_filter.windbot&quot;&gt;"/> 单人模式 </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">283,285</context>
</context-group>
</trans-unit>
<trans-unit id="96684194168608217" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{room.users![0] &amp;&amp; room.users![0].username}}"/> 的私密房间</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">305,306</context>
</context-group>
</trans-unit>
<trans-unit id="3410658596720819857" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{room.users![0] &amp;&amp; room.users![0].username}}"/><x id="INTERPOLATION_1" equiv-text="{{room.users![1] &amp;&amp; room.users![1].username}}"/> 的决斗</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/ygopro/ygopro.component.html</context>
<context context-type="linenumber">306,307</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment