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

i18n

parent 4fd5e106
...@@ -34,10 +34,17 @@ ...@@ -34,10 +34,17 @@
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
"i18n": {
"sourceLocale": "zh-Hans",
"locales": {
"en-US": "src/locale/messages.en-US.xlf"
}
},
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-builders/custom-webpack:browser", "builder": "@angular-builders/custom-webpack:browser",
"options": { "options": {
"localize": ["zh-Hans"],
"allowedCommonJsDependencies": [ "allowedCommonJsDependencies": [
"glob", "glob",
"aria2", "aria2",
......
...@@ -13,10 +13,12 @@ function handleElevate() { ...@@ -13,10 +13,12 @@ function handleElevate() {
require('electron').app.dock.hide(); require('electron').app.dock.hide();
} }
let elevate = JSON.parse(Buffer.from(process.argv[2], 'base64').toString()); let elevate = JSON.parse(Buffer.from(process.argv[2], 'base64').toString());
require('net').connect(elevate['ipc'], function() { require('net').connect(elevate['ipc'], function () {
process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + require('os').EOL, callback); process.send = (message, sendHandle, options, callback) => this.write(JSON.stringify(message) + require('os').EOL, callback);
this.on('end', () => process.emit('disconnect')); this.on('end', () => process.emit('disconnect'));
require('readline').createInterface({ input: this }).on('line', (line) => process.emit('message', JSON.parse(line))); require('readline')
.createInterface({ input: this })
.on('line', (line) => process.emit('message', JSON.parse(line)));
process.argv = elevate['arguments'][1]; process.argv = elevate['arguments'][1];
require('./' + elevate['arguments'][0]); require('./' + elevate['arguments'][0]);
}); });
...@@ -30,6 +32,8 @@ if (handleElevate()) { ...@@ -30,6 +32,8 @@ if (handleElevate()) {
const { ipcMain, app, shell, BrowserWindow, Menu, Tray, Notification } = require('electron'); const { ipcMain, app, shell, BrowserWindow, Menu, Tray, Notification } = require('electron');
const { autoUpdater } = require('electron-updater'); const { autoUpdater } = require('electron-updater');
const { localStorage } = require('electron-browser-storage');
const isDev = require('electron-is-dev'); const isDev = require('electron-is-dev');
const child_process = require('child_process'); const child_process = require('child_process');
const path = require('path'); const path = require('path');
...@@ -102,14 +106,14 @@ autoUpdater.on('update-downloaded', (event) => { ...@@ -102,14 +106,14 @@ autoUpdater.on('update-downloaded', (event) => {
console.log('autoUpdater', 'update-downloaded', event); console.log('autoUpdater', 'update-downloaded', event);
updateWindow = new BrowserWindow({ updateWindow = new BrowserWindow({
width: 640, width: 640,
height: 360 height: 360,
}); });
updateWindow.loadURL(`file://${__dirname}/update.html`); updateWindow.loadURL(`file://${__dirname}/update.html`);
updateWindow.webContents.on('new-window', function(e, url) { updateWindow.webContents.on('new-window', function (e, url) {
e.preventDefault(); e.preventDefault();
shell.openExternal(url); shell.openExternal(url);
}); });
updateWindow.on('closed', function() { updateWindow.on('closed', function () {
updateWindow = null; updateWindow = null;
}); });
ipcMain.on('update', (event, arg) => { ipcMain.on('update', (event, arg) => {
...@@ -141,7 +145,9 @@ function createAria2c() { ...@@ -141,7 +145,9 @@ function createAria2c() {
default: default:
throw 'unsupported platform'; throw 'unsupported platform';
} }
aria2c = child_process.spawn(aria2c_path, [ aria2c = child_process.spawn(
aria2c_path,
[
'--enable-rpc', '--enable-rpc',
'--rpc-allow-origin-all', '--rpc-allow-origin-all',
'--rpc-listen-port=6800', '--rpc-listen-port=6800',
...@@ -150,12 +156,21 @@ function createAria2c() { ...@@ -150,12 +156,21 @@ function createAria2c() {
'--min-split-size=1M', '--min-split-size=1M',
'--max-connection-per-server=10', '--max-connection-per-server=10',
'--remove-control-file', '--remove-control-file',
'--allow-overwrite' '--allow-overwrite',
], { stdio: 'ignore' }); ],
{ stdio: 'ignore' }
);
}
async function getLocale() {
const store = await localStorage.getItem('locale');
if (store) return store;
return app.getLocale().startsWith('zh') ? 'zh-Hans' : 'en-US';
} }
// 主窗口 // 主窗口
function createWindow() { async function createWindow() {
// Create the browser window. // Create the browser window.
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 1024, width: 1024,
...@@ -165,17 +180,17 @@ function createWindow() { ...@@ -165,17 +180,17 @@ function createWindow() {
frame: process.platform === 'darwin', frame: process.platform === 'darwin',
webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true }, webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true },
// transparent: process.platform != 'darwin', // transparent: process.platform != 'darwin',
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined,
}); });
// and load the index.html of the app. // and load the index.html of the app.
if (isDev) { if (isDev) {
mainWindow.loadURL('http://localhost:4200/'); mainWindow.loadURL('http://localhost:4200/');
} else { } else {
mainWindow.loadFile('dist/mycard/index.html'); mainWindow.loadFile(path.join('dist/mycard', await getLocale(), 'index.html'));
} }
mainWindow.webContents.on('new-window', function(e, url) { mainWindow.webContents.on('new-window', function (e, url) {
e.preventDefault(); e.preventDefault();
shell.openExternal(url); shell.openExternal(url);
}); });
...@@ -186,7 +201,7 @@ function createWindow() { ...@@ -186,7 +201,7 @@ function createWindow() {
} }
// Emitted when the window is closed. // Emitted when the window is closed.
mainWindow.on('closed', function() { mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows // Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time // in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element. // when you should delete the corresponding element.
...@@ -197,7 +212,7 @@ function createWindow() { ...@@ -197,7 +212,7 @@ function createWindow() {
let tray; let tray;
function createTray() { function createTray() {
tray = new Tray(path.join(__dirname, 'images', 'icon.ico')); tray = new Tray(path.join(__dirname, isDev ? 'src' : 'dist/mycard/zh-Hans', 'assets/icon.ico'));
tray.on('click', (event) => { tray.on('click', (event) => {
console.log(event); console.log(event);
if (event.metaKey) { if (event.metaKey) {
...@@ -211,13 +226,17 @@ function createTray() { ...@@ -211,13 +226,17 @@ function createTray() {
// {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: (menuItem, browserWindow, event)=>{}},
{ {
label: '显示主界面', type: 'normal', click: () => { label: '显示主界面',
type: 'normal',
click: () => {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show(); mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
} },
}, },
{ {
label: '退出', type: 'normal', click: app.quit label: '退出',
} type: 'normal',
click: app.quit,
},
]); ]);
tray.setToolTip('MyCard'); tray.setToolTip('MyCard');
tray.setContextMenu(contextMenu); tray.setContextMenu(contextMenu);
...@@ -252,7 +271,7 @@ app.on('ready', async () => { ...@@ -252,7 +271,7 @@ app.on('ready', async () => {
}); });
// Quit when all windows are closed. // Quit when all windows are closed.
app.on('window-all-closed', function() { app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar // On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q // to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
...@@ -260,7 +279,7 @@ app.on('window-all-closed', function() { ...@@ -260,7 +279,7 @@ app.on('window-all-closed', function() {
} }
}); });
app.on('activate', function() { app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the // 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. // dock icon is clicked and there are no other windows open.
if (mainWindow === null) { if (mainWindow === null) {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -13,6 +13,12 @@ ...@@ -13,6 +13,12 @@
"main": "main.js", "main": "main.js",
"description": "萌卡客户端", "description": "萌卡客户端",
"author": "zh99998 <zh99998@gmail.com>", "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": { "devDependencies": {
"@angular-builders/custom-webpack": "^12.1.1", "@angular-builders/custom-webpack": "^12.1.1",
"@angular/animations": "~12.2.5", "@angular/animations": "~12.2.5",
...@@ -26,41 +32,93 @@ ...@@ -26,41 +32,93 @@
"@angular/platform-browser": "~12.2.5", "@angular/platform-browser": "~12.2.5",
"@angular/platform-browser-dynamic": "~12.2.5", "@angular/platform-browser-dynamic": "~12.2.5",
"@angular/router": "~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", "@fortawesome/fontawesome-free": "^5.15.4",
"@types/bootstrap": "^5.1.4",
"@types/ini": "^1.3.30", "@types/ini": "^1.3.30",
"@types/jquery": "^3.5.6", "@types/jquery": "^3.5.6",
"@types/mousetrap": "^1.6.8",
"@types/mustache": "^4.1.2", "@types/mustache": "^4.1.2",
"@types/node": "^16.4.13",
"aria2": "^3.0.1", "aria2": "^3.0.1",
"bootstrap": "^5.1.0",
"candy": "https://github.com/moecube/candy/releases/download/v2.2.0/candy.tar.gz", "candy": "https://github.com/moecube/candy/releases/download/v2.2.0/candy.tar.gz",
"candy-shop": "github:candy-chat/candy-plugins", "candy-shop": "github:candy-chat/candy-plugins",
"electron-is-dev": "^2.0.0", "copy-webpack-plugin": "^9.0.1",
"electron-updater": "^4.3.9", "electron": "^14.0.0",
"electron-builder": "^22.11.7",
"electron-builder-notarize": "^1.2.0",
"exports-loader": "^3.0.0", "exports-loader": "^3.0.0",
"imports-loader": "^3.0.0", "imports-loader": "^3.0.0",
"ini": "^2.0.0", "ini": "^2.0.0",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"jquery-i18n": "github:recurser/jquery-i18n", "jquery-i18n": "github:recurser/jquery-i18n",
"mousetrap": "^1.6.5",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"reconnecting-websocket": "^4.4.0", "reconnecting-websocket": "^4.4.0",
"rxjs": "^7.3.0",
"strophe.js": "^1.4.2", "strophe.js": "^1.4.2",
"strophejs-plugin-caps": "^1.1.3", "strophejs-plugin-caps": "^1.1.3",
"strophejs-plugin-disco": "^0.0.2", "strophejs-plugin-disco": "^0.0.2",
"strophejs-plugin-muc": "^1.1.0", "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 { AppsService } from '../apps.service';
import { InstallOption } from '../shared/install-option'; import { InstallOption } from '../shared/install-option';
import { SettingsService } from '../settings.service'; import { SettingsService } from '../settings.service';
...@@ -22,7 +22,7 @@ declare const Notification: any; ...@@ -22,7 +22,7 @@ declare const Notification: any;
@Component({ @Component({
selector: 'app-detail', selector: 'app-detail',
templateUrl: 'app-detail.component.html', templateUrl: 'app-detail.component.html',
styleUrls: ['app-detail.component.css'] styleUrls: ['app-detail.component.css'],
}) })
export class AppDetailComponent implements OnInit, OnChanges { export class AppDetailComponent implements OnInit, OnChanges {
@Input() @Input()
...@@ -44,22 +44,31 @@ export class AppDetailComponent implements OnInit, OnChanges { ...@@ -44,22 +44,31 @@ export class AppDetailComponent implements OnInit, OnChanges {
payment = 'alipay'; payment = 'alipay';
creating_order = false; creating_order = false;
constructor(public appsService: AppsService, private settingsService: SettingsService, private downloadService: DownloadService, private ref: ChangeDetectorRef, private el: ElementRef, private loginService: LoginService) { constructor(
public appsService: AppsService,
this.tags = this.settingsService.getLocale().startsWith('zh') ? { private settingsService: SettingsService,
'recommend': '推荐', private downloadService: DownloadService,
'mysterious': '迷之物体', private ref: ChangeDetectorRef,
'touhou': '东方 Project', private el: ElementRef,
'touhou_pc98': '东方旧作', private loginService: LoginService,
'language': '语言包', @Inject(LOCALE_ID) private locale: string
'ygopro': 'YGOPro' ) {
} : { this.tags = locale.startsWith('zh')
'recommend': 'Recommended', ? {
'mysterious': 'Something', recommend: '推荐',
'touhou': 'Touhou Project', mysterious: '迷之物体',
'touhou_pc98': 'Touhou old series', touhou: '东方 Project',
'language': 'Language Pack', touhou_pc98: '东方旧作',
'ygopro': 'YGOPro' language: '语言包',
ygopro: 'YGOPro',
}
: {
recommend: 'Recommended',
mysterious: 'Something',
touhou: 'Touhou Project',
touhou_pc98: 'Touhou old series',
language: 'Language Pack',
ygopro: 'YGOPro',
}; };
} }
...@@ -108,8 +117,7 @@ export class AppDetailComponent implements OnInit, OnChanges { ...@@ -108,8 +117,7 @@ export class AppDetailComponent implements OnInit, OnChanges {
if (reference.isLanguage()) { if (reference.isLanguage()) {
// 对于语言包,只有在语言包的locales比游戏本身的更加合适的时候才默认勾选 // 对于语言包,只有在语言包的locales比游戏本身的更加合适的时候才默认勾选
// 这里先偷个懒,中文环境勾选中文语言包,非中文环境勾选非中文语言包 // 这里先偷个懒,中文环境勾选中文语言包,非中文环境勾选非中文语言包
this.referencesInstall[reference.id] = this.referencesInstall[reference.id] = reference.locales[0].startsWith('zh') === this.locale.startsWith('zh');
reference.locales[0].startsWith('zh') === this.settingsService.getLocale().startsWith('zh');
} else { } else {
this.referencesInstall[reference.id] = true; this.referencesInstall[reference.id] = true;
} }
...@@ -129,10 +137,8 @@ export class AppDetailComponent implements OnInit, OnChanges { ...@@ -129,10 +137,8 @@ export class AppDetailComponent implements OnInit, OnChanges {
} }
async installMod(mod: App) { async installMod(mod: App) {
let option = new InstallOption(mod, path.dirname(mod.parent!.local!.path)); let option = new InstallOption(mod, path.dirname(mod.parent!.local!.path));
await this.install(mod, option, {}); await this.install(mod, option, {});
} }
async uninstall(app: App) { async uninstall(app: App) {
...@@ -181,7 +187,7 @@ export class AppDetailComponent implements OnInit, OnChanges { ...@@ -181,7 +187,7 @@ export class AppDetailComponent implements OnInit, OnChanges {
this.availableLibraries.splice(index, 1); this.availableLibraries.splice(index, 1);
} }
} else { } 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; 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 child_process from 'child_process';
import { ChildProcess } from 'child_process'; import { ChildProcess } from 'child_process';
import crypto from 'crypto'; import crypto from 'crypto';
...@@ -20,8 +20,7 @@ import { AppsJson } from './shared/apps-json-type'; ...@@ -20,8 +20,7 @@ import { AppsJson } from './shared/apps-json-type';
import os from 'os'; import os from 'os';
import Timer = NodeJS.Timer; import Timer = NodeJS.Timer;
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import {lastValueFrom, map, Observable, Observer, timeout} from 'rxjs'; import { lastValueFrom, map, Observable, Observer, timeout } from 'rxjs';
const Logger = { const Logger = {
info: (...message: any[]) => { info: (...message: any[]) => {
...@@ -29,7 +28,7 @@ const Logger = { ...@@ -29,7 +28,7 @@ const Logger = {
}, },
error: (...message: any[]) => { error: (...message: any[]) => {
console.error('AppService [ERROR]: ', ...message); console.error('AppService [ERROR]: ', ...message);
} },
}; };
interface InstallTask { interface InstallTask {
...@@ -52,10 +51,9 @@ interface Connection { ...@@ -52,10 +51,9 @@ interface Connection {
declare const System: any; declare const System: any;
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root',
}) })
export class AppsService { export class AppsService {
eventEmitter = new EventEmitter<void>(); eventEmitter = new EventEmitter<void>();
map: Map<string, string> = new Map(); map: Map<string, string> = new Map();
connections = new Map<App, Connection>(); connections = new Map<App, Connection>();
...@@ -81,9 +79,15 @@ export class AppsService { ...@@ -81,9 +79,15 @@ export class AppsService {
private apps: Map<string, App>; private apps: Map<string, App>;
constructor(private http: HttpClient, private settingsService: SettingsService, private ref: ApplicationRef, constructor(
private downloadService: DownloadService, private ngZone: NgZone, private loginService: LoginService) { 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 { get lastVisited(): App | undefined {
let id = localStorage.getItem('last_visited'); let id = localStorage.getItem('last_visited');
...@@ -104,11 +108,13 @@ export class AppsService { ...@@ -104,11 +108,13 @@ export class AppsService {
let keysURL = 'https://sapi.moecube.com:444/keys'; let keysURL = 'https://sapi.moecube.com:444/keys';
try { try {
let data = await lastValueFrom(this.http.get<AppsJson.App[]>(appsURL).pipe(timeout(5000))); let data = await lastValueFrom(this.http.get<AppsJson.App[]>(appsURL).pipe(timeout(5000)));
let keys_data = await lastValueFrom(this.http.get<any[]>(keysURL, { let keys_data = await lastValueFrom(
this.http.get<any[]>(keysURL, {
params: { params: {
user_id: this.loginService.user.email user_id: this.loginService.user.email,
} },
})); })
);
for (let item of keys_data) { for (let item of keys_data) {
let app = data.find((app: any) => app.id === item.app_id); let app = data.find((app: any) => app.id === item.app_id);
if (app) { if (app) {
...@@ -183,19 +189,15 @@ export class AppsService { ...@@ -183,19 +189,15 @@ export class AppsService {
// "installLibrary": "D:\\MyCardLibrary" // "installLibrary": "D:\\MyCardLibrary"
// }, // },
// ] // ]
// { // {
// library: "D:\\MyCardLibrary", // library: "D:\\MyCardLibrary",
// apps: ["th105", "th105-lang-zh-CN", "th123", "th123-lang-zh-CN", "directx"] // 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 ... // 文件在 D:\MyCardLibrary\cache\th105.tar.xz, D:\MyCardLibrary\cache\th105-lang-zh-CN.tar.xz ...
// TODO: 安装那些app,不需要下载。安装成功后删除 bundle.json // TODO: 安装那些app,不需要下载。安装成功后删除 bundle.json
} catch (error) { } catch (error) {}
}
} }
async migrate_v2_ygopro() { async migrate_v2_ygopro() {
// 导入萌卡 v2 的 YGOPRO // 导入萌卡 v2 的 YGOPRO
let app = this.apps.get('ygopro')!; let app = this.apps.get('ygopro')!;
...@@ -222,8 +224,7 @@ export class AppsService { ...@@ -222,8 +224,7 @@ export class AppsService {
await this.createDirectory(_library); await this.createDirectory(_library);
this.settingsService.addLibrary(_library, true); this.settingsService.addLibrary(_library, true);
library = _library; library = _library;
} catch (error) { } catch (error) {}
}
} }
} }
if (!library) { if (!library) {
...@@ -234,8 +235,7 @@ export class AppsService { ...@@ -234,8 +235,7 @@ export class AppsService {
await this.importApp(app, legacy_ygopro_path, option); await this.importApp(app, legacy_ygopro_path, option);
localStorage.setItem('migrate_v2_ygopro', 'true'); localStorage.setItem('migrate_v2_ygopro', 'true');
} }
} catch (error) { } catch (error) {}
}
} }
async migreate_library() { async migreate_library() {
...@@ -250,7 +250,6 @@ export class AppsService { ...@@ -250,7 +250,6 @@ export class AppsService {
loadAppsList = (data: any): Map<string, App> => { loadAppsList = (data: any): Map<string, App> => {
let apps = new Map<string, App>(); let apps = new Map<string, App>();
let locale = this.settingsService.getLocale();
let platform = process.platform; let platform = process.platform;
for (let item of data) { for (let item of data) {
...@@ -277,7 +276,8 @@ export class AppsService { ...@@ -277,7 +276,8 @@ export class AppsService {
// 去除无关语言 // 去除无关语言
for (let key of ['name', 'description', 'news', 'developers', 'publishers']) { for (let key of ['name', 'description', 'news', 'developers', 'publishers']) {
if (app[key]) { 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 { ...@@ -308,7 +308,6 @@ export class AppsService {
} }
apps.set(item.id, app); apps.set(item.id, app);
} }
// 设置App关系 // 设置App关系
...@@ -347,26 +346,28 @@ export class AppsService { ...@@ -347,26 +346,28 @@ export class AppsService {
'en-US': 'English', 'en-US': 'English',
'zh-CN': 'Simplified Chinese', 'zh-CN': 'Simplified Chinese',
'zh-TW': 'Traditional Chinese', 'zh-TW': 'Traditional Chinese',
'language_pack': 'Language Pack' language_pack: 'Language Pack',
}, },
'zh-CN': { 'zh-Hans': {
'en-US': '英文', 'en-US': '英文',
'zh-CN': '简体中文', 'zh-CN': '简体中文',
'zh-TW': '繁体中文', 'zh-TW': '繁体中文',
'language_pack': '语言包' language_pack: '语言包',
} },
}; };
if (!app.name && app.parent && app.isLanguage()) { 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; return apps;
}; };
allReady(app: App) { allReady(app: App) {
return app.isReady() && return (
app.isReady() &&
app.findDependencies().every((dependency) => dependency.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> { async copyFile(src: string, dst: string): Promise<any> {
...@@ -411,8 +412,7 @@ export class AppsService { ...@@ -411,8 +412,7 @@ export class AppsService {
}); });
app.status.total = sortedFiles.length; app.status.total = sortedFiles.length;
// 刷新进度 // 刷新进度
let interval = setInterval(() => { let interval = setInterval(() => {}, 500);
}, 500);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this.ngZone.runOutsideAngular(async () => { this.ngZone.runOutsideAngular(async () => {
try { try {
...@@ -427,7 +427,6 @@ export class AppsService { ...@@ -427,7 +427,6 @@ export class AppsService {
} catch (e) { } catch (e) {
} finally { } finally {
app.status.progress += 1; app.status.progress += 1;
} }
} }
} }
...@@ -510,8 +509,7 @@ export class AppsService { ...@@ -510,8 +509,7 @@ export class AppsService {
let localFiles: Map<string, string> | undefined; let localFiles: Map<string, string> | undefined;
if (verify) { if (verify) {
// 刷新进度条 // 刷新进度条
let interval = setInterval(() => { let interval = setInterval(() => {}, 500);
}, 500);
app.status.total = latestFiles.size; app.status.total = latestFiles.size;
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this.ngZone.runOutsideAngular(async () => { this.ngZone.runOutsideAngular(async () => {
...@@ -653,12 +651,9 @@ export class AppsService { ...@@ -653,12 +651,9 @@ export class AppsService {
async doUpdate(app: App, changedFiles?: Set<string>, deletedFiles?: Set<string>) { async doUpdate(app: App, changedFiles?: Set<string>, deletedFiles?: Set<string>) {
if (changedFiles && changedFiles.size > 0) { if (changedFiles && changedFiles.size > 0) {
Logger.info('Update changed files: ', changedFiles); Logger.info('Update changed files: ', changedFiles);
let locale = this.settingsService.getLocale(); const locale = ['zh-Hans', 'en-US', 'ja-JP'].includes(this.locale) ? this.locale : 'en-US';
if (!['zh-CN', 'en-US', 'ja-JP'].includes(locale)) {
locale = 'en-US';
}
let updateUrl = App.updateUrl(app, process.platform, locale, os.arch()); 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 downloadDir = path.join(path.dirname(app.local!.path), 'downloading');
let downloadId = await this.downloadService.addMetalink(metalink, downloadDir); let downloadId = await this.downloadService.addMetalink(metalink, downloadDir);
await this.downloadService.progress(downloadId, (status: DownloadStatus) => { await this.downloadService.progress(downloadId, (status: DownloadStatus) => {
...@@ -670,17 +665,20 @@ export class AppsService { ...@@ -670,17 +665,20 @@ export class AppsService {
let downloadFiles = await this.downloadService.getFiles(downloadId); let downloadFiles = await this.downloadService.getFiles(downloadId);
app.status.total = 0; app.status.total = 0;
// 刷新进度条 // 刷新进度条
let interval = setInterval(() => { let interval = setInterval(() => {}, 500);
}, 500);
for (let downloadFile of downloadFiles) { for (let downloadFile of downloadFiles) {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this.extract(downloadFile, app.local!.path).subscribe((file) => { this.extract(downloadFile, app.local!.path).subscribe(
(file) => {
app.status.progressMessage = file; app.status.progressMessage = file;
}, (error) => { },
(error) => {
reject(error); reject(error);
}, () => { },
() => {
resolve(null); resolve(null);
}); }
);
}); });
} }
clearInterval(interval); clearInterval(interval);
...@@ -691,11 +689,9 @@ export class AppsService { ...@@ -691,11 +689,9 @@ export class AppsService {
await this.deleteFile(path.join(app.local!.path, deletedFile)); await this.deleteFile(path.join(app.local!.path, deletedFile));
} }
} }
} }
async install(app: App, option: InstallOption) { async install(app: App, option: InstallOption) {
const tryToInstall = async (task: InstallTask): Promise<void> => { const tryToInstall = async (task: InstallTask): Promise<void> => {
if (!task.app.readyForInstall()) { if (!task.app.readyForInstall()) {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
...@@ -710,14 +706,11 @@ export class AppsService { ...@@ -710,14 +706,11 @@ export class AppsService {
} }
await this.doInstall(task); await this.doInstall(task);
}; };
const addDownloadTask = async (_app: App, dir: string): Promise<{ app: App, files: string[] }> => { const addDownloadTask = async (_app: App, dir: string): Promise<{ app: App; files: string[] }> => {
let locale = this.settingsService.getLocale(); const locale = ['zh-Hans', 'en-US', 'ja-JP'].includes(this.locale) ? this.locale : 'en-US';
if (!['zh-CN', 'en-US', 'ja-JP'].includes(locale)) {
locale = 'en-US';
}
let metalinkUrl = App.downloadUrl(_app, process.platform, locale, os.arch()); let metalinkUrl = App.downloadUrl(_app, process.platform, locale, os.arch());
_app.status.status = 'downloading'; _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); let downloadId = await this.downloadService.addMetalink(metalink, dir);
try { try {
await this.downloadService.progress(downloadId, (status: DownloadStatus) => { await this.downloadService.progress(downloadId, (status: DownloadStatus) => {
...@@ -756,7 +749,6 @@ export class AppsService { ...@@ -756,7 +749,6 @@ export class AppsService {
installTasks.push(task); installTasks.push(task);
} }
await Promise.all(installTasks); await Promise.all(installTasks);
} catch (e) { } catch (e) {
for (let a of apps) { for (let a of apps) {
if (!a.isReady()) { if (!a.isReady()) {
...@@ -771,7 +763,7 @@ export class AppsService { ...@@ -771,7 +763,7 @@ export class AppsService {
findChildren(app: App): App[] { findChildren(app: App): App[] {
let children: App[] = []; let children: App[] = [];
for (let child of this.apps.values()) { 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); children.push(child);
} }
} }
...@@ -811,7 +803,9 @@ export class AppsService { ...@@ -811,7 +803,9 @@ export class AppsService {
async network(app: App, server: any) { async network(app: App, server: any) {
if (!this.maotama) { if (!this.maotama) {
this.maotama = new Promise((resolve, reject) => { 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('message', () => resolve(child));
child.once('error', reject); child.once('error', reject);
child.once('exit', reject); child.once('exit', reject);
...@@ -845,7 +839,7 @@ export class AppsService { ...@@ -845,7 +839,7 @@ export class AppsService {
id = setInterval(() => { id = setInterval(() => {
child.send({ child.send({
action: 'connect', action: 'connect',
arguments: [app.network.port, port, address] arguments: [app.network.port, port, address],
}); });
}, 200); }, 200);
break; break;
...@@ -876,10 +870,8 @@ export class AppsService { ...@@ -876,10 +870,8 @@ export class AppsService {
// tarPath: string; // tarPath: string;
// installingId: string = ''; // installingId: string = '';
// installQueue: Map<string,InstallTask> = new Map(); // installQueue: Map<string,InstallTask> = new Map();
// 调用前提:应用的依赖均已 Ready,应用处于下载完待安装的状态(waiting)。 // 调用前提:应用的依赖均已 Ready,应用处于下载完待安装的状态(waiting)。
// TODO: 要把Task系统去掉吗 // TODO: 要把Task系统去掉吗
async doInstall(task: InstallTask) { async doInstall(task: InstallTask) {
...@@ -887,12 +879,12 @@ export class AppsService { ...@@ -887,12 +879,12 @@ export class AppsService {
if (!app.isWaiting()) { if (!app.isWaiting()) {
console.error('doUninstall', '应用不处于等待安装状态', app); console.error('doUninstall', '应用不处于等待安装状态', app);
throw('应用不处于等待安装状态'); throw '应用不处于等待安装状态';
} }
if (!app.readyForInstall()) { if (!app.readyForInstall()) {
console.error('doInstall', '应用依赖不齐备', app); console.error('doInstall', '应用依赖不齐备', app);
throw('应用依赖不齐备'); throw '应用依赖不齐备';
} }
try { try {
...@@ -903,8 +895,7 @@ export class AppsService { ...@@ -903,8 +895,7 @@ export class AppsService {
app.status.status = 'installing'; app.status.status = 'installing';
app.status.total = allFiles.size; app.status.total = allFiles.size;
app.status.progress = 0; app.status.progress = 0;
let interval = setInterval(() => { let interval = setInterval(() => {}, 500);
}, 500);
if (app.parent) { if (app.parent) {
// mod需要安装到parent路径 // mod需要安装到parent路径
installDir = app.parent.local!.path; installDir = app.parent.local!.path;
...@@ -948,7 +939,8 @@ export class AppsService { ...@@ -948,7 +939,8 @@ export class AppsService {
}, },
() => { () => {
resolve(null); resolve(null);
}); }
);
}); });
} }
clearInterval(interval); clearInterval(interval);
...@@ -967,7 +959,6 @@ export class AppsService { ...@@ -967,7 +959,6 @@ export class AppsService {
} finally { } finally {
this.eventEmitter.emit(); this.eventEmitter.emit();
} }
} }
// 移除mkdirp函数,在这里自己实现 // 移除mkdirp函数,在这里自己实现
...@@ -986,7 +977,8 @@ export class AppsService { ...@@ -986,7 +977,8 @@ export class AppsService {
} }
}); });
}); });
} catch (error) { // 路径不存在,先尝试递归上级目录,再创建自己 } catch (error) {
// 路径不存在,先尝试递归上级目录,再创建自己
await this.createDirectory(path.dirname(dir)); await this.createDirectory(path.dirname(dir));
return new Promise<boolean>((resolve, reject) => { return new Promise<boolean>((resolve, reject) => {
fs.mkdir(dir, (error) => { fs.mkdir(dir, (error) => {
...@@ -998,9 +990,11 @@ export class AppsService { ...@@ -998,9 +990,11 @@ export class AppsService {
}); });
}); });
} }
if (stats.isDirectory()) { // 路径存在并且已经是目录,成功返回 if (stats.isDirectory()) {
// 路径存在并且已经是目录,成功返回
return false; return false;
} else { // 路径存在并且不是目录,失败。 } else {
// 路径存在并且不是目录,失败。
throw `#{dir} exists and is not a directory`; throw `#{dir} exists and is not a directory`;
} }
} }
...@@ -1014,7 +1008,7 @@ export class AppsService { ...@@ -1014,7 +1008,7 @@ export class AppsService {
Logger.info('Start to extract... Command Line: ' + this.tarPath, tarArgs.join(' ')); Logger.info('Start to extract... Command Line: ' + this.tarPath, tarArgs.join(' '));
let tarProcess = child_process.spawn(this.tarPath, tarArgs); let tarProcess = child_process.spawn(this.tarPath, tarArgs);
let rl = readline.createInterface({ let rl = readline.createInterface({
input: this.getTarStream(tarProcess) input: this.getTarStream(tarProcess),
}); });
rl.on('line', (input: string) => { rl.on('line', (input: string) => {
const line = input.split(' ', 2).pop()!; const line = input.split(' ', 2).pop()!;
...@@ -1032,8 +1026,7 @@ export class AppsService { ...@@ -1032,8 +1026,7 @@ export class AppsService {
observer.error(code); observer.error(code);
} }
}); });
return () => { return () => {};
};
}); });
} }
...@@ -1059,7 +1052,7 @@ export class AppsService { ...@@ -1059,7 +1052,7 @@ export class AppsService {
cwd: appPath, cwd: appPath,
env: env, env: env,
stdio: 'inherit', stdio: 'inherit',
shell: true shell: true,
}); });
child.on('error', (error) => { child.on('error', (error) => {
reject(error); reject(error);
...@@ -1117,14 +1110,11 @@ export class AppsService { ...@@ -1117,14 +1110,11 @@ export class AppsService {
} }
async getChecksumFile(app: App): Promise<Map<string, string>> { async getChecksumFile(app: App): Promise<Map<string, string>> {
const locale = ['zh-Hans', 'en-US', 'ja-JP'].includes(this.locale) ? this.locale : 'en-US';
let locale = this.settingsService.getLocale();
if (!['zh-CN', 'en-US', 'ja-JP'].includes(locale)) {
locale = 'en-US';
}
let checksumUrl = App.checksumUrl(app, process.platform, locale, os.arch()); let checksumUrl = App.checksumUrl(app, process.platform, locale, os.arch());
return lastValueFrom(this.http.get(checksumUrl,{responseType: 'text'}).pipe(map((response) => { return lastValueFrom(
this.http.get(checksumUrl, { responseType: 'text' }).pipe(
map((response) => {
let map = new Map<string, string>(); let map = new Map<string, string>();
for (let line of response.split('\n')) { for (let line of response.split('\n')) {
if (line !== '') { if (line !== '') {
...@@ -1135,10 +1125,11 @@ export class AppsService { ...@@ -1135,10 +1125,11 @@ export class AppsService {
} }
} }
return map; return map;
}))); })
)
);
} }
deleteFile(file: string): Promise<string> { deleteFile(file: string): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.lstat(file, (err, stats) => { fs.lstat(file, (err, stats) => {
...@@ -1191,8 +1182,7 @@ export class AppsService { ...@@ -1191,8 +1182,7 @@ export class AppsService {
app.status.total = files.length; app.status.total = files.length;
// 500毫秒手动刷新,避免文件过多产生的性能问题 // 500毫秒手动刷新,避免文件过多产生的性能问题
let interval = setInterval(() => { let interval = setInterval(() => {}, 500);
}, 500);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this.ngZone.runOutsideAngular(async () => { this.ngZone.runOutsideAngular(async () => {
try { try {
...@@ -1214,7 +1204,6 @@ export class AppsService { ...@@ -1214,7 +1204,6 @@ export class AppsService {
} catch (e) { } catch (e) {
reject(e); reject(e);
} }
}); });
}); });
clearInterval(interval); clearInterval(interval);
...@@ -1235,9 +1224,9 @@ export class AppsService { ...@@ -1235,9 +1224,9 @@ export class AppsService {
y: y, y: y,
frame: process.platform === 'darwin', frame: process.platform === 'darwin',
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined, titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined,
parent: remote.getCurrentWindow() parent: remote.getCurrentWindow(),
}); });
littleWindow.on('closed', function() { littleWindow.on('closed', function () {
littleWindow = null!; littleWindow = null!;
}); });
let urlt = new URL(url, window.location.toString()); let urlt = new URL(url, window.location.toString());
...@@ -1247,6 +1236,5 @@ export class AppsService { ...@@ -1247,6 +1236,5 @@ export class AppsService {
remote.ipcMain.on('massage', () => { remote.ipcMain.on('massage', () => {
alert('from littleWindow'); alert('from littleWindow');
}); });
} }
} }
...@@ -25,7 +25,7 @@ window['jQuery'] = $; ...@@ -25,7 +25,7 @@ window['jQuery'] = $;
import Mustache from 'mustache'; 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 { LoginService } from '../login/login.service';
import { SettingsService } from '../settings.service'; import { SettingsService } from '../settings.service';
import { App } from '../shared/app'; import { App } from '../shared/app';
...@@ -262,7 +262,12 @@ export class CandyComponent implements OnInit, OnChanges { ...@@ -262,7 +262,12 @@ export class CandyComponent implements OnInit, OnChanges {
// ismax_window:Boolean=false; // ismax_window:Boolean=false;
height_default_window: string = '230px'; 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() { ngOnInit() {
this.jid = this.loginService.user.username + '@mycard.moe'; this.jid = this.loginService.user.username + '@mycard.moe';
...@@ -307,7 +312,7 @@ export class CandyComponent implements OnInit, OnChanges { ...@@ -307,7 +312,7 @@ export class CandyComponent implements OnInit, OnChanges {
}, },
view: { view: {
assets: 'candy/res/', // copy-webpack-plugin assets: 'candy/res/', // copy-webpack-plugin
language: this.settingsService.getLocale().startsWith('zh') ? 'cn' : 'en', language: this.locale.startsWith('zh') ? 'cn' : 'en',
enableXHTML: true, enableXHTML: true,
}, },
}); });
......
/** /**
* Created by zh99998 on 16/9/2. * 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 { AppsService } from '../apps.service';
import { LoginService } from '../login/login.service'; import { LoginService } from '../login/login.service';
import { App, Category } from '../shared/app'; import { App, Category } from '../shared/app';
...@@ -16,10 +16,9 @@ const ReconnectingWebSocket = require('reconnecting-websocket'); ...@@ -16,10 +16,9 @@ const ReconnectingWebSocket = require('reconnecting-websocket');
@Component({ @Component({
selector: 'lobby', selector: 'lobby',
templateUrl: 'lobby.component.html', templateUrl: 'lobby.component.html',
styleUrls: ['lobby.component.css'] styleUrls: ['lobby.component.css'],
}) })
export class LobbyComponent implements OnInit { export class LobbyComponent implements OnInit {
currentApp: App; currentApp: App;
resizing: HTMLElement | undefined; resizing: HTMLElement | undefined;
offset: number; offset: number;
...@@ -29,9 +28,13 @@ export class LobbyComponent implements OnInit { ...@@ -29,9 +28,13 @@ export class LobbyComponent implements OnInit {
//private messages: WebSocket; //private messages: WebSocket;
constructor(private appsService: AppsService, private loginService: LoginService, constructor(
private settingsService: SettingsService, private ref: ChangeDetectorRef) { private appsService: AppsService,
} private loginService: LoginService,
private settingsService: SettingsService,
private ref: ChangeDetectorRef,
@Inject(LOCALE_ID) private locale: string
) {}
get grouped_apps(): any { get grouped_apps(): any {
// @ts-ignore // @ts-ignore
...@@ -51,7 +54,6 @@ export class LobbyComponent implements OnInit { ...@@ -51,7 +54,6 @@ export class LobbyComponent implements OnInit {
} else { } else {
tags = ['runtime']; tags = ['runtime'];
} }
} }
for (const tag of tags) { for (const tag of tags) {
if (!result[tag]) { if (!result[tag]) {
...@@ -80,7 +82,7 @@ export class LobbyComponent implements OnInit { ...@@ -80,7 +82,7 @@ export class LobbyComponent implements OnInit {
} }
} }
// 特化个 YGOPRO 国际服聊天室。其他的暂时没需求。 // 特化个 YGOPRO 国际服聊天室。其他的暂时没需求。
if (!this.settingsService.getLocale().startsWith('zh')) { if (!this.locale.startsWith('zh')) {
this.apps.get('ygopro')!.conference = 'ygopro-international'; this.apps.get('ygopro')!.conference = 'ygopro-international';
} }
this.ref.detectChanges(); this.ref.detectChanges();
...@@ -96,7 +98,6 @@ export class LobbyComponent implements OnInit { ...@@ -96,7 +98,6 @@ export class LobbyComponent implements OnInit {
this.currentApp = this.apps.get(this.currentApp.id)!; this.currentApp = this.apps.get(this.currentApp.id)!;
}; */ }; */
// $(this.search.nativeElement).typeahead(<any>{ // $(this.search.nativeElement).typeahead(<any>{
// minLength: 1, // minLength: 1,
// highlight: true // highlight: true
......
...@@ -77,9 +77,9 @@ ...@@ -77,9 +77,9 @@
<div class='form-group row'> <div class='form-group row'>
<label class='col-sm-2 col-form-label' for='locale' i18n>语言</label> <label class='col-sm-2 col-form-label' for='locale' i18n>语言</label>
<div class='col-sm-10'> <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='en-US'>English</option>
<option value='zh-CN'>简体中文</option> <option value='zh-Hans'>简体中文</option>
</select> </select>
</div> </div>
</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 { shell } from 'electron';
import * as remote from '@electron/remote'; import * as remote from '@electron/remote';
import $ from 'jquery'; import $ from 'jquery';
...@@ -32,7 +32,7 @@ export class MyCardComponent implements OnInit { ...@@ -32,7 +32,7 @@ export class MyCardComponent implements OnInit {
update_downloaded: ElementRef; update_downloaded: ElementRef;
update_elements: Map<string, ElementRef>; update_elements: Map<string, ElementRef>;
locale: string; localeNew: string = this.locale;
resizing: HTMLElement | null; resizing: HTMLElement | null;
...@@ -73,7 +73,11 @@ export class MyCardComponent implements OnInit { ...@@ -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) => { // renderer.listenGlobal('window', 'message', (event) => {
// console.log(event); // console.log(event);
// // Do something with 'event' // // Do something with 'event'
...@@ -98,8 +102,6 @@ export class MyCardComponent implements OnInit { ...@@ -98,8 +102,6 @@ export class MyCardComponent implements OnInit {
autoUpdater.on('update-downloaded', (event) => { autoUpdater.on('update-downloaded', (event) => {
this.set_update_status('update-downloaded'); this.set_update_status('update-downloaded');
}); });
this.locale = this.settingsService.getLocale();
} }
update_retry() { update_retry() {
...@@ -128,8 +130,8 @@ export class MyCardComponent implements OnInit { ...@@ -128,8 +130,8 @@ export class MyCardComponent implements OnInit {
} }
submit() { submit() {
if (this.locale !== this.settingsService.getLocale()) { if (this.localeNew !== this.locale) {
localStorage.setItem(SettingsService.SETTING_LOCALE, this.locale); localStorage.setItem(SettingsService.SETTING_LOCALE, this.localeNew);
remote.app.relaunch(); remote.app.relaunch();
remote.app.quit(); remote.app.quit();
} }
......
/** /**
* Created by weijian on 2016/10/24. * Created by weijian on 2016/10/24.
*/ */
import { Injectable } from '@angular/core'; import {Injectable} from '@angular/core';
import path from 'path'; import path from 'path';
import { app } from '@electron/remote'; import {app} from '@electron/remote';
export interface Library { export interface Library {
'default': boolean; 'default': boolean;
...@@ -23,12 +23,8 @@ export class SettingsService { ...@@ -23,12 +23,8 @@ export class SettingsService {
} }
]; ];
static SETTING_LOCALE = 'locale'; static SETTING_LOCALE = 'locale';
static defaultLocale = app.getLocale();
locale: string;
libraries: Library[]; libraries: Library[];
getLibraries() { getLibraries() {
if (!this.libraries) { if (!this.libraries) {
let data = localStorage.getItem(SettingsService.SETTING_LIBRARY); let data = localStorage.getItem(SettingsService.SETTING_LIBRARY);
...@@ -51,7 +47,7 @@ export class SettingsService { ...@@ -51,7 +47,7 @@ export class SettingsService {
l.default = false; l.default = false;
}); });
} }
libraries.push({ 'default': isDefault, path: libraryPath }); libraries.push({'default': isDefault, path: libraryPath});
this.libraries = libraries; this.libraries = libraries;
localStorage.setItem(SettingsService.SETTING_LIBRARY, JSON.stringify(libraries)); localStorage.setItem(SettingsService.SETTING_LIBRARY, JSON.stringify(libraries));
} }
...@@ -76,22 +72,4 @@ export class SettingsService { ...@@ -76,22 +72,4 @@ export class SettingsService {
throw('no default library found'); 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 { ...@@ -108,7 +108,7 @@ export class App {
static getQuerySuffix(platform: string, locale: string, arch: string) { static getQuerySuffix(platform: string, locale: string, arch: string) {
const params = new URLSearchParams(); const params = new URLSearchParams();
params.set('platform', platform); params.set('platform', platform);
params.set('locale', locale); params.set('locale', locale === 'zh-Hans' ? 'zh-CN' : 'zh-Hans');
params.set('arch', arch); params.set('arch', arch);
return params.toString(); 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. * 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 { clipboard, shell } from 'electron';
import * as remote from '@electron/remote' import * as remote from '@electron/remote';
import fs from 'fs-extra'; import fs from 'fs-extra';
import $ from 'jquery'; import $ from 'jquery';
import path from 'path'; import path from 'path';
...@@ -16,7 +28,7 @@ import fg from 'fast-glob'; ...@@ -16,7 +28,7 @@ import fg from 'fast-glob';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import WillNavigateEvent = Electron.WillNavigateEvent; import WillNavigateEvent = Electron.WillNavigateEvent;
import Timer = NodeJS.Timer; import Timer = NodeJS.Timer;
import {lastValueFrom, Subscription} from 'rxjs'; import { lastValueFrom, Subscription } from 'rxjs';
interface SystemConf { interface SystemConf {
use_d3d: string; use_d3d: string;
...@@ -61,10 +73,10 @@ interface Room { ...@@ -61,10 +73,10 @@ interface Room {
id?: string; id?: string;
title?: string; title?: string;
server?: Server; server?: Server;
'private'?: boolean; private?: boolean;
options: Options; options: Options;
arena?: string; arena?: string;
users?: { username: string, position: number }[]; users?: { username: string; position: number }[];
} }
interface Options { interface Options {
...@@ -106,7 +118,6 @@ interface YGOProData { ...@@ -106,7 +118,6 @@ interface YGOProData {
servers: Server[]; servers: Server[];
} }
let matching: Subscription | undefined; let matching: Subscription | undefined;
let matching_arena: string | undefined; let matching_arena: string | undefined;
let match_started_at: Date; let match_started_at: Date;
...@@ -115,7 +126,7 @@ let match_started_at: Date; ...@@ -115,7 +126,7 @@ let match_started_at: Date;
moduleId: module.id, moduleId: module.id,
selector: 'ygopro', selector: 'ygopro',
templateUrl: 'ygopro.component.html', templateUrl: 'ygopro.component.html',
styleUrls: ['ygopro.component.css'] styleUrls: ['ygopro.component.css'],
}) })
export class YGOProComponent implements OnInit, OnDestroy { export class YGOProComponent implements OnInit, OnDestroy {
@Input() @Input()
...@@ -153,7 +164,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -153,7 +164,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
lastDeckFormat: RegExp; lastDeckFormat: RegExp;
default_options: Options = { default_options: Options = {
mode: 1, mode: 1,
rule: this.settingsService.getLocale().startsWith('zh') ? 0 : 1, rule: this.locale.startsWith('zh') ? 0 : 1,
start_lp: 8000, start_lp: 8000,
start_lp_tag: 16000, start_lp_tag: 16000,
start_hand: 5, start_hand: 5,
...@@ -163,7 +174,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -163,7 +174,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
no_shuffle_deck: false, no_shuffle_deck: false,
lflist: 0, lflist: 0,
time_limit: 180, time_limit: 180,
auto_death: false auto_death: false,
}; };
room: Room = { title: this.loginService.user.username + '的房间', options: Object.assign({}, this.default_options) }; room: Room = { title: this.loginService.user.username + '的房间', options: Object.assign({}, this.default_options) };
rooms: Room[] = []; rooms: Room[] = [];
...@@ -178,7 +189,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -178,7 +189,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
single: true, single: true,
match: true, match: true,
tag: true, tag: true,
windbot: false windbot: false,
}; };
matching: Subscription | undefined; matching: Subscription | undefined;
matching_arena: string | undefined; matching_arena: string | undefined;
...@@ -188,8 +199,14 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -188,8 +199,14 @@ export class YGOProComponent implements OnInit, OnDestroy {
join_password: string; join_password: string;
host_password = (this.loginService.user.external_id ^ 0x54321).toString(); host_password = (this.loginService.user.external_id ^ 0x54321).toString();
constructor(private http: HttpClient, public appsService: AppsService, private loginService: LoginService, constructor(
public settingsService: SettingsService, private ref: ChangeDetectorRef) { private http: HttpClient,
public appsService: AppsService,
private loginService: LoginService,
public settingsService: SettingsService,
private ref: ChangeDetectorRef,
@Inject(LOCALE_ID) public locale: string
) {
switch (process.platform) { switch (process.platform) {
// linux should have fonts set by default // linux should have fonts set by default
case 'linux': case 'linux':
...@@ -197,13 +214,13 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -197,13 +214,13 @@ export class YGOProComponent implements OnInit, OnDestroy {
'/usr/share/fonts/truetype/DroidSansFallbackFull.ttf', '/usr/share/fonts/truetype/DroidSansFallbackFull.ttf',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc', '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc',
'/usr/share/fonts/google-noto-cjk/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 = [ this.textfont = [
'/usr/share/fonts/truetype/DroidSansFallbackFull.ttf', '/usr/share/fonts/truetype/DroidSansFallbackFull.ttf',
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', '/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
'/usr/share/fonts/google-noto-cjk/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; break;
case 'darwin': case 'darwin':
...@@ -215,7 +232,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -215,7 +232,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
this.textfont = [ this.textfont = [
path.join(process.env['SystemRoot']!, 'Fonts', 'msyh.ttc'), path.join(process.env['SystemRoot']!, 'Fonts', 'msyh.ttc'),
path.join(process.env['SystemRoot']!, 'Fonts', 'msyh.ttf'), 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; break;
} }
...@@ -239,17 +256,21 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -239,17 +256,21 @@ export class YGOProComponent implements OnInit, OnDestroy {
} }
refresh_replay_rooms() { refresh_replay_rooms() {
this.replay_rooms_show = this.replay_rooms.filter((room) => { this.replay_rooms_show = this.replay_rooms
.filter((room) => {
if (!room.arena && room.server && room.server !== this.currentServer) { if (!room.arena && room.server && room.server !== this.currentServer) {
return false; return false;
} }
return ((this.replay_rooms_filter.athletic && room.arena === 'athletic') || return (
(this.replay_rooms_filter.athletic && room.arena === 'athletic') ||
(this.replay_rooms_filter.entertain && room.arena === 'entertain') || (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.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.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.tag && room.options.mode === 2 && !room.arena && !room.id!.startsWith('AI#')) ||
(this.replay_rooms_filter.windbot && room.id!.startsWith('AI#'))); (this.replay_rooms_filter.windbot && room.id!.startsWith('AI#'))
}).sort((a, b) => { );
})
.sort((a, b) => {
// if (a.arena === 'athletic' && b.arena === 'athletic') { // if (a.arena === 'athletic' && b.arena === 'athletic') {
// return a.dp - b.dp; // return a.dp - b.dp;
// } else if (a.arena === 'entertain' && b.arena === 'entertain') { // } else if (a.arena === 'entertain' && b.arena === 'entertain') {
...@@ -288,17 +309,10 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -288,17 +309,10 @@ export class YGOProComponent implements OnInit, OnDestroy {
async ngOnInit() { async ngOnInit() {
const ygoproData = this.getYGOProData(this.app); const ygoproData = this.getYGOProData(this.app);
this.servers = ygoproData.servers; 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.currentServer = this.selectableServers[0];
// this.reloadCurrentServer(); // this.reloadCurrentServer();
let locale: string;
if (this.settingsService.getLocale().startsWith('zh')) {
locale = 'zh-CN';
} else {
locale = 'en-US';
}
if (ygoproData.ygopro.lastDeckFormat) { if (ygoproData.ygopro.lastDeckFormat) {
// console.log(`Deck format pattern: ${ygoproData.ygopro.lastDeckFormat}`) // console.log(`Deck format pattern: ${ygoproData.ygopro.lastDeckFormat}`)
this.lastDeckFormat = new RegExp(ygoproData.ygopro.lastDeckFormat); this.lastDeckFormat = new RegExp(ygoproData.ygopro.lastDeckFormat);
...@@ -312,17 +326,19 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -312,17 +326,19 @@ export class YGOProComponent implements OnInit, OnDestroy {
modal.on('show.bs.modal', () => { modal.on('show.bs.modal', () => {
this.rooms_loading = true; this.rooms_loading = true;
this.connections = this.servers.filter(server => server.custom).map((server) => { this.connections = this.servers
.filter((server) => server.custom)
.map((server) => {
let url = new URL(server.url!); let url = new URL(server.url!);
url['searchParams'].set('filter', 'waiting'); url['searchParams'].set('filter', 'waiting');
let connection = new WebSocket(url.toString()); let connection = new WebSocket(url.toString());
connection.onclose = (event: CloseEvent) => { connection.onclose = (event: CloseEvent) => {
this.rooms = this.rooms.filter(room => room.server !== server); this.rooms = this.rooms.filter((room) => room.server !== server);
this.refresh_rooms(); this.refresh_rooms();
}; };
connection.onerror = (event) => { connection.onerror = (event) => {
console.log('error', server.id, event); console.log('error', server.id, event);
this.rooms = this.rooms.filter(room => room.server !== server); this.rooms = this.rooms.filter((room) => room.server !== server);
this.refresh_rooms(); this.refresh_rooms();
}; };
connection.onmessage = (event) => { connection.onmessage = (event) => {
...@@ -330,18 +346,24 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -330,18 +346,24 @@ export class YGOProComponent implements OnInit, OnDestroy {
switch (message.event) { switch (message.event) {
case 'init': case 'init':
this.rooms_loading = false; this.rooms_loading = false;
this.rooms = this.rooms.filter(room => room.server !== server).concat( this.rooms = this.rooms
message.data.map((room: Room) => Object.assign({ server: server }, room)) .filter((room) => room.server !== server)
); .concat(message.data.map((room: Room) => Object.assign({ server: server }, room)));
break; break;
case 'create': case 'create':
this.rooms.push(Object.assign({ server: server }, message.data)); this.rooms.push(Object.assign({ server: server }, message.data));
break; break;
case 'update': case 'update':
Object.assign(this.rooms.find(room => room.server === server && room.id === message.data.id), message.data); Object.assign(
this.rooms.find((room) => room.server === server && room.id === message.data.id),
message.data
);
break; break;
case 'delete': case 'delete':
this.rooms.splice(this.rooms.findIndex(room => room.server === server && room.id === message.data), 1); this.rooms.splice(
this.rooms.findIndex((room) => room.server === server && room.id === message.data),
1
);
} }
this.refresh_rooms(); this.refresh_rooms();
this.ref.detectChanges(); this.ref.detectChanges();
...@@ -361,34 +383,48 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -361,34 +383,48 @@ export class YGOProComponent implements OnInit, OnDestroy {
let replay_modal = $('#game-replay-modal'); let replay_modal = $('#game-replay-modal');
replay_modal.on('show.bs.modal', () => { replay_modal.on('show.bs.modal', () => {
this.replay_connections = this.servers.filter(server => server.replay).map((server) => { this.replay_connections = this.servers
.filter((server) => server.replay)
.map((server) => {
let url = new URL(server.url!); let url = new URL(server.url!);
url['searchParams'].set('filter', 'started'); url['searchParams'].set('filter', 'started');
let connection = new WebSocket(url.toString()); let connection = new WebSocket(url.toString());
connection.onclose = () => { connection.onclose = () => {
this.replay_rooms = this.replay_rooms.filter(room => room.server !== server); this.replay_rooms = this.replay_rooms.filter((room) => room.server !== server);
this.refresh_replay_rooms(); this.refresh_replay_rooms();
}; };
connection.onmessage = (event) => { connection.onmessage = (event) => {
let message = JSON.parse(event.data); let message = JSON.parse(event.data);
switch (message.event) { switch (message.event) {
case 'init': case 'init':
this.replay_rooms = this.replay_rooms.filter(room => room.server !== server).concat( this.replay_rooms = this.replay_rooms
message.data.map((room: Room) => Object.assign({ .filter((room) => room.server !== server)
.concat(
message.data.map((room: Room) =>
Object.assign(
{
server: server, server: server,
'private': /^\d+$/.test(room.title!) private: /^\d+$/.test(room.title!),
}, room)) },
room
)
)
); );
break; break;
case 'create': case 'create':
this.replay_rooms.push(Object.assign({ this.replay_rooms.push(
Object.assign(
{
server: server, server: server,
'private': /^\d+$/.test(message.data.title!) private: /^\d+$/.test(message.data.title!),
}, message.data)); },
message.data
)
);
break; break;
case 'delete': case 'delete':
this.replay_rooms.splice( this.replay_rooms.splice(
this.replay_rooms.findIndex(room => room.server === server && room.id === message.data), this.replay_rooms.findIndex((room) => room.server === server && room.id === message.data),
1 1
); );
} }
...@@ -408,7 +444,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -408,7 +444,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
let watchDropdownMenu = $('#watch-filter'); 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); // $(event.target).closest("label").toggleClass("active", (<HTMLInputElement> event.target).checked);
this.refresh_replay_rooms(); this.refresh_replay_rooms();
}); });
...@@ -429,7 +465,6 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -429,7 +465,6 @@ export class YGOProComponent implements OnInit, OnDestroy {
}); });
} }
async refresh(init?: boolean) { async refresh(init?: boolean) {
this.decks = await this.get_decks(); this.decks = await this.get_decks();
this.decks_grouped = this.deckGroup(); this.decks_grouped = this.deckGroup();
...@@ -462,16 +497,18 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -462,16 +497,18 @@ export class YGOProComponent implements OnInit, OnDestroy {
// https://mycard.moe/ygopro/api/user?username=ozxdno // https://mycard.moe/ygopro/api/user?username=ozxdno
try { try {
let points = await lastValueFrom(this.http.get<any>('https://mycard.moe/ygopro/api/user', { let points = await lastValueFrom(
this.http.get<any>('https://mycard.moe/ygopro/api/user', {
params: { params: {
username: this.loginService.user.username username: this.loginService.user.username,
} },
})); })
);
this.points.emit(points); this.points.emit(points);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
}; }
async get_decks(): Promise<string[]> { async get_decks(): Promise<string[]> {
try { try {
...@@ -483,13 +520,18 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -483,13 +520,18 @@ export class YGOProComponent implements OnInit, OnDestroy {
} }
deckGroup(): [string, string[]][] { 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[]> { async get_replays(): Promise<string[]> {
try { try {
let files: string[] = await fs.readdir(this.app.ygoproReplayPath!); 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) { } catch (error) {
console.error(`Load replay fail: ${error.toString()}`); console.error(`Load replay fail: ${error.toString()}`);
return []; return [];
...@@ -509,8 +551,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -509,8 +551,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
if (confirm('确认删除?')) { if (confirm('确认删除?')) {
try { try {
await fs.unlink(path.join(this.app.ygoproDeckPath!, deck + '.ydk')); await fs.unlink(path.join(this.app.ygoproDeckPath!, deck + '.ydk'));
} catch (error) { } catch (error) {}
}
return this.refresh(); return this.refresh();
} }
} }
...@@ -543,7 +584,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -543,7 +584,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
} catch (e) { } catch (e) {
return; return;
} }
}; }
/* /*
save_system_conf(data: SystemConf) { save_system_conf(data: SystemConf) {
...@@ -562,7 +603,7 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -562,7 +603,7 @@ export class YGOProComponent implements OnInit, OnDestroy {
await this.save_system_conf(system_conf);*/ 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(['-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 }); return this.start_game('main', { server, password: name, username: this.loginService.user.username, deck: this.current_deck });
}; }
async edit_deck(deck: string) { async edit_deck(deck: string) {
/*let system_conf = await this.load_system_conf(); /*let system_conf = await this.load_system_conf();
...@@ -610,23 +651,25 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -610,23 +651,25 @@ export class YGOProComponent implements OnInit, OnDestroy {
win.restore(); win.restore();
}); });
try { try {
lastValueFrom(this.http.get<any>('https://mycard.moe/ygopro/api/history', { lastValueFrom(
this.http.get<any>('https://mycard.moe/ygopro/api/history', {
params: { params: {
page: 1, page: 1,
username: this.loginService.user.username, username: this.loginService.user.username,
type: 0, type: 0,
page_num: 1 page_num: 1,
} },
})) })
.then((d) => { ).then((d) => {
start_time = d.data[0].start_time; start_time = d.data[0].start_time;
}); });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
try { try {
lastValueFrom(this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', { params: { username: this.loginService.user.username } })) lastValueFrom(
.then((d2) => { 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; exp_rank_ex = d2.exp_rank;
arena_rank_ex = d2.arena_rank; arena_rank_ex = d2.arena_rank;
}); });
...@@ -635,26 +678,28 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -635,26 +678,28 @@ export class YGOProComponent implements OnInit, OnDestroy {
} }
}); });
try { try {
await lastValueFrom(this.http.get<any>('https://mycard.moe/ygopro/api/history', { await lastValueFrom(
this.http.get<any>('https://mycard.moe/ygopro/api/history', {
params: { params: {
page: 1, page: 1,
username: this.loginService.user.username, username: this.loginService.user.username,
// username: "星光pokeboy", // username: "星光pokeboy",
type: 0, type: 0,
page_num: 1 page_num: 1,
} },
})) })
.then((d) => { ).then((d) => {
data = d.data[0]; data = d.data[0];
data.myname = this.loginService.user.username; data.myname = this.loginService.user.username;
}); });
await lastValueFrom(this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', { await lastValueFrom(
this.http.get<any>('https://sapi.moecube.com:444/ygopro/arena/user', {
params: { params: {
username: this.loginService.user.username username: this.loginService.user.username,
} },
})) })
.then((data2) => { ).then((data2) => {
data.athletic_win = data2.athletic_win; data.athletic_win = data2.athletic_win;
data.athletic_lose = data2.athletic_lose; data.athletic_lose = data2.athletic_lose;
data.entertain_win = data2.entertain_win; data.entertain_win = data2.entertain_win;
...@@ -670,41 +715,40 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -670,41 +715,40 @@ export class YGOProComponent implements OnInit, OnDestroy {
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
}; }
create_room(room: Room) { create_room(room: Room) {
let options_buffer = Buffer.alloc(6); let options_buffer = Buffer.alloc(6);
// 建主密码 https://docs.google.com/document/d/1rvrCGIONua2KeRaYNjKBLqyG9uybs9ZI-AmzZKNftOI/edit // 建主密码 https://docs.google.com/document/d/1rvrCGIONua2KeRaYNjKBLqyG9uybs9ZI-AmzZKNftOI/edit
options_buffer.writeUInt8(((room.private ? 2 : 1) << 4) | options_buffer.writeUInt8(((room.private ? 2 : 1) << 4) | (room.options.duel_rule << 1) | (room.options.auto_death ? 0x1 : 0), 1);
(room.options.duel_rule << 1) |
(room.options.auto_death ? 0x1 : 0), 1);
options_buffer.writeUInt8( options_buffer.writeUInt8(
room.options.rule << 5 | (room.options.rule << 5) |
room.options.mode << 3 | (room.options.mode << 3) |
(room.options.no_check_deck ? 1 << 1 : 0) | (room.options.no_check_deck ? 1 << 1 : 0) |
(room.options.no_shuffle_deck ? 1 : 0) (room.options.no_shuffle_deck ? 1 : 0),
, 2); 2
);
options_buffer.writeUInt16LE(room.options.start_lp, 3); 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; let checksum = 0;
for (let i = 1; i < options_buffer.length; i++) { for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(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) { for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i); options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
} }
let password = options_buffer.toString('base64') + (room.private ? this.host_password : let password =
room.title!.replace(/\s/, String.fromCharCode(0xFEFF))); 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') // let room_id = crypto.createHash('md5').update(password + this.loginService.user.username).digest('base64')
// .slice(0, 10).replace('+', '-').replace('/', '_'); // .slice(0, 10).replace('+', '-').replace('/', '_');
if (room.private) { if (room.private) {
new Notification('YGOPro 私密房间已建立', { new Notification('YGOPro 私密房间已建立', {
body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。` body: `房间密码是 ${this.host_password}, 您的对手可在自定义游戏界面输入密码与您对战。`,
}); });
} }
this.join(password, this.currentServer); this.join(password, this.currentServer);
...@@ -724,14 +768,13 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -724,14 +768,13 @@ export class YGOProComponent implements OnInit, OnDestroy {
for (let i = 1; i < options_buffer.length; i++) { for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(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) { for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i); options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i);
} }
let name = options_buffer.toString('base64') + room.id; let name = options_buffer.toString('base64') + room.id;
this.join(name, room.server!); this.join(name, room.server!);
...@@ -744,14 +787,14 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -744,14 +787,14 @@ export class YGOProComponent implements OnInit, OnDestroy {
for (let i = 1; i < options_buffer.length; i++) { for (let i = 1; i < options_buffer.length; i++) {
checksum -= options_buffer.readUInt8(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) { for (let i = 0; i < options_buffer.length; i += 2) {
options_buffer.writeUInt16LE(options_buffer.readUInt16LE(i) ^ secret, i); 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); this.join(name, this.currentServer);
} }
...@@ -759,18 +802,22 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -759,18 +802,22 @@ export class YGOProComponent implements OnInit, OnDestroy {
request_match(arena = 'entertain') { request_match(arena = 'entertain') {
match_started_at = new Date(); match_started_at = new Date();
this.matching_arena = matching_arena = arena; this.matching_arena = matching_arena = arena;
this.matching = matching = this.http.post<any>('https://sapi.moecube.com:444/ygopro/match', null, { this.matching = matching = this.http
.post<any>('https://sapi.moecube.com:444/ygopro/match', null, {
headers: { headers: {
Authorization: 'Basic ' + Buffer.from(this.loginService.user.username + ':' + this.loginService.user.external_id).toString('base64') Authorization:
'Basic ' + Buffer.from(this.loginService.user.username + ':' + this.loginService.user.external_id).toString('base64'),
}, },
params: { params: {
arena, arena,
locale: this.settingsService.getLocale() locale: this.locale === 'zh-Hans' ? 'zh-CN' : this.locale,
} },
}) })
.subscribe((data) => { .subscribe(
(data) => {
this.join(data['password'], { id: '_match', address: data['address'], port: data['port'] }); this.join(data['password'], { id: '_match', address: data['address'], port: data['port'] });
}, (error) => { },
(error) => {
alert(`匹配失败`); alert(`匹配失败`);
this.matching = matching = undefined; this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined; this.matching_arena = matching_arena = undefined;
...@@ -778,14 +825,16 @@ export class YGOProComponent implements OnInit, OnDestroy { ...@@ -778,14 +825,16 @@ export class YGOProComponent implements OnInit, OnDestroy {
clearInterval(this.match_interval); clearInterval(this.match_interval);
this.match_interval = undefined; this.match_interval = undefined;
} }
}, () => { },
() => {
this.matching = matching = undefined; this.matching = matching = undefined;
this.matching_arena = matching_arena = undefined; this.matching_arena = matching_arena = undefined;
if (this.match_interval) { if (this.match_interval) {
clearInterval(this.match_interval); clearInterval(this.match_interval);
this.match_interval = undefined; this.match_interval = undefined;
} }
}); }
);
this.refresh_match(); this.refresh_match();
this.match_interval = setInterval(() => { 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