mirror of
https://github.com/hansjone/netx.git
synced 2026-10-13 08:30:45 +08:00
Make Windows Setup bilingual, offline-capable, and use NetX branding.
Ship WinSW + icon assets, default first-run without network, EN/ZH installer UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6603afd007
commit
b016037270
12 changed files with 622 additions and 47 deletions
|
|
@ -17,6 +17,10 @@ This directory builds a Windows deliverable with:
|
||||||
| `NetX-x.y.z-win64.zip` | `build_release.ps1` |
|
| `NetX-x.y.z-win64.zip` | `build_release.ps1` |
|
||||||
| `NetX-Setup-x.y.z.exe` | Compile `installer/netx.iss` with [Inno Setup](https://jrsoftware.org/isinfo.php) after staging |
|
| `NetX-Setup-x.y.z.exe` | Compile `installer/netx.iss` with [Inno Setup](https://jrsoftware.org/isinfo.php) after staging |
|
||||||
|
|
||||||
|
**Installer:** English + 简体中文 (language dialog). Icons use `packaging/assets/netx.ico`.
|
||||||
|
|
||||||
|
**Offline:** Setup ships portable PostgreSQL, `.venv` (when built with `-CreateVenv`), and WinSW. First-run uses `-NonInteractive -DbMode bundled` — **no GitHub/EDB download on the target PC**. Service install uses bundled WinSW (pass `-AllowDownload` only on a build/dev machine if the binary is missing). Auto-update still needs network later, and is unchecked by default.
|
||||||
|
|
||||||
## Build (developer machine)
|
## Build (developer machine)
|
||||||
|
|
||||||
Prerequisites: Python 3.11+, Node 20+, PowerShell, network (to download PG binaries once).
|
Prerequisites: Python 3.11+, Node 20+, PowerShell, network (to download PG binaries once).
|
||||||
|
|
|
||||||
6
packaging/assets/README.md
Normal file
6
packaging/assets/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# NetX packaging assets
|
||||||
|
|
||||||
|
- `netx.ico` — installer / shortcuts / tray (regenerate with `python gen_icon.py`)
|
||||||
|
- `netx-256.png` / `netx-64.png` — previews
|
||||||
|
|
||||||
|
Mark matches `web/public/favicon.svg` (network “N” nodes on navy).
|
||||||
56
packaging/assets/gen_icon.py
Normal file
56
packaging/assets/gen_icon.py
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
"""Generate NetX Windows .ico from brand mark (matches web/public/favicon.svg)."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
OUT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
BG = (15, 39, 68, 255)
|
||||||
|
LINE = (126, 182, 232, 255)
|
||||||
|
NODE = (232, 242, 252, 255)
|
||||||
|
ACCENT = (61, 130, 247, 255)
|
||||||
|
|
||||||
|
|
||||||
|
def make(size: int) -> Image.Image:
|
||||||
|
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
radius = max(2, int(size * 0.22))
|
||||||
|
d.rounded_rectangle([0, 0, size - 1, size - 1], radius=radius, fill=BG)
|
||||||
|
s = size / 32.0
|
||||||
|
|
||||||
|
def xy(x: float, y: float) -> tuple[float, float]:
|
||||||
|
return (x * s, y * s)
|
||||||
|
|
||||||
|
stroke = max(2, int(round(2.2 * s)))
|
||||||
|
for a, b in (
|
||||||
|
(xy(9.5, 8.5), xy(9.5, 23.5)),
|
||||||
|
(xy(9.5, 8.5), xy(22.5, 23.5)),
|
||||||
|
(xy(22.5, 8.5), xy(22.5, 23.5)),
|
||||||
|
):
|
||||||
|
d.line([a, b], fill=LINE, width=stroke)
|
||||||
|
|
||||||
|
def circle(cx: float, cy: float, rad: float, fill: tuple[int, int, int, int]) -> None:
|
||||||
|
x, y = xy(cx, cy)
|
||||||
|
rr = rad * s
|
||||||
|
d.ellipse([x - rr, y - rr, x + rr, y + rr], fill=fill)
|
||||||
|
|
||||||
|
circle(9.5, 8.5, 2.35, NODE)
|
||||||
|
circle(9.5, 23.5, 2.35, NODE)
|
||||||
|
circle(22.5, 8.5, 2.35, NODE)
|
||||||
|
circle(22.5, 23.5, 2.35, NODE)
|
||||||
|
circle(16, 16, 1.7, ACCENT)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
sizes = [16, 24, 32, 48, 64, 128, 256]
|
||||||
|
images = [make(s) for s in sizes]
|
||||||
|
ico_path = os.path.join(OUT_DIR, "netx.ico")
|
||||||
|
images[-1].save(ico_path, format="ICO", sizes=[(s, s) for s in sizes])
|
||||||
|
images[-1].save(os.path.join(OUT_DIR, "netx-256.png"))
|
||||||
|
make(64).save(os.path.join(OUT_DIR, "netx-64.png"))
|
||||||
|
print(f"wrote {ico_path} ({os.path.getsize(ico_path)} bytes)")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
BIN
packaging/assets/netx-256.png
Normal file
BIN
packaging/assets/netx-256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
packaging/assets/netx-64.png
Normal file
BIN
packaging/assets/netx-64.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 575 B |
BIN
packaging/assets/netx.ico
Normal file
BIN
packaging/assets/netx.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -51,6 +51,20 @@ if (-not $SkipPostgresDownload) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Bundle WinSW so offline installs can register a Windows Service without GitHub.
|
||||||
|
$winswCache = Join-Path $PSScriptRoot "cache\WinSW-x64.exe"
|
||||||
|
$winswShip = Join-Path $PSScriptRoot "winsw\WinSW-x64.exe"
|
||||||
|
if (-not (Test-Path $winswShip)) {
|
||||||
|
if (-not (Test-Path $winswCache)) {
|
||||||
|
$winswUrl = "https://github.com/winsw/winsw/releases/download/v2.12.0/WinSW-x64.exe"
|
||||||
|
Write-Host "==> Downloading WinSW for offline bundle: $winswUrl"
|
||||||
|
New-Item -ItemType Directory -Path (Split-Path $winswCache -Parent) -Force | Out-Null
|
||||||
|
Invoke-WebRequest -Uri $winswUrl -OutFile $winswCache -UseBasicParsing
|
||||||
|
}
|
||||||
|
New-Item -ItemType Directory -Path (Split-Path $winswShip -Parent) -Force | Out-Null
|
||||||
|
Copy-Item -Path $winswCache -Destination $winswShip -Force
|
||||||
|
}
|
||||||
|
|
||||||
# Flat layout = same as repo so scripts\start_netx.ps1 works unchanged.
|
# Flat layout = same as repo so scripts\start_netx.ps1 works unchanged.
|
||||||
foreach ($d in @("netx_api", "alembic", "scripts")) {
|
foreach ($d in @("netx_api", "alembic", "scripts")) {
|
||||||
Copy-Item -Path (Join-Path $repo $d) -Destination (Join-Path $stage $d) -Recurse -Force
|
Copy-Item -Path (Join-Path $repo $d) -Destination (Join-Path $stage $d) -Recurse -Force
|
||||||
|
|
@ -81,13 +95,36 @@ foreach ($name in @(
|
||||||
}
|
}
|
||||||
Copy-Item -Path (Join-Path $PSScriptRoot "config") -Destination (Join-Path $packOut "config") -Recurse -Force
|
Copy-Item -Path (Join-Path $PSScriptRoot "config") -Destination (Join-Path $packOut "config") -Recurse -Force
|
||||||
Copy-Item -Path (Join-Path $PSScriptRoot "installer") -Destination (Join-Path $packOut "installer") -Recurse -Force
|
Copy-Item -Path (Join-Path $PSScriptRoot "installer") -Destination (Join-Path $packOut "installer") -Recurse -Force
|
||||||
|
$assetsSrc = Join-Path $PSScriptRoot "assets"
|
||||||
|
if (Test-Path $assetsSrc) {
|
||||||
|
Copy-Item -Path $assetsSrc -Destination (Join-Path $packOut "assets") -Recurse -Force
|
||||||
|
}
|
||||||
|
$winswOut = Join-Path $packOut "winsw"
|
||||||
|
New-Item -ItemType Directory -Path $winswOut -Force | Out-Null
|
||||||
|
if (Test-Path $winswShip) {
|
||||||
|
Copy-Item -Path $winswShip -Destination (Join-Path $winswOut "WinSW-x64.exe") -Force
|
||||||
|
Write-Host "==> Bundled WinSW for offline service install"
|
||||||
|
} else {
|
||||||
|
Write-Host "[WARN] WinSW missing — offline service install will fail" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
New-Item -ItemType Directory -Path (Join-Path $packOut "postgres") -Force | Out-Null
|
New-Item -ItemType Directory -Path (Join-Path $packOut "postgres") -Force | Out-Null
|
||||||
Copy-Item -Path (Join-Path $PSScriptRoot "postgres\README.md") -Destination (Join-Path $packOut "postgres\README.md") -Force
|
Copy-Item -Path (Join-Path $PSScriptRoot "postgres\README.md") -Destination (Join-Path $packOut "postgres\README.md") -Force
|
||||||
|
|
||||||
if (Test-Path (Join-Path $pgsql "bin\pg_ctl.exe")) {
|
if (Test-Path (Join-Path $pgsql "bin\pg_ctl.exe")) {
|
||||||
Write-Host "==> Copying bundled PostgreSQL"
|
Write-Host "==> Copying bundled PostgreSQL (bin/lib/share; skip doc/)"
|
||||||
New-Item -ItemType Directory -Path (Join-Path $stage "postgres") -Force | Out-Null
|
$pgStage = Join-Path $stage "postgres\pgsql"
|
||||||
Copy-Item -Path $pgsql -Destination (Join-Path $stage "postgres\pgsql") -Recurse -Force
|
New-Item -ItemType Directory -Path $pgStage -Force | Out-Null
|
||||||
|
foreach ($sub in @("bin", "lib", "share")) {
|
||||||
|
$srcSub = Join-Path $pgsql $sub
|
||||||
|
if (Test-Path $srcSub) {
|
||||||
|
Copy-Item -Path $srcSub -Destination (Join-Path $pgStage $sub) -Recurse -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Get-ChildItem -Path $pgsql -File -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
Copy-Item -Path $_.FullName -Destination (Join-Path $pgStage $_.Name) -Force
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw "bundled_postgres_missing: Setup.exe must ship postgres for offline install. Run download_postgres.ps1 (build machine only)."
|
||||||
}
|
}
|
||||||
|
|
||||||
$builtAt = (Get-Date).ToUniversalTime().ToString("o")
|
$builtAt = (Get-Date).ToUniversalTime().ToString("o")
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,14 @@ param(
|
||||||
[ValidateSet("winsw", "task")]
|
[ValidateSet("winsw", "task")]
|
||||||
[string]$Mode = "winsw",
|
[string]$Mode = "winsw",
|
||||||
[switch]$Uninstall = $false,
|
[switch]$Uninstall = $false,
|
||||||
[switch]$Start = $false
|
[switch]$Start = $false,
|
||||||
|
# Offline-safe by default: use WinSW shipped in the package. Opt-in to download from GitHub.
|
||||||
|
[switch]$AllowDownload = $false
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install NetX as a Windows Service (WinSW) or as a SYSTEM startup Scheduled Task.
|
# Install NetX as a Windows Service (WinSW) or as a SYSTEM startup Scheduled Task.
|
||||||
# Requires elevation for winsw / task modes that run as SYSTEM.
|
# Requires elevation for winsw / task modes that run as SYSTEM.
|
||||||
|
# WinSW binary is bundled at packaging\winsw\WinSW-x64.exe by build_release.ps1 — no network needed.
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
. "$PSScriptRoot\_common.ps1"
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
@ -38,13 +41,24 @@ function Ensure-WinSW {
|
||||||
if (-not (Test-Path $cacheDir)) {
|
if (-not (Test-Path $cacheDir)) {
|
||||||
New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null
|
New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
$bundled = Join-Path $PSScriptRoot "winsw\WinSW-x64.exe"
|
||||||
$dl = Join-Path $cacheDir "WinSW-x64.exe"
|
$dl = Join-Path $cacheDir "WinSW-x64.exe"
|
||||||
if (-not (Test-Path $dl)) {
|
$src = $null
|
||||||
|
if (Test-Path $bundled) {
|
||||||
|
$src = $bundled
|
||||||
|
Write-Host "==> Using bundled WinSW: $bundled"
|
||||||
|
} elseif (Test-Path $dl) {
|
||||||
|
$src = $dl
|
||||||
|
Write-Host "==> Using cached WinSW: $dl"
|
||||||
|
} elseif ($AllowDownload) {
|
||||||
$url = "https://github.com/winsw/winsw/releases/download/v2.12.0/WinSW-x64.exe"
|
$url = "https://github.com/winsw/winsw/releases/download/v2.12.0/WinSW-x64.exe"
|
||||||
Write-Host "==> Downloading WinSW: $url"
|
Write-Host "==> Downloading WinSW: $url"
|
||||||
Invoke-WebRequest -Uri $url -OutFile $dl -UseBasicParsing
|
Invoke-WebRequest -Uri $url -OutFile $dl -UseBasicParsing
|
||||||
|
$src = $dl
|
||||||
|
} else {
|
||||||
|
throw "winsw_missing_offline: expected $bundled (rebuild with build_release.ps1). Or pass -AllowDownload when online."
|
||||||
}
|
}
|
||||||
Copy-Item -Path $dl -Destination $winswExe -Force
|
Copy-Item -Path $src -Destination $winswExe -Force
|
||||||
|
|
||||||
$runPs1 = ConvertTo-WinSWPath (Join-Path $PSScriptRoot "service_run.ps1")
|
$runPs1 = ConvertTo-WinSWPath (Join-Path $PSScriptRoot "service_run.ps1")
|
||||||
$stopPs1 = ConvertTo-WinSWPath (Join-Path $PSScriptRoot "stop_netx_app.ps1")
|
$stopPs1 = ConvertTo-WinSWPath (Join-Path $PSScriptRoot "stop_netx_app.ps1")
|
||||||
|
|
|
||||||
417
packaging/installer/Languages/ChineseSimplified.isl
Normal file
417
packaging/installer/Languages/ChineseSimplified.isl
Normal file
|
|
@ -0,0 +1,417 @@
|
||||||
|
; *** Inno Setup version 6.5.0+ Chinese Simplified messages ***
|
||||||
|
;
|
||||||
|
; To download user-contributed translations of this file, go to:
|
||||||
|
; https://jrsoftware.org/files/istrans/
|
||||||
|
;
|
||||||
|
; Note: When translating this text, do not add periods (.) to the end of
|
||||||
|
; messages that didn't have them already, because on those messages Inno
|
||||||
|
; Setup adds the periods automatically (appending a period would result in
|
||||||
|
; two periods being displayed).
|
||||||
|
;
|
||||||
|
; Maintainer: Zhenghan Yang (Kira)
|
||||||
|
; Email: 847320916@QQ.com
|
||||||
|
; Github: https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
|
||||||
|
; Encoding: UTF-8
|
||||||
|
; Translation based on network resource
|
||||||
|
;
|
||||||
|
|
||||||
|
[LangOptions]
|
||||||
|
; The following three entries are very important. Be sure to read and
|
||||||
|
; understand the '[LangOptions] section' topic in the help file.
|
||||||
|
LanguageName=简体中文
|
||||||
|
; About LanguageID, to reference link:
|
||||||
|
; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
|
||||||
|
LanguageID=$0804
|
||||||
|
; LanguageCodePage should always be set if possible, even if this file is Unicode
|
||||||
|
; For English it's set to zero anyway because English only uses ASCII characters
|
||||||
|
LanguageCodePage=936
|
||||||
|
; If the language you are translating to requires special font faces or
|
||||||
|
; sizes, uncomment any of the following entries and change them accordingly.
|
||||||
|
;DialogFontName=
|
||||||
|
;DialogFontSize=9
|
||||||
|
;DialogFontBaseScaleWidth=7
|
||||||
|
;DialogFontBaseScaleHeight=15
|
||||||
|
;WelcomeFontName=Segoe UI
|
||||||
|
;WelcomeFontSize=14
|
||||||
|
|
||||||
|
[Messages]
|
||||||
|
|
||||||
|
; *** Application titles
|
||||||
|
SetupAppTitle=安装
|
||||||
|
SetupWindowTitle=安装 - %1
|
||||||
|
UninstallAppTitle=卸载
|
||||||
|
UninstallAppFullTitle=%1 卸载
|
||||||
|
|
||||||
|
; *** Misc. common
|
||||||
|
InformationTitle=信息
|
||||||
|
ConfirmTitle=确认
|
||||||
|
ErrorTitle=错误
|
||||||
|
|
||||||
|
; *** SetupLdr messages
|
||||||
|
SetupLdrStartupMessage=现在将安装 %1。您想要继续吗?
|
||||||
|
LdrCannotCreateTemp=无法创建临时文件。安装程序已中止
|
||||||
|
LdrCannotExecTemp=无法执行临时目录中的文件。安装程序已中止
|
||||||
|
HelpTextNote=
|
||||||
|
|
||||||
|
; *** Startup error messages
|
||||||
|
LastErrorMessage=%1。%n%n错误 %2: %3
|
||||||
|
SetupFileMissing=安装目录中缺少文件 %1。请修正这个问题或者获取程序的新副本。
|
||||||
|
SetupFileCorrupt=安装文件已损坏。请获取程序的新副本。
|
||||||
|
SetupFileCorruptOrWrongVer=安装文件已损坏,或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。
|
||||||
|
InvalidParameter=无效的命令行参数:%n%n%1
|
||||||
|
SetupAlreadyRunning=安装程序已在运行。
|
||||||
|
WindowsVersionNotSupported=此程序不支持当前计算机运行的 Windows 版本。
|
||||||
|
WindowsServicePackRequired=此程序需要 %1 服务包 %2 或更高版本。
|
||||||
|
NotOnThisPlatform=此程序不能在 %1 上运行。
|
||||||
|
OnlyOnThisPlatform=此程序只能在 %1 上运行。
|
||||||
|
OnlyOnTheseArchitectures=此程序只能安装到为下列处理器架构设计的 Windows 版本中:%n%n%1
|
||||||
|
WinVersionTooLowError=此程序需要 %1 版本 %2 或更高。
|
||||||
|
WinVersionTooHighError=此程序不能安装于 %1 版本 %2 或更高。
|
||||||
|
AdminPrivilegesRequired=在安装此程序时您必须以管理员身份登录。
|
||||||
|
PowerUserPrivilegesRequired=在安装此程序时您必须以管理员身份或高级用户组身份登录。
|
||||||
|
SetupAppRunningError=安装程序检测到 %1 当前正在运行。%n%n请先关闭正在运行的程序,然后点击“确定”继续,或点击“取消”退出。
|
||||||
|
UninstallAppRunningError=卸载程序检测到 %1 当前正在运行。%n%n请先关闭正在运行的程序,然后点击“确定”继续,或点击“取消”退出。
|
||||||
|
|
||||||
|
; *** Startup questions
|
||||||
|
PrivilegesRequiredOverrideTitle=选择安装程序安装模式
|
||||||
|
PrivilegesRequiredOverrideInstruction=选择安装模式
|
||||||
|
PrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限),或仅为您安装。
|
||||||
|
PrivilegesRequiredOverrideText2=%1 可以仅为您安装,或为所有用户安装(需要管理员权限)。
|
||||||
|
PrivilegesRequiredOverrideAllUsers=为所有用户安装(&A)
|
||||||
|
PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(&A)(推荐)
|
||||||
|
PrivilegesRequiredOverrideCurrentUser=仅为我安装(&M)
|
||||||
|
PrivilegesRequiredOverrideCurrentUserRecommended=仅为我安装(&M)(推荐)
|
||||||
|
|
||||||
|
; *** Misc. errors
|
||||||
|
ErrorCreatingDir=安装程序无法创建目录“%1”
|
||||||
|
ErrorTooManyFilesInDir=无法在目录“%1”中创建文件,因为里面包含太多文件。
|
||||||
|
|
||||||
|
; *** Setup common messages
|
||||||
|
ExitSetupTitle=退出安装程序
|
||||||
|
ExitSetupMessage=安装程序尚未完成。如果现在退出,将不会安装该程序。%n%n您之后可以再次运行安装程序完成安装。%n%n现在退出安装程序吗?
|
||||||
|
AboutSetupMenuItem=关于安装程序(&A)...
|
||||||
|
AboutSetupTitle=关于安装程序
|
||||||
|
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4
|
||||||
|
AboutSetupNote=
|
||||||
|
TranslatorNote=简体中文翻译由 Kira(847320916@qq.com)维护。项目地址:https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
|
||||||
|
|
||||||
|
; *** Buttons
|
||||||
|
ButtonBack=< 上一步(&B)
|
||||||
|
ButtonNext=下一步(&N) >
|
||||||
|
ButtonInstall=安装(&I)
|
||||||
|
ButtonOK=确定
|
||||||
|
ButtonCancel=取消
|
||||||
|
ButtonYes=是(&Y)
|
||||||
|
ButtonYesToAll=全是(&A)
|
||||||
|
ButtonNo=否(&N)
|
||||||
|
ButtonNoToAll=全否(&O)
|
||||||
|
ButtonFinish=完成(&F)
|
||||||
|
ButtonBrowse=浏览(&B)...
|
||||||
|
ButtonWizardBrowse=浏览(&R)...
|
||||||
|
ButtonNewFolder=新建文件夹(&M)
|
||||||
|
|
||||||
|
; *** "Select Language" dialog messages
|
||||||
|
SelectLanguageTitle=选择安装语言
|
||||||
|
SelectLanguageLabel=选择安装时使用的语言。
|
||||||
|
|
||||||
|
; *** Common wizard text
|
||||||
|
ClickNext=点击“下一步”继续,或点击“取消”退出安装程序。
|
||||||
|
BeveledLabel=
|
||||||
|
BrowseDialogTitle=浏览文件夹
|
||||||
|
BrowseDialogLabel=在下面的列表中选择一个文件夹,然后点击“确定”。
|
||||||
|
NewFolderName=新建文件夹
|
||||||
|
|
||||||
|
; *** "Welcome" wizard page
|
||||||
|
WelcomeLabel1=欢迎使用 [name] 安装向导
|
||||||
|
WelcomeLabel2=即将在您的计算机上安装 [name/ver]。%n%n建议您在继续安装前关闭所有其他应用程序。
|
||||||
|
|
||||||
|
; *** "Password" wizard page
|
||||||
|
WizardPassword=密码
|
||||||
|
PasswordLabel1=此安装程序需要密码验证。
|
||||||
|
PasswordLabel3=请输入密码,然后点击“下一步”继续。密码区分大小写。
|
||||||
|
PasswordEditLabel=密码(&P):
|
||||||
|
IncorrectPassword=您输入的密码不正确,请重新输入。
|
||||||
|
|
||||||
|
; *** "License Agreement" wizard page
|
||||||
|
WizardLicense=许可协议
|
||||||
|
LicenseLabel=请在继续安装前阅读以下重要信息。
|
||||||
|
LicenseLabel3=请阅读下列许可协议。在继续安装前您必须同意这些协议条款。
|
||||||
|
LicenseAccepted=我同意此协议(&A)
|
||||||
|
LicenseNotAccepted=我不同意此协议(&D)
|
||||||
|
|
||||||
|
; *** "Information" wizard pages
|
||||||
|
WizardInfoBefore=信息
|
||||||
|
InfoBeforeLabel=请在继续安装前阅读以下重要信息。
|
||||||
|
InfoBeforeClickLabel=准备好继续安装后,点击“下一步”。
|
||||||
|
WizardInfoAfter=信息
|
||||||
|
InfoAfterLabel=请在继续安装前阅读以下重要信息。
|
||||||
|
InfoAfterClickLabel=准备好继续安装后,点击“下一步”。
|
||||||
|
|
||||||
|
; *** "User Information" wizard page
|
||||||
|
WizardUserInfo=用户信息
|
||||||
|
UserInfoDesc=请输入您的信息。
|
||||||
|
UserInfoName=用户名(&U):
|
||||||
|
UserInfoOrg=组织(&O):
|
||||||
|
UserInfoSerial=序列号(&S):
|
||||||
|
UserInfoNameRequired=请输入用户名。
|
||||||
|
|
||||||
|
; *** "Select Destination Location" wizard page
|
||||||
|
WizardSelectDir=选择目标位置
|
||||||
|
SelectDirDesc=您想将 [name] 安装在哪里?
|
||||||
|
SelectDirLabel3=安装程序将安装 [name] 到下面的文件夹中。
|
||||||
|
SelectDirBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹,点击“浏览”。
|
||||||
|
DiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。
|
||||||
|
DiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。
|
||||||
|
CannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。
|
||||||
|
CannotInstallToUNCPath=安装程序无法安装到一个 UNC 路径。
|
||||||
|
InvalidPath=您必须输入一个带驱动器盘符的完整路径,例如:%n%nC:\App%n%n或UNC路径:%n%n\\server\share
|
||||||
|
InvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选择其他位置。
|
||||||
|
DiskSpaceWarningTitle=磁盘空间不足
|
||||||
|
DiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装,但选定驱动器只有 %2 KB 的可用空间。%n%n您确定要继续吗?
|
||||||
|
DirNameTooLong=文件夹名称或路径太长。
|
||||||
|
InvalidDirName=文件夹名称无效。
|
||||||
|
BadDirName32=文件夹名称不能包含下列任何字符:%n%n%1
|
||||||
|
DirExistsTitle=文件夹已存在
|
||||||
|
DirExists=文件夹:%n%n%1%n%n已经存在。您确定安装到这个文件夹中吗?
|
||||||
|
DirDoesntExistTitle=文件夹不存在
|
||||||
|
DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此文件夹吗?
|
||||||
|
|
||||||
|
; *** "Select Components" wizard page
|
||||||
|
WizardSelectComponents=选择组件
|
||||||
|
SelectComponentsDesc=您想安装哪些程序组件?
|
||||||
|
SelectComponentsLabel2=选中您想安装的组件;取消您不想安装的组件。然后点击“下一步”继续。
|
||||||
|
FullInstallation=完全安装
|
||||||
|
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
|
||||||
|
CompactInstallation=简洁安装
|
||||||
|
CustomInstallation=自定义安装
|
||||||
|
NoUninstallWarningTitle=组件已存在
|
||||||
|
NoUninstallWarning=安装程序检测到下列组件已安装在您的计算机中:%n%n%1%n%n取消选中这些组件不会卸载它们。%n%n您确定要继续吗?
|
||||||
|
ComponentSize1=%1 KB
|
||||||
|
ComponentSize2=%1 MB
|
||||||
|
ComponentsDiskSpaceGBLabel=当前选择的组件需要至少 [gb] GB 的磁盘空间。
|
||||||
|
ComponentsDiskSpaceMBLabel=当前选择的组件需要至少 [mb] MB 的磁盘空间。
|
||||||
|
|
||||||
|
; *** "Select Additional Tasks" wizard page
|
||||||
|
WizardSelectTasks=选择附加任务
|
||||||
|
SelectTasksDesc=您想要安装程序执行哪些附加任务?
|
||||||
|
SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后点击“下一步”。
|
||||||
|
|
||||||
|
; *** "Select Start Menu Folder" wizard page
|
||||||
|
WizardSelectProgramGroup=选择开始菜单文件夹
|
||||||
|
SelectStartMenuFolderDesc=安装程序应该在哪里放置程序的快捷方式?
|
||||||
|
SelectStartMenuFolderLabel3=安装程序将在下列“开始”菜单文件夹中创建程序的快捷方式。
|
||||||
|
SelectStartMenuFolderBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹,点击“浏览”。
|
||||||
|
MustEnterGroupName=您必须输入一个文件夹名称。
|
||||||
|
GroupNameTooLong=文件夹名称或路径太长。
|
||||||
|
InvalidGroupName=文件夹名称无效。
|
||||||
|
BadGroupName=文件夹名称不能包含下列任何字符:%n%n%1
|
||||||
|
NoProgramGroupCheck2=不创建开始菜单文件夹(&D)
|
||||||
|
|
||||||
|
; *** "Ready to Install" wizard page
|
||||||
|
WizardReady=准备安装
|
||||||
|
ReadyLabel1=安装程序准备就绪,现在可以开始安装 [name] 到您的计算机。
|
||||||
|
ReadyLabel2a=点击“安装”继续此安装程序。如果您想重新查看或修改任何设置,点击“上一步”。
|
||||||
|
ReadyLabel2b=点击“安装”继续此安装程序。
|
||||||
|
ReadyMemoUserInfo=用户信息:
|
||||||
|
ReadyMemoDir=目标位置:
|
||||||
|
ReadyMemoType=安装类型:
|
||||||
|
ReadyMemoComponents=已选择组件:
|
||||||
|
ReadyMemoGroup=开始菜单文件夹:
|
||||||
|
ReadyMemoTasks=附加任务:
|
||||||
|
|
||||||
|
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
|
||||||
|
DownloadingLabel2=正在下载文件...
|
||||||
|
ButtonStopDownload=停止下载(&S)
|
||||||
|
StopDownload=您确定要停止下载吗?
|
||||||
|
ErrorDownloadAborted=下载已中止。
|
||||||
|
ErrorDownloadFailed=下载失败:%1 %2。
|
||||||
|
ErrorDownloadSizeFailed=获取大小失败:%1 %2。
|
||||||
|
ErrorProgress=无效的进度:%1 / %2。
|
||||||
|
ErrorFileSize=文件大小错误:预期 %1,实际 %2。
|
||||||
|
|
||||||
|
; *** TExtractionWizardPage wizard page and ExtractArchive
|
||||||
|
ExtractingLabel=正在提取文件...
|
||||||
|
ButtonStopExtraction=停止提取(&S)
|
||||||
|
StopExtraction=您确定要停止提取吗?
|
||||||
|
ErrorExtractionAborted=提取已中止。
|
||||||
|
ErrorExtractionFailed=提取失败:%1
|
||||||
|
|
||||||
|
; *** Archive extraction failure details
|
||||||
|
ArchiveIncorrectPassword=密码不正确。
|
||||||
|
ArchiveIsCorrupted=压缩包已损坏。
|
||||||
|
ArchiveUnsupportedFormat=不支持的压缩包格式。
|
||||||
|
|
||||||
|
; *** "Preparing to Install" wizard page
|
||||||
|
WizardPreparing=正在准备安装
|
||||||
|
PreparingDesc=安装程序正在准备安装 [name] 到您的计算机。
|
||||||
|
PreviousInstallNotCompleted=先前的程序安装或卸载未完成,需要您重启计算机以完成该安装。%n%n在重启计算机后,再次运行安装程序以完成 [name] 的安装。
|
||||||
|
CannotContinue=安装程序不能继续。请点击“取消”退出。
|
||||||
|
ApplicationsFound=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。
|
||||||
|
ApplicationsFound2=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。安装完成后,安装程序将尝试重新启动这些应用程序。
|
||||||
|
CloseApplications=自动关闭应用程序(&A)
|
||||||
|
DontCloseApplications=不要关闭应用程序(&D)
|
||||||
|
ErrorCloseApplications=安装程序无法自动关闭所有应用程序。建议您在继续之前,关闭所有在使用需要由安装程序更新的文件的应用程序。
|
||||||
|
PrepareToInstallNeedsRestart=安装程序必须重启您的计算机。计算机重启后,请再次运行安装程序以完成 [name] 的安装。%n%n要立即重启吗?
|
||||||
|
|
||||||
|
; *** "Installing" wizard page
|
||||||
|
WizardInstalling=正在安装
|
||||||
|
InstallingLabel=安装程序正在安装 [name] 到您的计算机,请稍候。
|
||||||
|
|
||||||
|
; *** "Setup Completed" wizard page
|
||||||
|
FinishedHeadingLabel=完成 [name] 安装向导
|
||||||
|
FinishedLabelNoIcons=安装程序已在您的计算机中安装了 [name]。
|
||||||
|
FinishedLabel=安装程序已在您的计算机中安装了 [name]。您可以通过已安装的快捷方式运行此应用程序。
|
||||||
|
ClickFinish=点击“完成”退出安装程序。
|
||||||
|
FinishedRestartLabel=为完成 [name] 的安装,安装程序必须重新启动您的计算机。要立即重启吗?
|
||||||
|
FinishedRestartMessage=为完成 [name] 的安装,安装程序必须重新启动您的计算机。%n%n要立即重启吗?
|
||||||
|
ShowReadmeCheck=是,我想查阅自述文件
|
||||||
|
YesRadio=是,立即重启计算机(&Y)
|
||||||
|
NoRadio=否,稍后重启计算机(&N)
|
||||||
|
; used for example as 'Run MyProg.exe'
|
||||||
|
RunEntryExec=运行 %1
|
||||||
|
; used for example as 'View Readme.txt'
|
||||||
|
RunEntryShellExec=查阅 %1
|
||||||
|
|
||||||
|
; *** "Setup Needs the Next Disk" stuff
|
||||||
|
ChangeDiskTitle=安装程序需要下一张磁盘
|
||||||
|
SelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果这个磁盘中的文件可以在下列文件夹之外的文件夹中找到,请输入正确的路径或点击“浏览”。
|
||||||
|
PathLabel=路径(&P):
|
||||||
|
FileNotInDir2=“%2”中找不到文件“%1”。请插入正确的磁盘或选择其他文件夹。
|
||||||
|
SelectDirectoryLabel=请指定下一张磁盘的位置。
|
||||||
|
|
||||||
|
; *** Installation phase messages
|
||||||
|
SetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。
|
||||||
|
AbortRetryIgnoreSelectAction=选择操作
|
||||||
|
AbortRetryIgnoreRetry=重试(&T)
|
||||||
|
AbortRetryIgnoreIgnore=忽略错误并继续(&I)
|
||||||
|
AbortRetryIgnoreCancel=取消安装
|
||||||
|
RetryCancelSelectAction=选择操作
|
||||||
|
RetryCancelRetry=重试(&T)
|
||||||
|
RetryCancelCancel=取消
|
||||||
|
|
||||||
|
; *** Installation status messages
|
||||||
|
StatusClosingApplications=正在关闭应用程序...
|
||||||
|
StatusCreateDirs=正在创建目录...
|
||||||
|
StatusExtractFiles=正在提取文件...
|
||||||
|
StatusDownloadFiles=正在下载文件...
|
||||||
|
StatusCreateIcons=正在创建快捷方式...
|
||||||
|
StatusCreateIniEntries=正在创建 INI 条目...
|
||||||
|
StatusCreateRegistryEntries=正在创建注册表条目...
|
||||||
|
StatusRegisterFiles=正在注册文件...
|
||||||
|
StatusSavingUninstall=正在保存卸载信息...
|
||||||
|
StatusRunProgram=正在完成安装...
|
||||||
|
StatusRestartingApplications=正在重启应用程序...
|
||||||
|
StatusRollback=正在撤销更改...
|
||||||
|
|
||||||
|
; *** Misc. errors
|
||||||
|
ErrorInternal2=内部错误:%1。
|
||||||
|
ErrorFunctionFailedNoCode=%1 失败。
|
||||||
|
ErrorFunctionFailed=%1 失败;错误代码 %2。
|
||||||
|
ErrorFunctionFailedWithMessage=%1 失败;错误代码 %2。%n%3
|
||||||
|
ErrorExecutingProgram=无法执行文件:%n%1
|
||||||
|
|
||||||
|
; *** Registry errors
|
||||||
|
ErrorRegOpenKey=打开注册表项时出错:%n%1\%2
|
||||||
|
ErrorRegCreateKey=创建注册表项时出错:%n%1\%2
|
||||||
|
ErrorRegWriteKey=写入注册表项时出错:%n%1\%2
|
||||||
|
|
||||||
|
; *** INI errors
|
||||||
|
ErrorIniEntry=在文件“%1”中创建 INI 条目时出错。
|
||||||
|
|
||||||
|
; *** File copying errors
|
||||||
|
FileAbortRetryIgnoreSkipNotRecommended=跳过此文件(&S)(不推荐)
|
||||||
|
FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续(&I)(不推荐)
|
||||||
|
SourceIsCorrupted=源文件已损坏。
|
||||||
|
SourceDoesntExist=源文件“%1”不存在。
|
||||||
|
SourceVerificationFailed=源文件验证失败:%1
|
||||||
|
VerificationSignatureDoesntExist=签名文件“%1”不存在。
|
||||||
|
VerificationSignatureInvalid=签名文件“%1”无效。
|
||||||
|
VerificationKeyNotFound=签名文件“%1”使用了未知的密钥。
|
||||||
|
VerificationFileNameIncorrect=文件名不正确。
|
||||||
|
VerificationFileTagIncorrect=文件标签不正确。
|
||||||
|
VerificationFileSizeIncorrect=文件大小不正确。
|
||||||
|
VerificationFileHashIncorrect=文件哈希值不正确。
|
||||||
|
ExistingFileReadOnly2=无法替换已存在的文件,它是只读的。
|
||||||
|
ExistingFileReadOnlyRetry=移除只读属性并重试(&R)
|
||||||
|
ExistingFileReadOnlyKeepExisting=保留已存在的文件(&K)
|
||||||
|
ErrorReadingExistingDest=尝试读取已存在的文件时出错:
|
||||||
|
FileExistsSelectAction=选择操作
|
||||||
|
FileExists2=文件已经存在。
|
||||||
|
FileExistsOverwriteExisting=覆盖已存在的文件(&O)
|
||||||
|
FileExistsKeepExisting=保留已存在的文件(&K)
|
||||||
|
FileExistsOverwriteOrKeepAll=为接下来的冲突文件执行此操作(&D)
|
||||||
|
ExistingFileNewerSelectAction=选择操作
|
||||||
|
ExistingFileNewer2=已存在的文件比安装程序将要安装的文件还要新。
|
||||||
|
ExistingFileNewerOverwriteExisting=覆盖已存在的文件(&O)
|
||||||
|
ExistingFileNewerKeepExisting=保留已存在的文件(&K)(推荐)
|
||||||
|
ExistingFileNewerOverwriteOrKeepAll=为接下来的冲突文件执行此操作(&D)
|
||||||
|
ErrorChangingAttr=尝试更改下列已存在的文件属性时出错:
|
||||||
|
ErrorCreatingTemp=尝试在目标目录创建文件时出错:
|
||||||
|
ErrorReadingSource=尝试读取下列源文件时出错:
|
||||||
|
ErrorCopying=尝试复制下列文件时出错:
|
||||||
|
ErrorDownloading=尝试下载文件时出错:
|
||||||
|
ErrorExtracting=尝试提取压缩包时出错:
|
||||||
|
ErrorReplacingExistingFile=尝试替换已存在的文件时出错:
|
||||||
|
ErrorRestartReplace=重启并替换失败:
|
||||||
|
ErrorRenamingTemp=尝试重命名下列目标目录中的一个文件时出错:
|
||||||
|
ErrorRegisterServer=无法注册 DLL/OCX:%1
|
||||||
|
ErrorRegSvr32Failed=RegSvr32 失败;退出代码 %1。
|
||||||
|
ErrorRegisterTypeLib=无法注册类型库:%1
|
||||||
|
|
||||||
|
; *** Uninstall display name markings
|
||||||
|
; used for example as 'My Program (32-bit)'
|
||||||
|
UninstallDisplayNameMark=%1 (%2)
|
||||||
|
; used for example as 'My Program (32-bit, All users)'
|
||||||
|
UninstallDisplayNameMarks=%1 (%2, %3)
|
||||||
|
UninstallDisplayNameMark32Bit=32 位
|
||||||
|
UninstallDisplayNameMark64Bit=64 位
|
||||||
|
UninstallDisplayNameMarkAllUsers=所有用户
|
||||||
|
UninstallDisplayNameMarkCurrentUser=当前用户
|
||||||
|
|
||||||
|
; *** Post-installation errors
|
||||||
|
ErrorOpeningReadme=尝试打开自述文件时出错。
|
||||||
|
ErrorRestartingComputer=安装程序无法重启计算机,请手动重启。
|
||||||
|
|
||||||
|
; *** Uninstaller messages
|
||||||
|
UninstallNotFound=文件“%1”不存在。无法卸载。
|
||||||
|
UninstallOpenError=文件“%1”不能被打开。无法卸载
|
||||||
|
UninstallUnsupportedVer=此版本的卸载程序无法识别卸载日志文件“%1”的格式。无法卸载。
|
||||||
|
UninstallUnknownEntry=卸载日志中遇到一个未知条目(%1)。
|
||||||
|
ConfirmUninstall=您确认要完全移除 %1 及其所有组件吗?
|
||||||
|
UninstallOnlyOnWin64=仅允许在 64 位 Windows 中卸载此程序。
|
||||||
|
OnlyAdminCanUninstall=仅使用管理员权限的用户能完成此卸载。
|
||||||
|
UninstallStatusLabel=正在从您的计算机中移除 %1,请稍候。
|
||||||
|
UninstalledAll=已顺利从您的计算机中移除 %1。
|
||||||
|
UninstalledMost=%1 卸载完成。%n%n有部分内容未能被删除,但您可以手动删除它们。
|
||||||
|
UninstalledAndNeedsRestart=为完成 %1 的卸载,需要重启您的计算机。%n%n要立即重启吗?
|
||||||
|
UninstallDataCorrupted=文件“%1”已损坏。无法卸载。
|
||||||
|
|
||||||
|
; *** Uninstallation phase messages
|
||||||
|
ConfirmDeleteSharedFileTitle=删除共享文件?
|
||||||
|
ConfirmDeleteSharedFile2=系统表示下列共享文件已不再有任何程序使用。您希望卸载程序删除此共享文件吗?%n%n如果仍有程序正在使用此文件,删除后这些程序可能无法正常运行。如果您不能确定,请选择“否”,保留此文件在系统中不会造成任何损害。
|
||||||
|
SharedFileNameLabel=文件名:
|
||||||
|
SharedFileLocationLabel=位置:
|
||||||
|
WizardUninstalling=卸载状态
|
||||||
|
StatusUninstalling=正在卸载 %1...
|
||||||
|
|
||||||
|
; *** Shutdown block reasons
|
||||||
|
ShutdownBlockReasonInstallingApp=正在安装 %1。
|
||||||
|
ShutdownBlockReasonUninstallingApp=正在卸载 %1。
|
||||||
|
|
||||||
|
; The custom messages below aren't used by Setup itself, but if you make
|
||||||
|
; use of them in your scripts, you'll want to translate them.
|
||||||
|
|
||||||
|
[CustomMessages]
|
||||||
|
|
||||||
|
NameAndVersion=%1 版本 %2
|
||||||
|
AdditionalIcons=附加快捷方式:
|
||||||
|
CreateDesktopIcon=创建桌面快捷方式(&D)
|
||||||
|
CreateQuickLaunchIcon=创建快速启动栏快捷方式(&Q)
|
||||||
|
ProgramOnTheWeb=%1 网站
|
||||||
|
UninstallProgram=卸载 %1
|
||||||
|
LaunchProgram=运行 %1
|
||||||
|
AssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A)
|
||||||
|
AssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联...
|
||||||
|
AutoStartProgramGroupDescription=启动:
|
||||||
|
AutoStartProgram=自动启动 %1
|
||||||
|
AddonHostProgramNotFound=您选择的文件夹中无法找到 %1。%n%n您确定要继续吗?
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
; Stage directory produced by build_release.ps1 (relative to this .iss)
|
; Stage directory produced by build_release.ps1 (relative to this .iss)
|
||||||
#define StageDir "..\release\netx-win64"
|
#define StageDir "..\release\netx-win64"
|
||||||
|
#define IconFile "..\assets\netx.ico"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppId={{A7E3C2D1-9F40-4B8E-9C1A-NETXWIN64001}
|
AppId={{A7E3C2D1-9F40-4B8E-9C1A-NETXWIN64001}
|
||||||
|
|
@ -25,6 +26,8 @@ DisableProgramGroupPage=yes
|
||||||
LicenseFile={#StageDir}\LICENSE
|
LicenseFile={#StageDir}\LICENSE
|
||||||
OutputDir=..\release
|
OutputDir=..\release
|
||||||
OutputBaseFilename=NetX-Setup-{#MyAppVersion}
|
OutputBaseFilename=NetX-Setup-{#MyAppVersion}
|
||||||
|
SetupIconFile={#IconFile}
|
||||||
|
UninstallDisplayIcon={app}\packaging\assets\netx.ico
|
||||||
Compression=lzma2
|
Compression=lzma2
|
||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
WizardStyle=modern
|
WizardStyle=modern
|
||||||
|
|
@ -33,13 +36,31 @@ ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
PrivilegesRequired=admin
|
PrivilegesRequired=admin
|
||||||
; Data lives under {commonappdata}\NetX — not overwritten by upgrades
|
; Data lives under {commonappdata}\NetX — not overwritten by upgrades
|
||||||
CloseApplications=yes
|
CloseApplications=yes
|
||||||
|
ShowLanguageDialog=yes
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
Name: "chinesesimplified"; MessagesFile: "Languages\ChineseSimplified.isl"
|
||||||
|
|
||||||
|
[CustomMessages]
|
||||||
|
english.CreateDesktopIcon=Create a desktop shortcut
|
||||||
|
english.SetupOptions=Setup options:
|
||||||
|
english.RunFirstSetup=Run first-time setup after install (bundled database, offline)
|
||||||
|
english.StartTrayNow=Start NetX tray now
|
||||||
|
english.EnableAutostart=Start NetX tray at Windows logon
|
||||||
|
english.EnableAutoUpdate=Enable daily silent auto-update (needs network later)
|
||||||
|
english.InstallService=Install as Windows Service (uses bundled WinSW, offline)
|
||||||
|
chinesesimplified.CreateDesktopIcon=创建桌面快捷方式
|
||||||
|
chinesesimplified.SetupOptions=安装选项:
|
||||||
|
chinesesimplified.RunFirstSetup=安装后运行首次配置(内置数据库,可离线)
|
||||||
|
chinesesimplified.StartTrayNow=立即启动 NetX 托盘
|
||||||
|
chinesesimplified.EnableAutostart=开机时自动启动 NetX 托盘
|
||||||
|
chinesesimplified.EnableAutoUpdate=启用每日静默自动更新(以后需要联网)
|
||||||
|
chinesesimplified.InstallService=安装为 Windows 服务(使用已捆绑的 WinSW,可离线)
|
||||||
|
|
||||||
[Tasks]
|
[Tasks]
|
||||||
Name: "desktopicon"; Description: "Create a desktop shortcut"; GroupDescription: "Additional icons:"; Flags: unchecked
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||||
Name: "firstrun"; Description: "Run first-time setup (database mode) after install"; GroupDescription: "Setup:"; Flags: checkedonce
|
Name: "firstrun"; Description: "{cm:RunFirstSetup}"; GroupDescription: "{cm:SetupOptions}"; Flags: checkedonce
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; Entire release stage → {app}. Exclude .portable so installed builds use ProgramData.
|
; Entire release stage → {app}. Exclude .portable so installed builds use ProgramData.
|
||||||
|
|
@ -54,23 +75,24 @@ Name: "{commonappdata}\NetX\pgdata"
|
||||||
Name: "{commonappdata}\NetX\backups"
|
Name: "{commonappdata}\NetX\backups"
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{group}\NetX Tray"; Filename: "powershell.exe"; Parameters: "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""{app}\packaging\netx_tray.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"
|
Name: "{group}\NetX Tray"; Filename: "powershell.exe"; Parameters: "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""{app}\packaging\netx_tray.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Start NetX"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\start_netx_app.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"
|
Name: "{group}\Start NetX"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\start_netx_app.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Stop NetX"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\stop_netx_app.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"
|
Name: "{group}\Stop NetX"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\stop_netx_app.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Check for updates"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\check_update.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"
|
Name: "{group}\Check for updates"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\check_update.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Open NetX UI"; Filename: "http://127.0.0.1:8890/"
|
Name: "{group}\Open NetX UI"; Filename: "http://127.0.0.1:8890/"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\First-time setup"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\setup_first_run.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"
|
Name: "{group}\First-time setup"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\setup_first_run.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Install Windows Service (admin)"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"
|
Name: "{group}\Install Windows Service (admin)"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Enable silent auto-update (daily)"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_update_task.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"
|
Name: "{group}\Enable silent auto-update (daily)"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_update_task.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{group}\Enable start at logon"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_autostart.ps1"" -ProgramRoot ""{app}"""; WorkingDir: "{app}"
|
Name: "{group}\Enable start at logon"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_autostart.ps1"" -ProgramRoot ""{app}"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"
|
||||||
Name: "{autodesktop}\NetX"; Filename: "powershell.exe"; Parameters: "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""{app}\packaging\netx_tray.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; Tasks: desktopicon
|
Name: "{autodesktop}\NetX"; Filename: "powershell.exe"; Parameters: "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""{app}\packaging\netx_tray.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"; Tasks: desktopicon
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\setup_first_run.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; Flags: postinstall skipifsilent; Tasks: firstrun
|
; First-run is NonInteractive + bundled DB so offline machines succeed without prompts or downloads.
|
||||||
Filename: "powershell.exe"; Parameters: "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""{app}\packaging\netx_tray.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; Description: "Start NetX tray now"; Flags: postinstall nowait skipifsilent unchecked
|
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\setup_first_run.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -NonInteractive -DbMode bundled"; WorkingDir: "{app}"; Flags: postinstall skipifsilent; Tasks: firstrun
|
||||||
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_autostart.ps1"" -ProgramRoot ""{app}"""; WorkingDir: "{app}"; Description: "Start NetX tray at Windows logon"; Flags: postinstall skipifsilent unchecked
|
Filename: "powershell.exe"; Parameters: "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File ""{app}\packaging\netx_tray.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; Description: "{cm:StartTrayNow}"; Flags: postinstall nowait skipifsilent unchecked
|
||||||
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_update_task.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; Description: "Enable daily silent auto-update"; Flags: postinstall skipifsilent unchecked
|
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_autostart.ps1"" -ProgramRoot ""{app}"""; WorkingDir: "{app}"; Description: "{cm:EnableAutostart}"; Flags: postinstall skipifsilent unchecked
|
||||||
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; Description: "Install as Windows Service (admin)"; Flags: postinstall skipifsilent unchecked
|
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_update_task.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; Description: "{cm:EnableAutoUpdate}"; Flags: postinstall skipifsilent unchecked
|
||||||
|
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; Description: "{cm:InstallService}"; Flags: postinstall skipifsilent unchecked
|
||||||
|
|
||||||
[UninstallDelete]
|
[UninstallDelete]
|
||||||
; Do NOT delete {commonappdata}\NetX — preserves DB and secrets across reinstall
|
; Do NOT delete {commonappdata}\NetX — preserves DB and secrets across reinstall
|
||||||
|
|
|
||||||
|
|
@ -56,31 +56,43 @@ $form.WindowState = "Minimized"
|
||||||
$form.Visible = $false
|
$form.Visible = $false
|
||||||
$form.Size = New-Object System.Drawing.Size(0, 0)
|
$form.Size = New-Object System.Drawing.Size(0, 0)
|
||||||
|
|
||||||
|
$zh = ([cultureinfo]::CurrentUICulture.Name -match '^(zh|zh-)')
|
||||||
|
function T([string]$En, [string]$Zh) {
|
||||||
|
if ($zh) { return $Zh } else { return $En }
|
||||||
|
}
|
||||||
|
|
||||||
$notify = New-Object System.Windows.Forms.NotifyIcon
|
$notify = New-Object System.Windows.Forms.NotifyIcon
|
||||||
$notify.Text = "NetX $ver"
|
$notify.Text = "NetX $ver"
|
||||||
$notify.Visible = $true
|
$notify.Visible = $true
|
||||||
|
$iconPath = Join-Path $PSScriptRoot "assets\netx.ico"
|
||||||
try {
|
try {
|
||||||
$notify.Icon = [System.Drawing.SystemIcons]::Application
|
if (Test-Path $iconPath) {
|
||||||
} catch {}
|
$notify.Icon = New-Object System.Drawing.Icon $iconPath
|
||||||
|
} else {
|
||||||
|
$notify.Icon = [System.Drawing.SystemIcons]::Application
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
try { $notify.Icon = [System.Drawing.SystemIcons]::Application } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
$menu = New-Object System.Windows.Forms.ContextMenuStrip
|
||||||
|
|
||||||
$miOpen = $menu.Items.Add("Open UI ($uiUrl)")
|
$miOpen = $menu.Items.Add((T "Open UI ($uiUrl)" "打开界面 ($uiUrl)"))
|
||||||
$miOpen.add_Click({ Start-Process $uiUrl })
|
$miOpen.add_Click({ Start-Process $uiUrl })
|
||||||
|
|
||||||
$miStart = $menu.Items.Add("Start NetX")
|
$miStart = $menu.Items.Add((T "Start NetX" "启动 NetX"))
|
||||||
$miStart.add_Click({
|
$miStart.add_Click({
|
||||||
$notify.ShowBalloonTip(3000, "NetX", "Starting…", [System.Windows.Forms.ToolTipIcon]::Info)
|
$notify.ShowBalloonTip(3000, "NetX", (T "Starting…" "正在启动…"), [System.Windows.Forms.ToolTipIcon]::Info)
|
||||||
Invoke-NetxScript -File $startPs1 -ExtraArgs @("-SkipBrowser")
|
Invoke-NetxScript -File $startPs1 -ExtraArgs @("-SkipBrowser")
|
||||||
})
|
})
|
||||||
|
|
||||||
$miStop = $menu.Items.Add("Stop NetX")
|
$miStop = $menu.Items.Add((T "Stop NetX" "停止 NetX"))
|
||||||
$miStop.add_Click({
|
$miStop.add_Click({
|
||||||
$notify.ShowBalloonTip(3000, "NetX", "Stopping…", [System.Windows.Forms.ToolTipIcon]::Info)
|
$notify.ShowBalloonTip(3000, "NetX", (T "Stopping…" "正在停止…"), [System.Windows.Forms.ToolTipIcon]::Info)
|
||||||
Invoke-NetxScript -File $stopPs1
|
Invoke-NetxScript -File $stopPs1
|
||||||
})
|
})
|
||||||
|
|
||||||
$miUpdate = $menu.Items.Add("Check for updates")
|
$miUpdate = $menu.Items.Add((T "Check for updates" "检查更新"))
|
||||||
$miUpdate.add_Click({
|
$miUpdate.add_Click({
|
||||||
try {
|
try {
|
||||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
$p = Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
||||||
|
|
@ -89,8 +101,8 @@ $miUpdate.add_Click({
|
||||||
) -Wait -PassThru -WindowStyle Normal
|
) -Wait -PassThru -WindowStyle Normal
|
||||||
if ($p.ExitCode -eq 10) {
|
if ($p.ExitCode -eq 10) {
|
||||||
$ans = [System.Windows.Forms.MessageBox]::Show(
|
$ans = [System.Windows.Forms.MessageBox]::Show(
|
||||||
"A newer NetX is available. Download and apply now?",
|
(T "A newer NetX is available. Download and apply now?" "发现新版本,是否立即下载并更新?"),
|
||||||
"NetX update",
|
(T "NetX update" "NetX 更新"),
|
||||||
[System.Windows.Forms.MessageBoxButtons]::YesNo,
|
[System.Windows.Forms.MessageBoxButtons]::YesNo,
|
||||||
[System.Windows.Forms.MessageBoxIcon]::Question
|
[System.Windows.Forms.MessageBoxIcon]::Question
|
||||||
)
|
)
|
||||||
|
|
@ -101,16 +113,16 @@ $miUpdate.add_Click({
|
||||||
) -WorkingDirectory $prog
|
) -WorkingDirectory $prog
|
||||||
}
|
}
|
||||||
} elseif ($p.ExitCode -eq 0) {
|
} elseif ($p.ExitCode -eq 0) {
|
||||||
[System.Windows.Forms.MessageBox]::Show("NetX is up to date ($ver).", "NetX update")
|
[System.Windows.Forms.MessageBox]::Show((T "NetX is up to date ($ver)." "已是最新版本 ($ver)。"), (T "NetX update" "NetX 更新"))
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
[System.Windows.Forms.MessageBox]::Show("Update check failed: $($_.Exception.Message)", "NetX")
|
[System.Windows.Forms.MessageBox]::Show((T "Update check failed: $($_.Exception.Message)" "检查更新失败:$($_.Exception.Message)"), "NetX")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
[void]$menu.Items.Add("-")
|
[void]$menu.Items.Add("-")
|
||||||
|
|
||||||
$miExit = $menu.Items.Add("Exit tray (services keep running)")
|
$miExit = $menu.Items.Add((T "Exit tray (services keep running)" "退出托盘(服务继续运行)"))
|
||||||
$miExit.add_Click({
|
$miExit.add_Click({
|
||||||
$notify.Visible = $false
|
$notify.Visible = $false
|
||||||
$form.Close()
|
$form.Close()
|
||||||
|
|
@ -122,7 +134,7 @@ $notify.add_DoubleClick({ Start-Process $uiUrl })
|
||||||
|
|
||||||
$form.add_Shown({
|
$form.add_Shown({
|
||||||
if ($AutoUpdate) {
|
if ($AutoUpdate) {
|
||||||
$notify.ShowBalloonTip(4000, "NetX", "Checking for updates…", [System.Windows.Forms.ToolTipIcon]::Info)
|
$notify.ShowBalloonTip(4000, "NetX", (T "Checking for updates…" "正在检查更新…"), [System.Windows.Forms.ToolTipIcon]::Info)
|
||||||
Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
||||||
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $checkPs1,
|
"-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $checkPs1,
|
||||||
"-ProgramRoot", $prog, "-DataRoot", $data, "-Apply", "-Quiet", "-AutoOnly"
|
"-ProgramRoot", $prog, "-DataRoot", $data, "-Apply", "-Quiet", "-AutoOnly"
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,15 @@ $ErrorActionPreference = "Stop"
|
||||||
$prog = Get-NetxProgramRoot -Override $ProgramRoot
|
$prog = Get-NetxProgramRoot -Override $ProgramRoot
|
||||||
$data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot
|
$data = Get-NetxDataRoot -ProgramRoot $prog -Override $DataRoot
|
||||||
$envPath = Join-Path $data ".env"
|
$envPath = Join-Path $data ".env"
|
||||||
|
$zh = ([cultureinfo]::CurrentUICulture.Name -match '^(zh|zh-)')
|
||||||
|
|
||||||
Write-Host "==> Program root: $prog"
|
function T([string]$En, [string]$Zh) {
|
||||||
Write-Host "==> Data root: $data"
|
if ($zh) { return $Zh } else { return $En }
|
||||||
Write-Host "==> Env file: $envPath"
|
}
|
||||||
|
|
||||||
|
Write-Host ("==> " + (T "Program root:" "程序目录:") + " $prog")
|
||||||
|
Write-Host ("==> " + (T "Data root:" "数据目录:") + " $data")
|
||||||
|
Write-Host ("==> " + (T "Env file:" "环境文件:") + " $envPath")
|
||||||
|
|
||||||
Ensure-NetxDataDirectories -DataRoot $data
|
Ensure-NetxDataDirectories -DataRoot $data
|
||||||
|
|
||||||
|
|
@ -34,10 +39,10 @@ if (-not $DbMode) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Choose database mode:"
|
Write-Host (T "Choose database mode:" "选择数据库模式:")
|
||||||
Write-Host " 1) bundled — use NetX portable PostgreSQL (default for new installs)"
|
Write-Host (T " 1) bundled — use NetX portable PostgreSQL (default for new installs)" " 1) bundled — 使用 NetX 内置便携 PostgreSQL(新安装默认)")
|
||||||
Write-Host " 2) external — connect to an existing PostgreSQL (Linux / already deployed)"
|
Write-Host (T " 2) external — connect to an existing PostgreSQL (Linux / already deployed)" " 2) external — 连接已有 PostgreSQL")
|
||||||
$choice = Read-Host "Enter 1 or 2"
|
$choice = Read-Host (T "Enter 1 or 2" "请输入 1 或 2")
|
||||||
if ($choice -eq "2") { $DbMode = "external" } else { $DbMode = "bundled" }
|
if ($choice -eq "2") { $DbMode = "external" } else { $DbMode = "bundled" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,14 +74,16 @@ if ($DbMode -eq "bundled") {
|
||||||
if (Test-Path (Join-Path $alt "bin\initdb.exe")) {
|
if (Test-Path (Join-Path $alt "bin\initdb.exe")) {
|
||||||
$pgsql = $alt
|
$pgsql = $alt
|
||||||
} else {
|
} else {
|
||||||
throw "bundled_postgres_missing: run packaging\download_postgres.ps1 first (expected $pgsql)"
|
throw (T `
|
||||||
|
"bundled_postgres_missing: incomplete package (expected $pgsql). Offline Setup must include postgres; rebuild with build_release.ps1 on a machine that already ran download_postgres.ps1." `
|
||||||
|
"缺少内置 PostgreSQL(期望路径 $pgsql)。离线安装包必须自带数据库;请在已运行过 download_postgres.ps1 的机器上重新 build_release。")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (-not $BundledPassword) {
|
if (-not $BundledPassword) {
|
||||||
if ($NonInteractive) {
|
if ($NonInteractive) {
|
||||||
$BundledPassword = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 24 | ForEach-Object { [char]$_ })
|
$BundledPassword = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 24 | ForEach-Object { [char]$_ })
|
||||||
} else {
|
} else {
|
||||||
$sec = Read-Host -Prompt "Password for bundled role 'netx' (empty = auto-generate)" -AsSecureString
|
$sec = Read-Host -Prompt (T "Password for bundled role 'netx' (empty = auto-generate)" "内置数据库用户 netx 的密码(回车=自动生成)") -AsSecureString
|
||||||
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
|
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
|
||||||
try {
|
try {
|
||||||
$BundledPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
|
$BundledPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
|
||||||
|
|
@ -85,7 +92,7 @@ if ($DbMode -eq "bundled") {
|
||||||
}
|
}
|
||||||
if (-not $BundledPassword) {
|
if (-not $BundledPassword) {
|
||||||
$BundledPassword = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 24 | ForEach-Object { [char]$_ })
|
$BundledPassword = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 24 | ForEach-Object { [char]$_ })
|
||||||
Write-Host "Generated password (saved in .env only)."
|
Write-Host (T "Generated password (saved in .env only)." "已自动生成密码(仅保存在 .env)。")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue