diff --git a/Electron/AMAI-release/install.js b/Electron/AMAI-release/install.js index 95bd469c7..3c9790a6a 100644 --- a/Electron/AMAI-release/install.js +++ b/Electron/AMAI-release/install.js @@ -3,7 +3,8 @@ const path = require("path"); const { takeHeapSnapshot } = require("process"); const spawnSync = require("child_process").spawnSync; const arrayOfFiles = []; - +let totalFiles = 0; +let currentFileIndex = 0; /** uncomment to debbug */ // const ls = spawnSync( @@ -33,16 +34,14 @@ const installOnDirectory = async () => { const args = process.argv.slice(2); const response = args[0]; const commander = args[1]; - const ver = args[2] - const language = args[3] - const installCommander = commander == 1 - const vsAICommander = commander == 2 - let bj = 'Blizzard.j' - if (vsAICommander) { bj = 'vsai\\Blizzard.j'} - + const ver = args[2]; + const language = args[3]; + const installCommander = commander == 1; + const vsAICommander = commander == 2; + let bj = 'Blizzard.j'; + if (vsAICommander) {bj = 'vsai\\Blizzard.j'} const commonAIPath = `Scripts\\${ver}\\common.ai` const blizzardPath =`Scripts\\${ver}\\Blizzard.j` - process.send(`#### Installing AMAI for ${ver} Commander ${commander > 0 ? bj : 'None'} forcing ai language to ${language || 'default'} ####`); // TODO: change to receive array of maps @@ -71,8 +70,6 @@ const installOnDirectory = async () => { return } - - if (language !== '-') { setLanguage(commonAIPath, language); if (installCommander) { @@ -85,8 +82,9 @@ const installOnDirectory = async () => { } } - if(arrayOfFiles) { + totalFiles = arrayOfFiles.length; + //process.send({ type: 'progress', current: currentFileIndex, total: totalFiles }); for (const file of arrayOfFiles) { /** uncomment to debbug */ // process.send(`path.extname(file): ${path.extname(file)}`); @@ -94,6 +92,15 @@ const installOnDirectory = async () => { const ext = path.extname(file).toLowerCase(); if(ext.indexOf(`w3m`) >= 0 || ext.indexOf(`w3x`) >= 0) { + currentFileIndex++; + // Send complete progress data including both current and total + if (process.send) { + process.send({ + type: 'progress', + current: currentFileIndex, + total: totalFiles, + }); + } process.send(`#### Installing ${ver} into file: ${file} ####`); } else { process.send(`skip file: ${file}`); @@ -128,7 +135,7 @@ const installOnDirectory = async () => { process.send(mpqEditor.error.message) : process.send(`Resize map hashtable size ${file}`); - const f1AddToMPQ = spawnSync( + const f1AddToMPQ = spawnSync( `MPQEditor.exe`, [ 'a', @@ -178,16 +185,15 @@ const installOnDirectory = async () => { f1AddVSAIToMPQ.error ? process.send(f1AddVSAIToMPQ.error.message) : process.send(`Installing VS Vanilla AI Scripts ${file}`); - } - const f2AddToMPQ = spawnSync( + const f2AddToMPQ = spawnSync( `MPQEditor.exe`, [ 'a', file, `Scripts\\${ver}\\${bj}`, - `Scripts\\Blizzard.j`, + `Scripts\\Blizzard.j` ], { encoding : `utf8` } ); @@ -206,7 +212,6 @@ const installOnDirectory = async () => { f2AddToMPQ.error ? process.send(f2AddToMPQ.error.message) : process.send(installCommander ? `Installing commander ${file}` : `Installing VS Vanilla AI commander ${file}`); - } const f3AddToMPQ = spawnSync( @@ -239,7 +244,6 @@ const installOnDirectory = async () => { } } - function setLanguage(file, language) { let data = fs.readFileSync(file, 'utf8'); const searchFor = /string language = "([^"]*)"/; diff --git a/Electron/app/main.ts b/Electron/app/main.ts index 6d045bc0f..e338a70dd 100644 --- a/Electron/app/main.ts +++ b/Electron/app/main.ts @@ -1,4 +1,4 @@ -import {app, BrowserWindow, dialog, Menu, screen } from 'electron'; +import { app, BrowserWindow, dialog, Menu, screen } from 'electron'; import * as path from 'path'; import * as fs from 'fs'; import * as remote from '@electron/remote/main'; @@ -6,9 +6,17 @@ import { InstallModel } from '../commons/models'; const ipcMain = require('electron').ipcMain; const cp = require('child_process'); +type Settings = { + TFT_PATH?: string | null; + ROC_PATH?: string | null; + REFORGED_PATH?: string | null; + [key: string]: any; +}; + let win: BrowserWindow = null; -let translations : { [key: string]: string } = {}; +let translations: { [key: string]: string } = {}; let currentLanguage: string = "English"; +const documentsPath = app.getPath('documents'); const args = process.argv.slice(1), serve = args.some(val => val === '--serve'); @@ -23,15 +31,15 @@ const isDev = () => { } const createWindow = (): BrowserWindow => { - const size = screen.getPrimaryDisplay().workAreaSize; - // Create the browser window. win = new BrowserWindow({ x: 0, y: 0, width: size.width, height: size.height, + minWidth: 1280, + minHeight: 940, webPreferences: { devTools: true, nodeIntegration: true, @@ -74,18 +82,59 @@ const createWindow = (): BrowserWindow => { return win; } -const execInstall = async (signal, commander: number = 1, isMap: boolean = false, ver: string = "REFORGED", forceLang: boolean) => { +const getversionpath = (pathver: string, settings: Settings): string => { + win.webContents.send('on-install-console', `get version path : ${JSON.stringify(settings)}, settings path : ${settings[`${pathver}_PATH`]}`); + if (pathver == "REFORGED") { + return settings.REFORGED_PATH || ''; + } else if (pathver == "TFT") { + return settings.TFT_PATH || ''; + } else if (pathver == "ROC") { + return settings.ROC_PATH || ''; + } + return ''; +} + +const execInstall = async (signal, commander: number = 1, isMap: boolean = false, ver: string = "REFORGED", forceLang: boolean, pathver: string = "REFORGED") => { const controller = new AbortController(); - const response = dialog.showOpenDialogSync(win, { - // TODO: add i18n here - title : isMap ? translations["PAGES.ELECTRON.OPEN_MAP"] || '': translations["PAGES.ELECTRON.OPEN_DIR"] || '', - // TODO: Change to let multiples selections when is map - properties: isMap ? ['openFile'] : ['openDirectory'], - // TODO: add i18n here - filters: isMap ? [ - { name: translations["PAGES.ELECTRON.MAPFILE"] || '', extensions: ['w3x', 'w3m'] }, - ] : null, - }); + let response; + const settingsPath = path.join(app.getPath('userData'), 'settings.json'); + let settings: Settings = {}; + let usepath = null; + if (fs.existsSync(settingsPath)) { + settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); + usepath = getversionpath(pathver, settings); + win.webContents.send('on-install-console', `${pathver} default path : ${usepath}`); + } + if (usepath !== null && usepath !== undefined && usepath !== '') { + if (isMap) { + response = dialog.showOpenDialogSync(win, { + title: translations["PAGES.ELECTRON.OPEN_MAP"] || '', + properties: ['openFile'] , + filters: [ + { name: translations["PAGES.ELECTRON.MAPFILE"] || '', extensions: ['w3x', 'w3m'] }, + ], + defaultPath: usepath, + }); + if (response && (response?.length > 0)) { + usepath = null; // wait updata path , maybe selected other path + } + } else { + response = [usepath]; + } + } else { + win.webContents.send('on-install-console', 'Choose path'); + response = dialog.showOpenDialogSync(win, { + // TODO: add i18n here + title: isMap ? translations["PAGES.ELECTRON.OPEN_MAP"] || '': translations["PAGES.ELECTRON.OPEN_DIR"] || '', + // TODO: Change to let multiples selections when is map + properties: isMap ? ['openFile'] : ['openDirectory'], + // TODO: add i18n here + filters: isMap ? [ + { name: translations["PAGES.ELECTRON.MAPFILE"] || '', extensions: ['w3x', 'w3m'] }, + ] : null, + defaultPath: documentsPath, + }); + } let child; @@ -95,7 +144,7 @@ const execInstall = async (signal, commander: number = 1, isMap: boolean = false let currentExecDir = `./AMAI-release/`, currentScriptDir = './AMAI-release/'; - if(!isDev()) { + if (!isDev()) { currentExecDir = `./AMAI/`; currentScriptDir = path.join( __dirname, @@ -116,11 +165,23 @@ const execInstall = async (signal, commander: number = 1, isMap: boolean = false // win.webContents.send('on-install-message', 'currentExecDir: ' + currentExecDir); // win.webContents.send('on-install-message', `install js path: ../${currentExecDir}install.js`); - if(!response || (response?.length === 0)) { + if (!response || (response?.length === 0)) { win.webContents.send('on-install-empty'); return; } + if (usepath === null) { + if (!isMap) { + usepath = response[0]; + } else { + usepath = path.dirname(response[0]); + } + const finalPath = usepath ? path.resolve(usepath) : null; + settings[`${pathver}_PATH`] = finalPath; + fs.writeFileSync(settingsPath, JSON.stringify(settings)); + win.webContents.send('on-install-console', `Default path updated to: ${finalPath}`); + win.webContents.send('path-updated', { pathver: pathver, path: finalPath }); + } // open modal on front win.webContents.send('on-install-init', { response: response[0], @@ -132,14 +193,13 @@ const execInstall = async (signal, commander: number = 1, isMap: boolean = false // MPQEditor and AddToMPQ only work when files and folders are in same directory try { process.chdir(currentScriptDir); - } catch(err) { + } catch (err) { console.log('error:', err.message); /** uncomment to debbug */ // win.webContents.send('on-install-message', 'Error: ' + err.message); } - // init install proccess try { child = cp.fork( @@ -156,26 +216,89 @@ const execInstall = async (signal, commander: number = 1, isMap: boolean = false } ); - // send messages to modal on front child.on('message', (message) => { - win.webContents.send('on-install-message', message); + if (typeof message === 'object' && message.type === 'progress') { + // Send progress updates via dedicated channel + console.log('progress:', message); + win.webContents.send('on-install-progress', message); + } else { + // Send regular messages via standard channel + win.webContents.send('on-install-message', message); + } }); // close modal on process finishes child.on('exit', () => { win.webContents.send('on-install-exit'); }); - } catch(err) { + } catch (err) { win.webContents.send('on-install-error', err.message); } } +const GetDefaultPath = () => { + ipcMain?.handle('load-path', async (_) => { + const settingsPath = path.join(app.getPath('userData'), 'settings.json'); + let settings: Settings = {}; + if (fs.existsSync(settingsPath)) { + settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); + win.webContents.send('on-install-console',`Loaded paths : REFORGED : ${settings.REFORGED_PATH} , TFT : ${settings.TFT_PATH} , ROC : ${settings.ROC_PATH}`); + return { REFORGED_PATH: settings.REFORGED_PATH || null, TFT_PATH: settings.TFT_PATH || null, ROC_PATH: settings.ROC_PATH || null }; + } + win.webContents.send('on-install-console', `Loading path file failed , using defaults`); + return { REFORGED_PATH: null, TFT_PATH: null, ROC_PATH: null }; + }); +} + +const SetDefaultPath = () => { + ipcMain?.on('set-path-and-install', async (_event, toFolder: boolean, commander: number, optimize: boolean, forceLang: boolean, pathver: string = "REFORGED") => { + const settingsPath = path.join(app.getPath('userData'), 'settings.json'); + let settings: Settings = {}; + let usepath = documentsPath; + let result; + let signal = {}; + win.webContents.send('on-install-console', `Selecting path and install , version : ${pathver}`); + if (toFolder) { + if (fs.existsSync(settingsPath)) { + win.webContents.send('on-install-console', `Get default path`); + settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); + usepath = getversionpath(pathver, settings); + if (!usepath || usepath === '' || usepath === null || !fs.existsSync(usepath)) { + usepath = documentsPath; + } + } + result = dialog.showOpenDialogSync(win, { + title: translations["PAGES.ELECTRON.OPEN_DIR"] || '', + properties: ['openDirectory'], + defaultPath: usepath + }); + if (result && (result?.length > 0)) { + usepath = result[0] ? path.resolve(result[0]) : documentsPath; + settings[`${pathver}_PATH`] = usepath; + win.webContents.send('on-install-console', `Set path : ${usepath}`); + try { + fs.writeFileSync(settingsPath, JSON.stringify(settings)); + win.webContents.send('path-updated', { pathver: pathver, path: usepath }); + execInstall(signal, commander, !toFolder, optimize ? `OPT${pathver}` : pathver, forceLang, pathver); + } catch (err) { + win.webContents.send('on-install-console', `Set path failed: ${err.message}`); + } + } else { + win.webContents.send('on-install-console', `Path selection was cancelled`); + } + } else { + execInstall(signal, commander, !toFolder, optimize ? `OPT${pathver}` : pathver, forceLang, pathver); + } + }); +} + const installProcess = () => { let signal = {}; - ipcMain?.on('install', async (_event, ver: string, toFolder: boolean, commander: number, optimize: boolean, forceLang : boolean) => { - execInstall(signal, commander, !toFolder, optimize ? `OPT${ver}` : ver, forceLang); + ipcMain?.on('install', async (_event, ver: string, toFolder: boolean, commander: number, optimize: boolean, forceLang: boolean) => { + const pathver = ver; + execInstall(signal, commander, !toFolder, optimize ? `OPT${ver}` : ver, forceLang, pathver); }); // TODO: stop process with signal @@ -268,3 +391,5 @@ const installTrans = () => { init(); installTrans(); installProcess(); +GetDefaultPath(); +SetDefaultPath(); \ No newline at end of file diff --git a/Electron/package-lock.json b/Electron/package-lock.json index f14696df2..679260ec9 100644 --- a/Electron/package-lock.json +++ b/Electron/package-lock.json @@ -19099,9 +19099,9 @@ "optional": true }, "node_modules/rollup": { - "version": "3.29.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", - "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -37206,9 +37206,9 @@ } }, "rollup": { - "version": "3.29.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", - "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", "dev": true, "requires": { "fsevents": "~2.3.2" diff --git a/Electron/package.json b/Electron/package.json index e9bcc5ab3..0cb928b59 100644 --- a/Electron/package.json +++ b/Electron/package.json @@ -46,7 +46,7 @@ "ip": "2.0.1", "tough-cookie": "4.1.3", "xml2js": "0.5.0", - "rollup": "3.29.5", + "rollup": "3.30.0", "body-parser": "1.20.3", "braces": "3.0.3", "ws": "8.17.1", diff --git a/Electron/src/app/app.component.ts b/Electron/src/app/app.component.ts index 289b43199..f571e0041 100644 --- a/Electron/src/app/app.component.ts +++ b/Electron/src/app/app.component.ts @@ -14,12 +14,15 @@ export class AppComponent implements AfterViewChecked { public active = false; public couldClose = false; public messages = []; + public currentFile = 0; + public totalFiles = 0; + public installingText = ''; - @ViewChild('logareawrapper') private readonly logContainer: ElementRef; - - ngAfterViewChecked() { this.scrollToBottom(); } - - private scrollToBottom(): void { this.logContainer.nativeElement.scrollTop = this.logContainer.nativeElement.scrollHeight; } + @ViewChild('logareawrapper') private readonly logContainer: ElementRef; + + ngAfterViewChecked() { this.scrollToBottom(); } + + private scrollToBottom(): void { this.logContainer.nativeElement.scrollTop = this.logContainer.nativeElement.scrollHeight; } constructor( private readonly electronService: ElectronService, @@ -33,27 +36,40 @@ export class AppComponent implements AfterViewChecked { // Refresh app when language changes this.translate.onDefaultLangChange.subscribe((event: LangChangeEvent) => { - this.translate.get([t_('PAGES.HOME.TITLE'),t_('PAGES.ELECTRON.OPEN_MAP'), t_('PAGES.ELECTRON.OPEN_DIR'), t_('PAGES.ELECTRON.MAPFILE')]).subscribe((translations: { [key: string]: string } ) => { + this.translate.get([t_('PAGES.HOME.TITLE'), t_('PAGES.ELECTRON.OPEN_MAP'), t_('PAGES.ELECTRON.OPEN_DIR'), t_('PAGES.ELECTRON.MAPFILE')]).subscribe((translations: { [key: string]: string }) => { this.electronService.ipcRenderer.send('Trans', event.lang, translations); }) this.cdr.detectChanges(); }); this.translate.onLangChange.subscribe((event: LangChangeEvent) => { - this.translate.get([t_('PAGES.HOME.TITLE'),t_('PAGES.ELECTRON.OPEN_MAP'), t_('PAGES.ELECTRON.OPEN_DIR'), t_('PAGES.ELECTRON.MAPFILE')]).subscribe((translations: { [key: string]: string } ) => { + this.translate.get([t_('PAGES.HOME.TITLE'), t_('PAGES.ELECTRON.OPEN_MAP'), t_('PAGES.ELECTRON.OPEN_DIR'), t_('PAGES.ELECTRON.MAPFILE')]).subscribe((translations: { [key: string]: string }) => { this.electronService.ipcRenderer.send('Trans', event.lang, translations); }) this.cdr.detectChanges(); }); - if (electronService.isElectron) { this.menuService.createMenu(); + this.electronService.ipcRenderer.on('on-install-progress', (_, args: { current: number, total: number }) => { + // console.log('totalFiles-in:', args.total, 'currentFile-in:', args.current); + if (args.total > 0 && this.totalFiles < args.total) { + this.totalFiles = args.total; + } + if (this.currentFile < this.totalFiles) { + this.currentFile++; + this.title = '(' + this.currentFile + '/' + this.totalFiles + ') ' + this.installingText; + } + // console.log('totalFiles-out:', this.totalFiles, 'currentFile-out:', this.currentFile); + this.cdr.detectChanges(); + }); + // TODO: add 'push notification'/'notification' this.electronService.ipcRenderer.on('on-install-init', (_, args: InstallModel) => { console.log('args-install-init', args) this.translate.get(t_('PAGES.APP.INSTALLING'), {path: args.response}).subscribe((res: string) => { - this.title = res + this.title = '(0/X) ' + res; + this.installingText = res; }); this.active = true; this.couldClose = false; @@ -77,16 +93,19 @@ export class AppComponent implements AfterViewChecked { console.log('args-install-empty', args); this.active = false; this.couldClose = true; + this.totalFiles = 0; + this.currentFile = 0; this.cdr.detectChanges(); }); // TODO: add 'push notification'/'notification' this.electronService.ipcRenderer.on('on-install-exit', (_, args) => { this.translate.get(t_('PAGES.APP.INSTALL_DONE')).subscribe((res: string) => { - this.title = res; + this.title = '(' + this.currentFile + '/' + this.totalFiles + ')' + ' ' + res; }); this.couldClose = true; - + this.totalFiles = 0; + this.currentFile = 0; this .menuService .changeEnabledMenuState(true); @@ -100,11 +119,17 @@ export class AppComponent implements AfterViewChecked { this.cdr.detectChanges(); }); + this.electronService.ipcRenderer.on('on-install-console', (_, args) => { + console.log('args-install-console', args); // just console + this.cdr.detectChanges(); + }); + // TODO: add 'push notification'/'notification' this.electronService.ipcRenderer.on('on-install-error', (_, args) => { console.log('args-install-error', args); this.couldClose = true; - + this.totalFiles = 0; + this.currentFile = 0; this .menuService .changeEnabledMenuState(true); @@ -118,7 +143,7 @@ export class AppComponent implements AfterViewChecked { } public closeCmd() { - if (this.couldClose) { + if (this.couldClose) { this.active = false; } } diff --git a/Electron/src/app/home/home.component.html b/Electron/src/app/home/home.component.html index 0711661b8..bd3890a2c 100644 --- a/Electron/src/app/home/home.component.html +++ b/Electron/src/app/home/home.component.html @@ -4,50 +4,91 @@

{{ 'PAGES.HOME.CHOOSE_GAME_VERSION' | translate }}
-
- REFSelected - REF - 1.33+ - Optimal:2.0.4 +
+
+ REFSelected + REF + 2.0.3+ + {{ 'PAGES.HOME.BEST_GAME_VERSION' | translate }}: 2.0.4+ +
+
+ {{gamePaths.REFORGED.displayText}} + edit +
+ {{ 'PAGES.HOME.SELECT_PATH' | translate }}
{{ gamePaths.REFORGED.displayText }} +
+
-
- TFTSelected - TFT - 1.24+ - Optimal:1.24-1.28 +
+
+ TFTSelected + TFT + 1.24e+ + {{ 'PAGES.HOME.BEST_GAME_VERSION' | translate }}: 1.24e ~ 1.28 +
+
+ {{gamePaths.TFT.displayText}} + edit +
+ {{ 'PAGES.HOME.SELECT_PATH' | translate }}
{{ gamePaths.TFT.displayText }} +
+
-
- ROCSelected - ROC - 1.24 - 1.31 - Optimal:1.24-1.28 +
+
+ ROCSelected + ROC + 1.24e+ ~ 1.31 + {{ 'PAGES.HOME.BEST_GAME_VERSION' | translate }}: 1.24e ~ 1.31 +
+
+ {{gamePaths.ROC.displayText}} + edit +
+ {{ 'PAGES.HOME.SELECT_PATH' | translate }}
{{ gamePaths.ROC.displayText }} +
+
-
{{ 'PAGES.HOME.ADVANCED_SETTING' | translate }}
-
+
+
-
+
-
+
\ No newline at end of file diff --git a/Electron/src/app/home/home.component.scss b/Electron/src/app/home/home.component.scss index 1529c2215..61d7cb711 100644 --- a/Electron/src/app/home/home.component.scss +++ b/Electron/src/app/home/home.component.scss @@ -1,223 +1,316 @@ :host { - :root { - --switch-width: 300px; /* 最大宽度 */ - } + :root { + --switch-width: 300px; /* 最大宽度 */ + } - .center-container { - text-align: center; - justify-content: center; - align-items: center; - margin: auto; - max-width: 100%; - } + .center-container { + text-align: center; + justify-content: center; + align-items: center; + margin: auto; + max-width: 100%; + } - .container { - color: white; - } + .container { + color: white; + } - .headtitle-text { - text-align: center; - font-size: 2rem; - font-weight: bold; - } + .headtitle-text { + text-align: center; + font-size: 2rem; + font-weight: bold; + } - .subtitle-text { - text-align: center; - font-size: 2rem; - font-weight: bold; - margin-top: 4rem; - } + .subtitle-text { + text-align: center; + font-size: 2rem; + font-weight: bold; + margin-top: 4rem; + } + .ContainerLattice { + display: flex; + text-align: center; + justify-content: space-around; + align-items: center; + max-width: inherit; /* 继承父元素(.center-container)的最大宽度 */ + width: 100%; + gap: 10px; + margin-top: 1.8rem; + } - .ContainerLattice { - display: flex; - text-align: center; - justify-content: space-around; - align-items: center; - max-width: inherit; /* 继承父元素(.center-container)的最大宽度 */ - width: 100%; - gap: 10px; - margin-top: 2rem; - } + .game-version-container { + max-width: 512px; + min-width: 200px; + } - .AdvancedSettings, - .MoreSettings { - background-color: black; - } + .game-path-item { + display: flex; + align-items: center; /* 垂直居中 */ + justify-content: space-between; /* 两端对齐 */ + padding: 0.6rem; + height: 60px; + background-color: black; + border-radius: 4px; + color: white; + cursor: pointer; + transition: all 0.2s ease; + position: relative; + overflow: visible; + box-sizing: border-box; /* 确保padding不影响总宽度 */ + } - .MoreSettings { - margin-top: 1rem; - } + .tooltip { + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + background-color: #1a1a1a; + color: #ffffff; + padding: 6px 12px; + border-radius: 6px; + white-space: nowrap; + font-size: 12px; + z-index: 1000; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + pointer-events: none; + opacity: 0; + visibility: hidden; + transition: opacity 0.2s ease; + margin-top: 8px; + border: 3px solid #5c5c5c; + min-width: 200px; + max-width: 512px; + text-align: center; + word-break: break-word; /* 确保长单词也能换行 */ + line-height: 1.4; /* 增加行高提高可读性 */ + } + + .game-path-item:hover .tooltip { + opacity: 1; + visibility: visible; + } + + .game-path-item:hover { + background-color: rgb(33, 4, 251); + } + + .imageContainerROC, + .imageContainerTFT, + .imageContainerREF { + display: block; + align-items: center; + justify-content: center; + height: auto; + background-color: black; + } + + .imageContainerROC span, + .imageContainerTFT span, + .imageContainerREF span { + background-color: black; + font-size: 2rem; + } + + .reccomendations { + font-size: 14pt; + display: block; + color: gold; + } + + .underlined-path { + text-decoration: underline; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; + position: relative; + font-size: 14pt; + flex-grow: 1; + box-sizing: border-box; + min-width: 0; /* 允许在flex容器中缩小 */ + } + + .icon-handle { + font-size: 14pt; + cursor: pointer; + margin-right: 0.4rem; + } + + .ContainerLattice-AdvancedSettings { + background-color: black; + display: flex; + text-align: center; + justify-content: space-around; + align-items: center; /* 垂直居中 */ + height: 48px; + margin-top: 1.4rem; + max-width: inherit; /* 继承父元素(.center-container)的最大宽度 */ + width: 100%; + } + + .ContainerLattice-MoreSettings { + background-color: black; + display: flex; + text-align: center; + justify-content: space-around; + align-items: center; + height: 48px; + margin-top: 1.8rem; + max-width: inherit; /* 继承父元素(.center-container)的最大宽度 */ + width: 100%; + } - .imageContainerROC, - .imageContainerTFT, - .imageContainerREF { - display: block; - align-items: center; - justify-content: center; - max-width: 512px; - width: 50%; - height: auto; - background-color: black; - min-width: 200px; + @media (max-width: 800px) { /* 当屏幕宽度小于等于800px时,减小字体大小 */ + .headtitle-text, + .subtitle-text { + font-size: 1rem; } .imageContainerROC span, .imageContainerTFT span, .imageContainerREF span { - background-color: black; - font-size: 2rem; + font-size: 1rem; } .reccomendations { - font-size: 14pt; - display: block; - color: gold; + font-size: 10pt; } - /* 当屏幕宽度小于等于800px时,减小字体大小 */ - @media (max-width: 800px) { - .headtitle-text, .subtitle-text { - font-size: 1rem; - } - - .imageContainerROC span, - .imageContainerTFT span, - .imageContainerREF span { - font-size: 1rem; - } - - .reccomendations { - font-size: 10pt; - } + .underlined-path { + font-size: 10pt; } - @media (max-width: 1600px) { - .ContainerLattice img { - width: 100%; - } + .icon-handle { + font-size: 10pt; } + } - .commander-group { - display: flex; - justify-content: center; - text-align: start; - align-items: center; - position: relative; - cursor: pointer; - width: 30%; - font-size: 1rem; - transform: scale(1.5); - min-width: 200px; + @media (max-width: 1600px) { + .ContainerLattice img { + width: 100%; } + } - .checkboxbj { - display: flex; - justify-content: center; - text-align: start; - align-items: center; - position: relative; - cursor: pointer; - width: 30%; - font-size: 1rem; - transform: scale(1.5); - min-width: 200px; - padding: 4px 10px; - border-radius: 12px; - background-color: black; - color: #FFFFFF; - } +.switch { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + position: relative; + max-width: var(--switch-width); + width: 36%; + height: 48px; + border: 3px solid #5c5c5c; /* 添加边框 */ + box-sizing: border-box; /* 包含边框和内填充在内的总宽度 */ + border-radius: 26px; + min-width: 400px; +} - .radio-btn { - display: inline-flex; /* 使用 flex 布局来更好地控制内部元素 */ - align-items: center; /* 垂直居中文本 */ - justify-content: center; /* 水平居中文本 */ - padding: 4px 10px; /* 内边距,根据需要调整 */ - border-radius: 12px; /* 圆角 */ - font-weight: bold; - background-color: #AAAAAA; /* 未选中时背景色 */ - cursor: pointer; /* 鼠标悬停时显示指针 */ - transition: background-color 0.3s, font-size 0.3s; /* 背景色变化过渡效果和字体大小变化过渡效果 */ - // width: 220px; /* 固定宽度 */ - white-space: nowrap; /* 防止文本换行 */ - overflow: visible; /* 隐藏超出部分 */ - text-overflow: ellipsis; /* 显示省略号 */ - box-sizing: border-box; /* 包含padding和border */ - font-size: calc(100% - 2px); /* 初始字体大小 */ - max-width: 100%; /* 最大宽度 */ - } +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgb(33, 4, 251); + border-radius: 26px; + -webkit-transition: .4s; + transition: .4s; + color: #ffffff; + font-size: 1rem; + font-weight: bold; + display: flex; + align-items: center; + justify-content: space-around; +} - /* 鼠标悬停样式 */ - .radio-btn:hover { - color: #FFFFFF; /* 悬停时文字颜色 */ - background-color: #47A4F9; /* 悬停时背景色 */ - } +.slider:before { + position: absolute; + display: flex; /* 将其转换为弹性布局容器 */ + align-items: center; + justify-content: center; + content: ""; + white-space: nowrap; + left: 1px; + height: 100%; + width: 50%; + background-color: #ffffff; + border-radius: 26px; + -webkit-transition: .4s; + transition: .4s; +} - input[type="radio"]:checked + .radio-btn { - background-color: rgb(33, 4, 251); /* 选中时背景色 */ - color: #FFFFFF; /* 选中时文字颜色 */ - } +input:checked + .slider { + background-color: #36b61a; +} - .switch { - display: flex; - justify-content: center; - align-items: center; - text-align: center; - position: relative; - max-width: var(--switch-width); - width: 36%; - height: 32px; - border: 3px solid #5c5c5c; /* 添加边框 */ - box-sizing: border-box; /* 包含边框和内填充在内的总宽度 */ - border-radius: 26px; - min-width: 400px; - } +input:checked + .slider:before { + content: ""; + -webkit-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); + margin-left: -1px; +} - .slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgb(33, 4, 251); - border-radius: 26px; - -webkit-transition: .4s; - transition: .4s; - - color: #ffffff; - font-size: 1rem; - font-weight: bold; - display: flex; - align-items: center; - justify-content: space-around; - } + .commander-group { + display: flex; + justify-content: center; + text-align: start; + align-items: center; + position: relative; + cursor: pointer; + width: 30%; + font-size: 1rem; + transform: scale(1.5); + min-width: 200px; + } - .slider:before { - position: absolute; - display: flex; /* 将其转换为弹性布局容器 */ - align-items: center; - justify-content: center; - content: ""; - white-space: nowrap; - left: 1px; - height: 100%; - width: 50%; - background-color: #ffffff; - border-radius: 26px; - -webkit-transition: .4s; - transition: .4s; - } + .radio-btn { + display: inline-flex; /* 使用 flex 布局来更好地控制内部元素 */ + align-items: center; /* 垂直居中文本 */ + justify-content: center; /* 水平居中文本 */ + padding: 4px 10px; /* 内边距,根据需要调整 */ + border-radius: 12px; /* 圆角 */ + font-weight: bold; + background-color: #AAAAAA; /* 未选中时背景色 */ + cursor: pointer; /* 鼠标悬停时显示指针 */ + transition: background-color 0.3s, font-size 0.3s; /* 背景色变化过渡效果和字体大小变化过渡效果 */ + width: 220px; /* 固定宽度 */ + white-space: nowrap; /* 防止文本换行 */ + overflow: hidden; /* 隐藏超出部分 */ + text-overflow: ellipsis; /* 显示省略号 */ + box-sizing: border-box; /* 包含padding和border */ + font-size: calc(100% - 2px); /* 初始字体大小 */ + max-width: 100%; /* 最大宽度 */ + } - input:checked + .slider { - background-color: #36b61a; - } + .radio-btn:hover { + color: #FFFFFF; /* 悬停时文字颜色 */ + background-color: #47A4F9; /* 悬停时背景色 */ + } + + input[type="radio"]:checked + .radio-btn { + background-color: rgb(33, 4, 251); /* 选中时背景色 */ + color: #FFFFFF; /* 选中时文字颜色 */ + } + + .checkboxbj { + display: flex; + justify-content: center; + text-align: start; + align-items: center; + position: relative; + cursor: pointer; + width: 30%; + font-size: 1rem; + transform: scale(1.5); + min-width: 200px; + padding: 4px 10px; + border-radius: 12px; + background-color: black; + color: #FFFFFF; + } - input:checked + .slider:before { - content: ""; - -webkit-transform: translateX(100%); - -ms-transform: translateX(100%); - transform: translateX(100%); - margin-left: -1px; - } } \ No newline at end of file diff --git a/Electron/src/app/home/home.component.ts b/Electron/src/app/home/home.component.ts index f57e5b9e6..aad3155b3 100644 --- a/Electron/src/app/home/home.component.ts +++ b/Electron/src/app/home/home.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild, ElementRef, HostListener, Injectable } from '@angular/core'; +import { Component, OnInit, OnDestroy , ViewChild, ElementRef, HostListener, Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { ElectronService } from '../core/services/electron/electron.service'; @@ -12,13 +12,13 @@ import { ElectronService } from '../core/services/electron/electron.service'; styleUrls: ['./home.component.scss'] }) export class HomeComponent implements OnInit { - + private pathUpdateListener: any; Images_ROC_Shown: boolean = false; - Images_TFT_Shown: boolean = false; - Images_REF_Shown: boolean = false; - ROCInstall: boolean = false; - TFTInstall: boolean = false; - REFInstall: boolean = false; + Images_TFT_Shown: boolean = false; + Images_REF_Shown: boolean = false; + ROCInstall: boolean = false; + TFTInstall: boolean = false; + REFInstall: boolean = false; Mode_State: boolean = true; BJ_State: number = 1; isInteractive: boolean = true; @@ -28,9 +28,86 @@ export class HomeComponent implements OnInit { optimize: boolean = true; forcelang: boolean = false; installEvent: string = 'install' + gamePaths = { + TFT: { + PATH: null as string | null, + displayText: '--', + }, + REFORGED: { + PATH: null as string | null, + displayText: '--', + }, + ROC: { + PATH: null as string | null, + displayText: '--', + } + }; + + constructor( + private electronService: ElectronService, + ) {} ngOnInit(): void { console.log('HomeComponent INIT'); + void this.loadDefaultPath(); + this.UpdateDefaultPath(); + } + + ngOnDestroy(): void { + if (this.pathUpdateListener) { + this.electronService.ipcRenderer.removeListener('path-updated', this.pathUpdateListener); + } + } + + private UpdateDefaultPath(): void { + this.pathUpdateListener = (event: any, { pathver, path = '' }) => { + console.log(`Path updated for ${pathver} : `, path); + if (pathver in this.gamePaths) { + this.gamePaths[pathver].PATH = path || null; + this.gamePaths[pathver].displayText = this.formatPath(path); + console.log('updated ver Path to : ', this.gamePaths[pathver].PATH, 'Display:', this.gamePaths[pathver].displayText); + } + }; + this.electronService.ipcRenderer.on('path-updated', this.pathUpdateListener); + } + + private async loadDefaultPath(): Promise { + const settings = await this.electronService.ipcRenderer.invoke('load-path'); + if (settings) { + console.log('Loaded paths settings:', settings); + this.gamePaths.TFT.PATH = settings.TFT_PATH; + this.gamePaths.REFORGED.PATH = settings.REFORGED_PATH; + this.gamePaths.ROC.PATH = settings.ROC_PATH; + this.gamePaths.TFT.displayText = this.gamePaths.TFT.PATH ? this.formatPath(this.gamePaths.TFT.PATH) : '--'; + this.gamePaths.REFORGED.displayText = this.gamePaths.REFORGED.PATH ? this.formatPath(this.gamePaths.REFORGED.PATH) : '--'; + this.gamePaths.ROC.displayText = this.gamePaths.ROC.PATH ? this.formatPath(this.gamePaths.ROC.PATH) : '--'; + console.log('REFORGED Path:', this.gamePaths.REFORGED.PATH, 'Display:', this.gamePaths.REFORGED.displayText); + console.log('TFT Path:', this.gamePaths.TFT.PATH, 'Display:', this.gamePaths.TFT.displayText); + console.log('ROC Path:', this.gamePaths.ROC.PATH, 'Display:', this.gamePaths.ROC.displayText); + } else { + console.error('Error loading paths:', settings); + } + } + + private formatPath(path: string, maxLength = 20): string { + if (!path) return '--'; + if (path.length <= maxLength) return path; + const parts = path.split(/[\\/]/); + if (parts.length <= 2) return path; + const firstPart = parts[0]; + const lastPart = parts[parts.length - 1]; + const middleLength = maxLength - (firstPart.length + lastPart.length + 5); + if (middleLength > 0) { + return `${firstPart}/.../${lastPart}`; + } + return `${firstPart}/...${lastPart}`; + } + + async selectPathAndInstall(pathver: 'REFORGED' | 'TFT' | 'ROC') { + if (this.isInteractive) { + console.log(`Selecting path and install for ${pathver}`); + this.electronService.ipcRenderer.send('set-path-and-install', this.Mode_State, this.BJ_State, this.optimize, this.forcelang, pathver); + } } @HostListener('mouseenter', ['$event', '$event.target.dataset.action']) @@ -56,7 +133,6 @@ export class HomeComponent implements OnInit { }; } - @HostListener('mouseout', ['$event', '$event.target.dataset.action']) onMouseLeave(event: MouseEvent, action: string) { if (this.isInteractive) { @@ -79,8 +155,6 @@ export class HomeComponent implements OnInit { } }; } - - @HostListener('click', ['$event', '$event.target.dataset.action']) onClick(event: MouseEvent, action: string) { @@ -89,31 +163,40 @@ export class HomeComponent implements OnInit { case 'Roc': if (!this.ROCInstall) { this.message = `install${this.modeState}${this.bjState}-ROC`; + this.Images_ROC_Shown = true; + this.Images_TFT_Shown = false; + this.Images_REF_Shown = false; this.TFTInstall = false; this.REFInstall = false; this.ROCInstall = !this.ROCInstall; this.electronService.ipcRenderer.send(this.installEvent, 'ROC', this.Mode_State, this.BJ_State, this.optimize, this.forcelang); - console.log('message',this.message); + console.log('message', this.message); } break; case 'Tft': if (!this.TFTInstall) { this.message = `install${this.modeState}${this.bjState}-TFT`; + this.Images_ROC_Shown = false; + this.Images_TFT_Shown = true; + this.Images_REF_Shown = false; this.ROCInstall = false; this.REFInstall = false; this.TFTInstall = !this.TFTInstall; this.electronService.ipcRenderer.send(this.installEvent, 'TFT', this.Mode_State, this.BJ_State, this.optimize, this.forcelang); - console.log('message',this.message); + console.log('message', this.message); } break; case 'Ref': if (!this.REFInstall) { this.message = `install${this.modeState}${this.bjState}`; + this.Images_ROC_Shown = false; + this.Images_TFT_Shown = false; + this.Images_REF_Shown = true; this.ROCInstall = false; this.TFTInstall = false; this.REFInstall = !this.REFInstall; this.electronService.ipcRenderer.send(this.installEvent, 'REFORGED', this.Mode_State, this.BJ_State, this.optimize, this.forcelang); - console.log('message',this.message); + console.log('message', this.message); } break; } @@ -132,23 +215,23 @@ export class HomeComponent implements OnInit { case 'ModeSwitch': this.Mode_State = !this.Mode_State; this.modeState = this.Mode_State ? '-folder' : '-map'; - console.log('mode',this.modeState,this.Mode_State); + console.log('mode', this.modeState, this.Mode_State); break; case 'BJoptionOn': - this.bjState = ''; - this.BJ_State = 1; - console.log('BJ',this.bjState); - break; + this.bjState = ''; + this.BJ_State = 1; + console.log('BJ', this.bjState); + break; case 'BJoptionVsAI': - this.bjState = '-vai'; - this.BJ_State = 2; - console.log('BJ',this.bjState); - break; + this.bjState = '-vai'; + this.BJ_State = 2; + console.log('BJ', this.bjState); + break; case 'BJoptionOff': - this.bjState = '-noc'; - this.BJ_State = 0; - console.log('BJ',this.bjState); - break; + this.bjState = '-noc'; + this.BJ_State = 0; + console.log('BJ', this.bjState); + break; case 'Optimise': this.optimize = !this.optimize; if (this.optimize) { @@ -160,13 +243,8 @@ export class HomeComponent implements OnInit { if (this.forcelang) { this.optimize = false; } - break; + break; } }; } - - constructor( - private router: Router, - private electronService: ElectronService, - ) { } -} +} \ No newline at end of file diff --git a/Electron/src/assets/i18n/de.json b/Electron/src/assets/i18n/de.json index 173d3d31f..502cdd212 100644 --- a/Electron/src/assets/i18n/de.json +++ b/Electron/src/assets/i18n/de.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Im Verzeichnis installieren", "INSTALL_ON_MAP": "Auf Karte installieren", "INCLUDE_COMMANDER": "Kommandant installieren", - "INCLUDE_COMMANDER_VSAI": "Gegen Vanilla KI", + "INCLUDE_COMMANDER_VSAI": "Gegen Vanilla KI", "INCLUDE_COMMANDER_OFF": "Kein Kommandant", - "OPTIMISE": "Optimierte Skripte verwenden", - "FORCELANG": "AI Chat Sprache überschreiben" + "OPTIMISE": "Optimierte Skripte verwenden", + "FORCELANG": "AI Chat Sprache überschreiben", + "BEST_GAME_VERSION": "Optimal", + "SELECT_PATH": "Standardpfad ändern und installieren" }, "APP": { "INSTALLING": "Installation in {{path}}", diff --git a/Electron/src/assets/i18n/en.json b/Electron/src/assets/i18n/en.json index 2a176ceb0..9456e25cd 100644 --- a/Electron/src/assets/i18n/en.json +++ b/Electron/src/assets/i18n/en.json @@ -4,13 +4,15 @@ "TITLE": "AMAI Installer", "CHOOSE_GAME_VERSION": "Choose Game Version", "ADVANCED_SETTING": "Advanced Settings", - "INSTALL_ON_FOLDER": "Install To Directory", + "INSTALL_ON_FOLDER": "Install To Directory", "INSTALL_ON_MAP": "Install To Map", "INCLUDE_COMMANDER": "Install Commander", "INCLUDE_COMMANDER_VSAI": "Vs Vanilla AI", "INCLUDE_COMMANDER_OFF": "No Commander", "OPTIMISE": "Use Optimised Scripts", - "FORCELANG": "Override AI Chat Language" + "FORCELANG": "Override AI Chat Language", + "BEST_GAME_VERSION": "Optimal", + "SELECT_PATH": "Change default path and install" }, "APP": { "INSTALLING": "Installing into {{path}}", diff --git a/Electron/src/assets/i18n/es.json b/Electron/src/assets/i18n/es.json index ffdf3bdc8..6d064b0a3 100644 --- a/Electron/src/assets/i18n/es.json +++ b/Electron/src/assets/i18n/es.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Instalar en el directorio", "INSTALL_ON_MAP": "Instalar en el mapa", "INCLUDE_COMMANDER": "Incluir comandante", - "INCLUDE_COMMANDER_VSAI": "Contra IA Vanilla", + "INCLUDE_COMMANDER_VSAI": "Contra IA Vanilla", "INCLUDE_COMMANDER_OFF": "Sin Comandante", - "OPTIMISE": "Usar scripts optimizados", - "FORCELANG": "Cubrir el lenguaje de chat de Ia" + "OPTIMISE": "Usar scripts optimizados", + "FORCELANG": "Cubrir el lenguaje de chat de Ia", + "BEST_GAME_VERSION": "Óptimo", + "SELECT_PATH": "Cambiar la ruta predeterminada e instalar" }, "APP": { "INSTALLING": "Instalando en {{path}}", diff --git a/Electron/src/assets/i18n/fr.json b/Electron/src/assets/i18n/fr.json index 341b472f4..e26d6ab74 100644 --- a/Electron/src/assets/i18n/fr.json +++ b/Electron/src/assets/i18n/fr.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Installer dans le répertoire", "INSTALL_ON_MAP": "Installer sur la carte", "INCLUDE_COMMANDER": "Installer le commandant", - "INCLUDE_COMMANDER_VSAI": "Contre IA Vanilla", + "INCLUDE_COMMANDER_VSAI": "Contre IA Vanilla", "INCLUDE_COMMANDER_OFF": "Pas de Commandant", - "OPTIMISE": "Utiliser des scripts optimisés", - "FORCELANG": "Couvrir le langage de chat ai" + "OPTIMISE": "Utiliser des scripts optimisés", + "FORCELANG": "Couvrir le langage de chat ai", + "BEST_GAME_VERSION": "Optimal", + "SELECT_PATH": "Modifier le chemin par défaut et installer" }, "APP": { "INSTALLING": "Installation dans {{path}}", diff --git a/Electron/src/assets/i18n/no.json b/Electron/src/assets/i18n/no.json index 370a2f190..76290f419 100644 --- a/Electron/src/assets/i18n/no.json +++ b/Electron/src/assets/i18n/no.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Installer i katalog", "INSTALL_ON_MAP": "Installer på kart", "INCLUDE_COMMANDER": "Inkluder kommandant", - "INCLUDE_COMMANDER_VSAI": "Mot Vanilla AI", + "INCLUDE_COMMANDER_VSAI": "Mot Vanilla AI", "INCLUDE_COMMANDER_OFF": "Ingen Kommandant", - "OPTIMISE": "Bruk optimaliserte skript", - "FORCELANG": "Overskriv AI-samtalespråk" + "OPTIMISE": "Bruk optimaliserte skript", + "FORCELANG": "Overskriv AI-samtalespråk", + "BEST_GAME_VERSION": "Optimal", + "SELECT_PATH": "Endre default sti og installer" }, "APP": { "INSTALLING": "Installerer i {{path}}", diff --git a/Electron/src/assets/i18n/pt.json b/Electron/src/assets/i18n/pt.json index acdbf0c2a..a90bfe9ff 100644 --- a/Electron/src/assets/i18n/pt.json +++ b/Electron/src/assets/i18n/pt.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Instalar no diretório", "INSTALL_ON_MAP": "Instalar no mapa", "INCLUDE_COMMANDER": "Incluir comandante", - "INCLUDE_COMMANDER_VSAI": "Contra IA Vanilla", + "INCLUDE_COMMANDER_VSAI": "Contra IA Vanilla", "INCLUDE_COMMANDER_OFF": "Sem Comandante", - "OPTIMISE": "Usar scripts otimizados", - "FORCELANG": "Substituir a linguagem de conversação AI" + "OPTIMISE": "Usar scripts otimizados", + "FORCELANG": "Substituir a linguagem de conversação AI", + "BEST_GAME_VERSION": "Optimal", + "SELECT_PATH": "Alterar o caminho padrão e instalar" }, "APP": { "INSTALLING": "Instalando em {{path}}", diff --git a/Electron/src/assets/i18n/ro.json b/Electron/src/assets/i18n/ro.json index 0330126b4..9b3dca028 100644 --- a/Electron/src/assets/i18n/ro.json +++ b/Electron/src/assets/i18n/ro.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Instalează în director", "INSTALL_ON_MAP": "Instalează pe hartă", "INCLUDE_COMMANDER": "Include comandant", - "INCLUDE_COMMANDER_VSAI": "Împotriva AI Vanilla", + "INCLUDE_COMMANDER_VSAI": "Împotriva AI Vanilla", "INCLUDE_COMMANDER_OFF": "Fără comandant", - "OPTIMISE": "Utilizați scripturi optimizate", - "FORCELANG": "Suprascrie limbajul de chat AI" + "OPTIMISE": "Utilizați scripturi optimizate", + "FORCELANG": "Suprascrie limbajul de chat AI", + "BEST_GAME_VERSION": "Optim", + "SELECT_PATH": "Schimbă calea implicită și instalează" }, "APP": { "INSTALLING": "Instalare în curs la {{path}}", diff --git a/Electron/src/assets/i18n/ru.json b/Electron/src/assets/i18n/ru.json index 86b1c6cc3..931b783ef 100644 --- a/Electron/src/assets/i18n/ru.json +++ b/Electron/src/assets/i18n/ru.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Установить в папку", "INSTALL_ON_MAP": "Установить на карту", "INCLUDE_COMMANDER": "Включить командира", - "INCLUDE_COMMANDER_VSAI": "Против Vanilla ИИ", + "INCLUDE_COMMANDER_VSAI": "Против Vanilla ИИ", "INCLUDE_COMMANDER_OFF": "Без командира", - "OPTIMISE": "Использовать оптимизированные скрипты", - "FORCELANG": "Скачать язык разговора" + "OPTIMISE": "Использовать оптимизированные скрипты", + "FORCELANG": "Скачать язык разговора", + "BEST_GAME_VERSION": "Оптимальный", + "SELECT_PATH": "Изменить путь по умолчанию и установить" }, "APP": { "INSTALLING": "Установка в {{path}}", diff --git a/Electron/src/assets/i18n/sv.json b/Electron/src/assets/i18n/sv.json index 084909b1e..ff0d3c8f0 100644 --- a/Electron/src/assets/i18n/sv.json +++ b/Electron/src/assets/i18n/sv.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "Installera i katalog", "INSTALL_ON_MAP": "Installera på karta", "INCLUDE_COMMANDER": "Inkludera befälhavare", - "INCLUDE_COMMANDER_VSAI": "Mot Vanilla AI", + "INCLUDE_COMMANDER_VSAI": "Mot Vanilla AI", "INCLUDE_COMMANDER_OFF": "Ingen befälhavare", - "OPTIMISE": "Använd optimerade skript", - "FORCELANG": "Skriv över AI-chattspråk" + "OPTIMISE": "Använd optimerade skript", + "FORCELANG": "Skriv över AI-chattspråk", + "BEST_GAME_VERSION": "Optimalt", + "SELECT_PATH": "Ändra standardsökväg och installera" }, "APP": { "INSTALLING": "Installerar i {{path}}", diff --git a/Electron/src/assets/i18n/zh.json b/Electron/src/assets/i18n/zh.json index 6107cf9fd..819d005d9 100644 --- a/Electron/src/assets/i18n/zh.json +++ b/Electron/src/assets/i18n/zh.json @@ -7,10 +7,12 @@ "INSTALL_ON_FOLDER": "按文件夹安装", "INSTALL_ON_MAP": "按地图安装", "INCLUDE_COMMANDER": "安装控制台", - "INCLUDE_COMMANDER_VSAI": "AMAI VS 暴雪AI", + "INCLUDE_COMMANDER_VSAI": "AMAI VS 暴雪AI 控制台", "INCLUDE_COMMANDER_OFF": "不安装控制台", - "OPTIMISE": "使用优化脚本", - "FORCELANG": "覆盖AI聊天语言" + "OPTIMISE": "使用优化脚本", + "FORCELANG": "覆盖AI聊天语言", + "BEST_GAME_VERSION": "最佳版本", + "SELECT_PATH": "变更默认路径并安装" }, "APP": { "INSTALLING": "正在安装 {{path}}",