mirror of
https://github.com/Corfirean/coa-server-manager.git
synced 2026-11-11 03:51:01 +00:00
Release Manager 0.6.0 with Chinese localization, realm sync and Linux preview
This commit is contained in:
1 parent
85963b0bf0
commit
162bfd1e04
20 files changed
+1627
-17
No files matched your search
@@ -0,0 +1,28 @@
|
||||
name: check
|
||||
on:
|
||||
push:
|
||||
branches: [master, 'release/**']
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Linux build dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential libxdo-dev libssl-dev librsvg2-dev libayatana-appindicator3-dev
|
||||
- run: npm ci
|
||||
- run: node tools/check-i18n.mjs
|
||||
- run: npm run build
|
||||
- run: cargo test --workspace --locked
|
||||
@@ -0,0 +1,17 @@
|
||||
# CoA Server Manager changelog
|
||||
|
||||
## 0.6.0 — 2026-10-03
|
||||
|
||||
- Added Simplified Chinese for the interface and all server and bot settings.
|
||||
- The closed game client now follows the selected CoA or Wildcard realm. Play checks the saved realm before launching; existing settings are preserved and backed up.
|
||||
- Fixed GitHub reports opening Windows Explorer instead of the default browser. Long reports use the clipboard fallback.
|
||||
- Fixed configuration snapshots created in the same millisecond overwriting each other during restore.
|
||||
- Added experimental Linux startup: persistent state uses the XDG data folder, Tailscale detection supports Linux, and a Wayland rendering workaround respects existing user settings.
|
||||
- Added experimental start, stop and status controls for manually prepared Docker servers, with private database networking and a remote console bound to localhost.
|
||||
- Linux extraction restores executable permissions for ELF binaries and scripts, and paths retain case-sensitive filesystem semantics.
|
||||
|
||||
### Availability
|
||||
|
||||
This release ships the Windows installer and signed updater assets. Linux support is a development preview, not a one-click installation flow. Docker installation/database setup, SQL operations and backups, updates, Wildcard realm profiles, and Wine/Proton client launching remain unfinished. Servers must be prepared manually and use Linux binaries built with the packaged configuration layout.
|
||||
|
||||
Server shutdown and starting-zone scaling issues require separate server releases and are not fixed by updating the Manager alone.
|
||||
Generated
+3
-3
@@ -491,7 +491,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "coa-core"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@@ -519,7 +519,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "coa-release"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"coa-core",
|
||||
@@ -528,7 +528,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "coa-server-manager"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"coa-core",
|
||||
"serde",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ resolver = "2"
|
||||
members = ["crates/coa-core", "crates/coa-release", "src-tauri"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-only"
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ no console, no config files, no database tools. Tauri 2 + Rust + React.
|
||||
* **CoA / Wildcard realms.** Choose the active realm on Overview. A server build with Wildcard support is required;
|
||||
the first switch copies world data and creates an empty character database. Accounts are shared, characters and
|
||||
module settings are separate, and only one world runs. Switching a running server saves characters and restarts it.
|
||||
The closed client's saved realm follows this selection and is checked again before PLAY. If the client is open,
|
||||
the change is applied on the next launch through the Manager.
|
||||
CoA companions are unavailable on Wildcard; other optional modules are experimental. Backups include both realms,
|
||||
and database updates apply to both.
|
||||
See [realm profiles and validation](docs/WILDCARD.md).
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: fixed
|
||||
audience: players
|
||||
title: The game client follows the realm selected in the Manager
|
||||
---
|
||||
Switching realms updates the closed client's saved realm automatically. Play checks it again before launch, preventing login attempts to the previous realm. If the client is running, the update waits until the next launch.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: fixed
|
||||
audience: admins
|
||||
title: Configuration snapshots no longer overwrite each other
|
||||
---
|
||||
Snapshots created close together keep separate copies, so restoring a configuration reliably restores the selected snapshot.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: added
|
||||
audience: admins
|
||||
title: Experimental Linux startup and Docker server controls
|
||||
---
|
||||
The Manager can start on Linux and control manually prepared Docker servers. One-click installation, updates, backups and Wine or Proton client launch are not available yet.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: fixed
|
||||
audience: admins
|
||||
title: Problem reports open in the default browser
|
||||
---
|
||||
GitHub reports open in the default browser instead of Windows Explorer. Long reports use the clipboard fallback.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
area: manager
|
||||
type: added
|
||||
audience: admins
|
||||
title: Simplified Chinese is available in the Manager
|
||||
---
|
||||
The interface and server and bot settings are now available in Simplified Chinese. Choose Simplified Chinese in the language selector.
|
||||
@@ -1,6 +1,7 @@
|
||||
//! The game client is a separate object: detected read-only, and touched only in two narrow ways -
|
||||
//! The game client is a separate object: detected read-only, with targeted updates to
|
||||
//! `realmlist.wtf` (backed up first) and the `Interface/AddOns/CoABotUI` folder (backed up when it differs).
|
||||
//! WTF, Cache, other addons and the executable are never modified.
|
||||
//! The selected realm in WTF/Config.wtf is synchronized while the client is closed.
|
||||
//! Cache, other addons and the executable are never modified.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs;
|
||||
@@ -15,6 +16,67 @@ use crate::fsx;
|
||||
pub const ADDON_NAME: &str = "CoABotUI";
|
||||
const EXECUTABLES: [&str; 3] = ["Ascension.exe", "Wow.exe", "WoW.exe"];
|
||||
|
||||
pub fn is_running(client: &Path) -> bool {
|
||||
EXECUTABLES.iter().any(|exe| {
|
||||
let path = client.join(exe);
|
||||
let path = dunce::canonicalize(&path).unwrap_or(path);
|
||||
!crate::process::find_by_exe(&path).is_empty()
|
||||
})
|
||||
}
|
||||
|
||||
fn realm_config(old: &[u8], realm: &str) -> Vec<u8> {
|
||||
let eol: &[u8] = if old.windows(2).any(|w| w == b"\r\n") { b"\r\n" } else { b"\n" };
|
||||
let mut out = Vec::new();
|
||||
let mut replaced = false;
|
||||
for line in old.split_inclusive(|b| *b == b'\n') {
|
||||
let body = line.strip_prefix(b"\xef\xbb\xbf").unwrap_or(line);
|
||||
let mut words = body.split(|b| b.is_ascii_whitespace()).filter(|w| !w.is_empty());
|
||||
let matches = words.next().is_some_and(|w| w.eq_ignore_ascii_case(b"SET"))
|
||||
&& words.next().is_some_and(|w| w.eq_ignore_ascii_case(b"realmName"));
|
||||
if matches {
|
||||
if line.starts_with(b"\xef\xbb\xbf") { out.extend_from_slice(b"\xef\xbb\xbf"); }
|
||||
out.extend_from_slice(format!("SET realmName \"{realm}\"").as_bytes());
|
||||
if line.ends_with(b"\r\n") { out.extend_from_slice(b"\r\n"); }
|
||||
else if line.ends_with(b"\n") { out.push(b'\n'); }
|
||||
replaced = true;
|
||||
} else {
|
||||
out.extend_from_slice(line);
|
||||
}
|
||||
}
|
||||
if !replaced {
|
||||
if !out.is_empty() && !out.ends_with(b"\n") { out.extend_from_slice(eol); }
|
||||
out.extend_from_slice(format!("SET realmName \"{realm}\"").as_bytes());
|
||||
out.extend_from_slice(eol);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn sync_realm(client: &Path, meta: &Path, mode: crate::realms::Mode) -> Result<bool> {
|
||||
sync_realm_when_closed(client, meta, mode, is_running(client))
|
||||
}
|
||||
|
||||
fn sync_realm_when_closed(client: &Path, meta: &Path, mode: crate::realms::Mode, running: bool) -> Result<bool> {
|
||||
if running { return Ok(false); }
|
||||
let file = client.join("WTF/Config.wtf");
|
||||
let old = match fs::read(&file) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Vec::new(),
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
let realm = match mode {
|
||||
crate::realms::Mode::Coa => "Conquest of Azeroth",
|
||||
crate::realms::Mode::Wildcard => "Wildcard",
|
||||
};
|
||||
let new = realm_config(&old, realm);
|
||||
if new == old { return Ok(true); }
|
||||
if file.exists() {
|
||||
let saved = backup_dir(meta).join(format!("config-realm-{}.wtf", uuid::Uuid::new_v4()));
|
||||
fsx::atomic_write(&saved, &old)?;
|
||||
}
|
||||
fsx::atomic_write(&file, &new)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct Realmlist {
|
||||
pub path: String,
|
||||
@@ -253,6 +315,45 @@ pub fn launch(client: &Path) -> Result<u32> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn realm_selection_preserves_other_settings_bytes_and_line_endings() {
|
||||
let old = b"\xef\xbb\xbfSET realmName \"Wildcard\"\r\nSET accountName \"\xff\"\r\nset REALMNAME \"old\"\r\nSET realmList \"127.0.0.1\"";
|
||||
let expected = b"\xef\xbb\xbfSET realmName \"Conquest of Azeroth\"\r\nSET accountName \"\xff\"\r\nSET realmName \"Conquest of Azeroth\"\r\nSET realmList \"127.0.0.1\"";
|
||||
assert_eq!(realm_config(old, "Conquest of Azeroth"), expected);
|
||||
assert_eq!(realm_config(b"SET sound 1", "Wildcard"), b"SET sound 1\nSET realmName \"Wildcard\"\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn realm_sync_backs_up_config_and_is_idempotent() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let c = fake_client(d.path());
|
||||
let meta = d.path().join("meta");
|
||||
let original = b"SET sound 1\r\nSET realmName \"Wildcard\"\r\n";
|
||||
fs::write(c.join("WTF/Config.wtf"), original).unwrap();
|
||||
assert!(sync_realm(&c, &meta, crate::realms::Mode::Coa).unwrap());
|
||||
let backups: Vec<_> = fs::read_dir(backup_dir(&meta)).unwrap().flatten().collect();
|
||||
assert_eq!(backups.len(), 1);
|
||||
assert_eq!(fs::read(backups[0].path()).unwrap(), original);
|
||||
assert!(sync_realm(&c, &meta, crate::realms::Mode::Coa).unwrap());
|
||||
assert_eq!(fs::read_dir(backup_dir(&meta)).unwrap().count(), 1);
|
||||
assert!(sync_realm(&c, &meta, crate::realms::Mode::Wildcard).unwrap());
|
||||
assert_eq!(fs::read(c.join("WTF/Config.wtf")).unwrap(), original);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn running_client_defers_realm_update_until_closed() {
|
||||
let d = tempfile::tempdir().unwrap();
|
||||
let c = fake_client(d.path());
|
||||
let meta = d.path().join("meta");
|
||||
let original = b"SET realmName \"Wildcard\"\n";
|
||||
fs::write(c.join("WTF/Config.wtf"), original).unwrap();
|
||||
assert!(!sync_realm_when_closed(&c, &meta, crate::realms::Mode::Coa, true).unwrap());
|
||||
assert_eq!(fs::read(c.join("WTF/Config.wtf")).unwrap(), original);
|
||||
assert!(!backup_dir(&meta).exists());
|
||||
assert!(sync_realm_when_closed(&c, &meta, crate::realms::Mode::Coa, false).unwrap());
|
||||
assert_eq!(fs::read(c.join("WTF/Config.wtf")).unwrap(), b"SET realmName \"Conquest of Azeroth\"\n");
|
||||
}
|
||||
|
||||
fn fake_client(d: &Path) -> PathBuf {
|
||||
let c = d.join("wow");
|
||||
fs::create_dir_all(c.join("Data/enUS")).unwrap();
|
||||
|
||||
@@ -363,6 +363,7 @@ fn game_args(cfg: &Config, n: &Names, kind: GameKind, host: &Path, port: u16, ra
|
||||
// on every interface of the container (the published address decides who can connect).
|
||||
let env = |k: &str, v: &str| ["--env".to_string(), format!("{k}={v}")];
|
||||
a.extend(env("AC_BIND_IP", "0.0.0.0"));
|
||||
a.extend(env(if kind == GameKind::World { "AC_WORLD_SERVER_PORT" } else { "AC_REALM_SERVER_PORT" }, &inner_port.to_string()));
|
||||
a.extend(env("AC_LOGS_DIR", &format!("{CORE}/Logs")));
|
||||
// The Manager applies database updates itself. The server's own updater would need a `mysql` client program inside
|
||||
// the container and stops the server when it cannot find one.
|
||||
@@ -374,6 +375,7 @@ fn game_args(cfg: &Config, n: &Names, kind: GameKind, host: &Path, port: u16, ra
|
||||
a.extend(["--publish".into(), format!("127.0.0.1:{ra_port}:{RA_PORT}")]);
|
||||
a.extend(env("AC_RA_ENABLE", "1"));
|
||||
a.extend(env("AC_RA_IP", "0.0.0.0"));
|
||||
a.extend(env("AC_RA_PORT", &RA_PORT.to_string()));
|
||||
// Saving every character can take a while.
|
||||
a.extend(["--stop-timeout".into(), "180".into()]);
|
||||
a.extend(["--env".into(), "AC_WORLD_DATABASE_INFO".into(), "--env".into(), "AC_CHARACTER_DATABASE_INFO".into()]);
|
||||
@@ -705,6 +707,21 @@ mod tests {
|
||||
assert!(runs[2].args.iter().any(|a| a == "0.0.0.0:3724:3724"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_host_ports_keep_the_container_listeners_on_the_mapped_ports() {
|
||||
let (_d, root) = server("ports");
|
||||
let cfg = Config::load(&root).unwrap();
|
||||
let n = cfg.names();
|
||||
let world = game_args(&cfg, &n, GameKind::World, &root, 18085, 13443, None);
|
||||
let auth = game_args(&cfg, &n, GameKind::Auth, &root, 13724, 0, None);
|
||||
assert!(world.iter().any(|a| a == "127.0.0.1:18085:8085"));
|
||||
assert!(world.iter().any(|a| a == "127.0.0.1:13443:3443"));
|
||||
assert!(world.iter().any(|a| a == "AC_WORLD_SERVER_PORT=8085"));
|
||||
assert!(world.iter().any(|a| a == "AC_RA_PORT=3443"));
|
||||
assert!(auth.iter().any(|a| a == "127.0.0.1:13724:3724"));
|
||||
assert!(auth.iter().any(|a| a == "AC_REALM_SERVER_PORT=3724"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_second_start_leaves_running_containers_alone() {
|
||||
let (_d, root) = server("t1");
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "coa-server-manager",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "coa-server-manager",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.12.0",
|
||||
"@tauri-apps/plugin-dialog": "^2.8.0",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "coa-server-manager",
|
||||
"private": true,
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"license": "AGPL-3.0-only",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
+14
-2
@@ -545,6 +545,10 @@ async fn realm_select(state: State<'_, AppState>, id: String, mode: coa_core::re
|
||||
if !out.ok { return Err(Error::Invalid(out.output)); }
|
||||
}
|
||||
let view = coa_core::realms::select(&root, mode)?;
|
||||
let (dir, meta) = install_meta(&root)?;
|
||||
if let Some(client) = meta.client_path {
|
||||
coa_core::client::sync_realm(std::path::Path::new(&client), &dir, view.active)?;
|
||||
}
|
||||
if restart {
|
||||
let out = driver::run(&root, Verb::StartAll)?;
|
||||
if !out.ok { return Err(Error::Invalid(format!("Realm selected, but startup failed: {}", out.output))); }
|
||||
@@ -1120,19 +1124,27 @@ fn end_client_job(state: &AppState) {
|
||||
#[tauri::command]
|
||||
async fn play(state: State<'_, AppState>, id: String) -> std::result::Result<DriverOutcome, UiError> {
|
||||
let root = path_of(&state, &id)?;
|
||||
let (_, _, client) = client_of(&root)?;
|
||||
let (dir, _, client) = client_of(&root)?;
|
||||
let client = client.unwrap();
|
||||
if coa_core::client::is_running(&client) {
|
||||
return Err(Error::Invalid("Close the game client before pressing Play so its selected realm can be updated.".into()).into());
|
||||
}
|
||||
let ready = {
|
||||
let o = coa_core::process::observe(&root, &layout::read_ports(&root));
|
||||
[&o.mysql, &o.auth, &o.world].iter().all(|s| s.state == coa_core::process::ServiceState::Running)
|
||||
};
|
||||
if !ready {
|
||||
let out = run_verb(&state, id, Verb::StartAll).await?;
|
||||
let out = run_verb(&state, id.clone(), Verb::StartAll).await?;
|
||||
if !out.ok {
|
||||
return Ok(out);
|
||||
}
|
||||
}
|
||||
let _guard = BusyGuard::acquire(&state, &id)?;
|
||||
blocking(move || {
|
||||
let mode = coa_core::realms::state(&root)?.active;
|
||||
if !coa_core::client::sync_realm(&client, &dir, mode)? {
|
||||
return Err(Error::Invalid("Close the game client before pressing Play so its selected realm can be updated.".into()));
|
||||
}
|
||||
coa_core::client::launch(&client)?;
|
||||
Ok(DriverOutcome { ok: true, exit_code: None, code: None, human: None, output: String::new() })
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "CoA Server Manager",
|
||||
"version": "0.5.0",
|
||||
"version": "0.6.0",
|
||||
"identifier": "com.coa.servermanager",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
+6
-3
@@ -4,12 +4,14 @@ import ru from "./locales/ru";
|
||||
import de from "./locales/de";
|
||||
import fr from "./locales/fr";
|
||||
import es from "./locales/es";
|
||||
import zh from "./locales/zh";
|
||||
import ruSchema from "./schema/ru.json";
|
||||
import deSchema from "./schema/de.json";
|
||||
import frSchema from "./schema/fr.json";
|
||||
import esSchema from "./schema/es.json";
|
||||
import zhSchema from "./schema/zh.json";
|
||||
|
||||
export type Locale = "en" | "ru" | "de" | "fr" | "es";
|
||||
export type Locale = "en" | "ru" | "de" | "fr" | "es" | "zh";
|
||||
export type Key = keyof typeof en;
|
||||
type Vars = Record<string, string | number>;
|
||||
|
||||
@@ -19,9 +21,10 @@ export const LOCALES: { id: Locale; name: string }[] = [
|
||||
{ id: "de", name: "Deutsch" },
|
||||
{ id: "fr", name: "Français" },
|
||||
{ id: "es", name: "Español" },
|
||||
{ id: "zh", name: "简体中文" },
|
||||
];
|
||||
|
||||
const DICTS: Record<Locale, Partial<Record<Key, string>>> = { en, ru, de, fr, es };
|
||||
const DICTS: Record<Locale, Partial<Record<Key, string>>> = { en, ru, de, fr, es, zh };
|
||||
const STORAGE_KEY = "coa-locale";
|
||||
|
||||
function initialLocale(): Locale {
|
||||
@@ -95,7 +98,7 @@ interface SchemaOverlay {
|
||||
options: Record<string, string>;
|
||||
presets: Record<string, { t: string; d: string }>;
|
||||
}
|
||||
const SCHEMA: Partial<Record<Locale, SchemaOverlay>> = { ru: ruSchema, de: deSchema, fr: frSchema, es: esSchema };
|
||||
const SCHEMA: Partial<Record<Locale, SchemaOverlay>> = { ru: ruSchema, de: deSchema, fr: frSchema, es: esSchema, zh: zhSchema };
|
||||
|
||||
export function useSchemaText() {
|
||||
const { locale } = useContext(I18n);
|
||||
|
||||
@@ -0,0 +1,794 @@
|
||||
/** Simplified Chinese localization (zh-CN) */
|
||||
const zh = {
|
||||
"realm.profileLabel": "服务器",
|
||||
"realm.switching": "正在切换服务器…",
|
||||
"realm.create": "创建 Wildcard 服务器",
|
||||
"realm.restart": "切换并重启",
|
||||
"realm.select": "选择服务器",
|
||||
"realm.active": "当前活跃:{name}",
|
||||
"realm.separate": "同时仅运行一个世界服务器。每个服务器保留独立的角色、进度和模块设置。",
|
||||
"realm.modules": "此处无法使用 CoA 随从。动态难度等级缩放及其他模块在 Wildcard 上仍处于实验阶段。",
|
||||
"realm.update": "请先将服务器更新至支持 Wildcard 的版本以创建此服务器。",
|
||||
"realm.recovery": "服务器切换被中断。请选择一个服务器以恢复保存的配置。",
|
||||
"realm.unsupported": "在 Wildcard 上不可用:职业机制尚未验证通过。",
|
||||
"realm.experimental": "在 Wildcard 上处于实验阶段 · 游戏玩法兼容性尚未验证。",
|
||||
"app.name": "CoA Server Manager",
|
||||
|
||||
"nav.overview": "概览",
|
||||
"nav.bots": "机器人",
|
||||
"nav.server": "服务器",
|
||||
"nav.players": "玩家",
|
||||
"nav.friends": "好友联机",
|
||||
"nav.backups": "备份",
|
||||
"nav.console": "控制台",
|
||||
"nav.settings": "设置",
|
||||
"nav.addAnother": "管理另一个服务器",
|
||||
"nav.main": "主要",
|
||||
"nav.serverPicker": "服务器",
|
||||
|
||||
"q.overview": "服务器当前是否正在运行?",
|
||||
"q.bots": "机器人目前是如何配置的?",
|
||||
"q.server": "服务器机制与规则是如何运行的?",
|
||||
"q.players": "当前有哪些玩家在线?",
|
||||
"q.friends": "好友如何加入我的服务器?",
|
||||
"q.backups": "我的数据是否安全?",
|
||||
"q.console": "服务器正在输出什么日志?",
|
||||
"q.settings": "管理器自身如何运行?",
|
||||
|
||||
"welcome.title": "欢迎使用 CoA Server Manager",
|
||||
"welcome.subtitle": "轻松运行专属的征服艾泽拉斯 (CoA) 服务器 —— 无需任何技术知识。",
|
||||
"welcome.install.title": "安装全新服务器",
|
||||
"welcome.install.text": "一键自动配置,包含运行所需的所有内容。",
|
||||
"welcome.import.title": "已有服务器",
|
||||
"welcome.import.text": "添加现有服务器。仅进行读取,不会更改任何原始文件。",
|
||||
"welcome.back": "返回我的服务器",
|
||||
|
||||
"overview.server": "服务器",
|
||||
"overview.database": "数据库",
|
||||
"overview.auth": "登录服务器",
|
||||
"overview.world": "世界服务器",
|
||||
"overview.uptime": "运行时间",
|
||||
"overview.players": "在线玩家",
|
||||
"overview.companions": "+ {n} 名随从",
|
||||
"overview.checking": "正在检查服务器状态…",
|
||||
"overview.partial": "部分服务正在运行。点击“启动”运行其余服务,或点击“停止”完全关闭。",
|
||||
"overview.portTitle": "服务器所需的端口已被占用",
|
||||
"overview.portText": "端口 {port} 正在被其他程序占用:{exe}。",
|
||||
"overview.missingTitle": "未找到服务器文件夹",
|
||||
"overview.missingText": "{path} 缺失或已被移动。",
|
||||
"overview.forget": "从管理器中移除(不会删除任何文件)",
|
||||
|
||||
"status.online": "在线",
|
||||
"status.offline": "离线",
|
||||
"status.starting": "正在启动…",
|
||||
"status.stopping": "正在停止…",
|
||||
"status.attention": "需要注意",
|
||||
"status.running": "运行中",
|
||||
"status.stopped": "已停止",
|
||||
|
||||
"btn.start": "启动服务器",
|
||||
"btn.stop": "停止服务器",
|
||||
"btn.stopSmall": "停止",
|
||||
"btn.restart": "重启",
|
||||
"btn.play": "开始游戏",
|
||||
"btn.startPlay": "启动并开始游戏",
|
||||
"btn.startingCaps": "正在启动…",
|
||||
"btn.stoppingCaps": "正在停止…",
|
||||
|
||||
"common.viewDetails": "查看详情",
|
||||
"common.hideDetails": "隐藏详情",
|
||||
"common.copyError": "复制错误信息",
|
||||
"common.noOutput": "(无输出)",
|
||||
"common.cancel": "取消",
|
||||
"common.save": "保存",
|
||||
|
||||
"settings.title": "设置",
|
||||
"settings.language": "语言",
|
||||
"settings.languageHint": "选择程序界面语言。翻译由母语者校对;尚未翻译的内容将显示为英文。",
|
||||
|
||||
"err.database_not_running.title": "数据库未运行",
|
||||
"err.database_not_running.message": "服务器启动需要数据库支持。请先启动数据库。",
|
||||
"err.port_in_use.title": "服务器端口已被占用",
|
||||
"err.port_in_use.message": "其他程序(或另一个服务器)正在使用此服务器所需的端口。",
|
||||
"err.server_files_incomplete.title": "服务器文件不完整",
|
||||
"err.server_files_incomplete.message": "部分服务器文件缺失或损坏。",
|
||||
"err.world_db_incompatible.title": "世界数据库与当前版本不兼容",
|
||||
"err.world_db_incompatible.message": "此服务器版本启动前需要先执行数据库更新。",
|
||||
"err.worldserver_already_running.title": "另一个 worldserver 进程已在运行",
|
||||
"err.worldserver_already_running.message": "请在启动此服务器前先停止另一个服务器。",
|
||||
"err.invalid_config_value.title": "服务器配置包含无效值",
|
||||
"err.invalid_config_value.message": "请修正高亮显示的设置并重新保存。",
|
||||
"err.disk_full.title": "磁盘可用空间不足",
|
||||
"err.disk_full.message": "请清理部分空间或选择其他驱动器,然后重试。",
|
||||
"err.operation_in_progress.title": "另一项操作仍在进行中",
|
||||
"err.operation_in_progress.message": "服务器正忙于启动或停止。请稍等片刻后重试。",
|
||||
"err.startup_failed.title": "服务器无法启动",
|
||||
"err.startup_failed.message": "某个服务在启动过程中停止。请查看详细信息了解原因。",
|
||||
"err.hash_mismatch.title": "下载的文件已损坏",
|
||||
"err.hash_mismatch.message": "文件校验和不匹配,已放弃使用。",
|
||||
"err.path_rejected.title": "不允许使用该路径",
|
||||
"err.path_rejected.message": "请求的文件路径超出了服务器文件夹范围。",
|
||||
"err.unknown.title": "出现异常",
|
||||
"err.unknown.message": "请查看技术详情。",
|
||||
|
||||
// Import server
|
||||
"import.title": "添加现有服务器",
|
||||
"import.subtitle": "选择服务器运行所在的文件夹。仅进行读取。",
|
||||
"import.dialogTitle": "选择服务器文件夹",
|
||||
"import.choose": "选择文件夹…",
|
||||
"import.chooseAnother": "选择其他文件夹",
|
||||
"import.looking": "正在检查服务器…",
|
||||
"import.healthy.title": "检测到现有服务器",
|
||||
"import.healthy.text": "运行此服务器所需的所有文件均已找到。",
|
||||
"import.partial.title": "服务器部分文件已找到",
|
||||
"import.partial.text": "缺少部分组件。你仍可添加它;不会自动修复任何内容。",
|
||||
"import.custom.title": "检测到自定义服务器",
|
||||
"import.custom.text": "无法识别该构建版本。部分更新和安装功能将被禁用。",
|
||||
"import.incompatible.title": "这不是有效的服务器文件夹",
|
||||
"import.incompatible.text": "请选择主服务器文件夹:即包含 Core、Data、mysql、Scripts 和 Settings 的文件夹(而不是 Core 文件夹本身)。",
|
||||
"import.techDetails": "显示技术详情",
|
||||
"import.detected": "已检测到",
|
||||
"import.notInstalled": "未安装",
|
||||
"import.notFound": "未找到",
|
||||
"import.noChanges": "导入过程中不会更改任何文件。",
|
||||
"import.add": "添加服务器",
|
||||
|
||||
// Install server
|
||||
"install.title": "安装全新服务器",
|
||||
"install.subtitle": "选择一个文件夹,或使用推荐位置。其余所有配置都会为你自动完成。",
|
||||
"install.installTo": "安装到",
|
||||
"install.browse": "浏览…",
|
||||
"install.dialogTitle": "选择服务器安装位置",
|
||||
"install.pkgDialogTitle": "选择服务器离线安装包文件夹",
|
||||
"install.ready": "此文件夹已就绪。剩余可用空间 {gb} GB。",
|
||||
"install.failedTitle": "安装未能完成",
|
||||
"install.nothingInstalled": "未安装任何内容。你可以重试;已下载的文件会保留。",
|
||||
"install.showTech": "显示技术详情",
|
||||
"install.hideTech": "隐藏技术详情",
|
||||
"install.advanced": "高级选项",
|
||||
"install.localPkg": "从本地离线包文件夹安装,无需在线下载",
|
||||
"install.localPkgHint": "(留空则在线下载)",
|
||||
"install.button": "安装",
|
||||
"install.progressTitle": "正在准备服务器",
|
||||
"install.progressText": "这可能需要几分钟。你可以保持此窗口开启。",
|
||||
"install.step.checking": "检查电脑环境",
|
||||
"install.step.downloading": "下载服务器",
|
||||
"install.step.unpacking": "解压文件",
|
||||
"install.step.database": "准备数据库",
|
||||
"install.step.finishing": "完成安装",
|
||||
"install.doneTitle": "服务器已就绪",
|
||||
"install.doneText": "所有组件均已安装完成。可在下一个界面中启动它。",
|
||||
"install.open": "打开我的服务器",
|
||||
|
||||
// Players
|
||||
"players.title": "玩家",
|
||||
"players.createTitle": "创建游戏账号",
|
||||
"players.createText": "用于登录游戏的账号名称和密码。",
|
||||
"players.startFirst": "请先启动服务器 —— 账号需要在服务器运行时创建。",
|
||||
"players.username": "账号名",
|
||||
"players.password": "密码",
|
||||
"players.admin": "设为管理员账号",
|
||||
"players.adminHint": "管理员可以在游戏中使用 GM 命令。请仅对信任的账号开启。",
|
||||
"players.create": "创建账号",
|
||||
"players.created": "账号“{name}”创建成功。现在可以使用它登录游戏了。",
|
||||
|
||||
// Companions
|
||||
"comp.title": "AI 随从伙伴",
|
||||
"comp.population": "当前在线 {online} · 共创建 {total}",
|
||||
"comp.reading": "正在读取当前人口…",
|
||||
"comp.startToSee": "启动服务器以查看在线随从数量。",
|
||||
"comp.wantMore": "想要添加更多随从吗?",
|
||||
"comp.custom": "自定义",
|
||||
"comp.numberLabel": "随从数量",
|
||||
"comp.largeWarning": "较大的人口规模可能需要更多 CPU 和内存。建议逐步增加。",
|
||||
"comp.hardware": "当前电脑:{cores} 核心,{ram} GB 内存。",
|
||||
"comp.add": "添加 {n} 名随从",
|
||||
"comp.addPlain": "添加随从",
|
||||
"comp.stoppedHint": "服务器已停止:随从将在下次服务器运行时创建。",
|
||||
"comp.spawned": "正在创建 {n} 名随从。它们将在接下来的几分钟内陆续上线。",
|
||||
"comp.saved": "已保存。{n} 名随从将在服务器启动时创建。",
|
||||
|
||||
// Client
|
||||
"client.title": "游戏客户端",
|
||||
"client.looking": "正在寻找…",
|
||||
"client.intro": "指定游戏客户端安装路径即可启用“开始游戏”按钮。除服务器地址和随从插件外,你的游戏文件绝不会被修改。",
|
||||
"client.chooseFolder": "选择游戏文件夹…",
|
||||
"client.dialogTitle": "选择游戏客户端文件夹",
|
||||
"client.connectsTo": "连接到",
|
||||
"client.thisComputer": "✓ 本机",
|
||||
"client.notThisServer": "非此服务器",
|
||||
"client.addon": "随从管理插件",
|
||||
"client.installedVersion": "已安装 (版本 {v})",
|
||||
"client.installed": "已安装",
|
||||
"client.addonNotInstalled": "未安装",
|
||||
"client.updateAvailable": "有可用更新",
|
||||
"client.otherAddons": "其他插件",
|
||||
"client.leftAsIs": "{n} 个 —— 完全保持原样",
|
||||
"client.pointLocal": "将游戏连接指向此服务器",
|
||||
"client.pointedNote": "游戏现在将连接到本机。先前的地址已备份保存。",
|
||||
"client.installAddon": "安装随从插件",
|
||||
"client.updateAddon": "更新随从插件",
|
||||
"client.addonNote": "随从插件已安装。其他插件未受任何影响。",
|
||||
"client.changeFolder": "更换文件夹…",
|
||||
|
||||
// Diagnostics
|
||||
"diag.title": "诊断",
|
||||
"diag.text": "检查常见问题。不会修改任何文件。",
|
||||
"diag.run": "运行诊断",
|
||||
"diag.verify": "校验服务器文件",
|
||||
"diag.export": "导出诊断包",
|
||||
"diag.saved": "已保存供问题反馈使用:{path}",
|
||||
"diag.allGood": "一切运行正常。",
|
||||
"diag.problems_one": "发现 {n} 处需要注意",
|
||||
"diag.problems_few": "发现 {n} 处需要注意",
|
||||
"diag.problems_many": "发现 {n} 处需要注意",
|
||||
"diag.problems_other": "发现 {n} 处需要注意",
|
||||
"diag.word.ok": "正常",
|
||||
"diag.word.warn": "注意",
|
||||
"diag.word.fail": "异常",
|
||||
"diag.filesOk": "所有程序文件完好无损。",
|
||||
"diag.filesDiffer": "{n} 个程序文件与原始安装不一致。你自己的配置文件绝不会出现在这里。“检查更新”可恢复缺失的文件。",
|
||||
"diag.fileMissing": "缺失",
|
||||
"diag.fileChanged": "已修改",
|
||||
|
||||
// About Manager
|
||||
"about.version": "版本 {v}。程序本身的更新绝不会改动你的服务器数据。",
|
||||
"about.check": "检查新版本",
|
||||
"about.install": "安装 {v} 并重启",
|
||||
"about.upToDate": "CoA Server Manager 已是最新版本。",
|
||||
"about.checkFailed": "检查新版本失败。请检查网络连接后重试。",
|
||||
"about.installFailed": "无法安装更新。你的服务器未受任何影响。",
|
||||
|
||||
// Backups
|
||||
"bk.title": "备份",
|
||||
"bk.trigger.manual": "手动备份",
|
||||
"bk.trigger.automatic": "自动备份",
|
||||
"bk.trigger.before-update": "更新前自动备份",
|
||||
"bk.trigger.before-restore": "还原前安全备份",
|
||||
"bk.trigger.before-migration": "数据库升级前备份",
|
||||
"bk.trigger.before-bots": "安装随从前备份",
|
||||
"bk.trigger.before-repair": "修复前备份",
|
||||
"bk.trigger.before-dangerous-change": "高风险更改前备份",
|
||||
"bk.kind.quick": "角色、账号与设置",
|
||||
"bk.kind.full": "完整数据(含世界数据库)",
|
||||
"bk.kind.config": "仅配置文件",
|
||||
"bk.kind.database": "角色与账号数据",
|
||||
"bk.db.characters": "角色数据",
|
||||
"bk.db.auth": "账号数据",
|
||||
"bk.db.world": "世界数据",
|
||||
"bk.today": "今天 {time}",
|
||||
"bk.yesterday": "昨天 {time}",
|
||||
"bk.created": "备份创建成功。",
|
||||
"bk.last": "上次备份:{when}",
|
||||
"bk.none": "暂无备份",
|
||||
"bk.keptNext": "备份存放在服务器目录旁,绝不会覆盖你的线上数据。",
|
||||
"bk.backUpNow": "立即备份",
|
||||
"bk.full": "完整备份",
|
||||
"bk.fullHint": "同时保存体积较大的世界数据库",
|
||||
"bk.settingsOnly": "仅配置文件",
|
||||
"bk.working": "正在处理…",
|
||||
"bk.failed": "操作未能完成",
|
||||
"bk.restoreFrom": "还原来自 {what} 的备份({when})",
|
||||
"bk.restoreNote": "不会删除任何数据。当前数据会先被安全备份,被替换的数据库将以新名称保留。",
|
||||
"bk.stopFirst": "请先停止服务器 —— 数据库仅可在服务器停止时还原。",
|
||||
"bk.settingsRestored": "设置已还原。先前的配置已生成安全副本。",
|
||||
"bk.restoreSettings": "还原设置",
|
||||
"bk.confirmDb": "是否从该备份还原 {db} 数据库?自 {when} 以来的新进度将被归档保留(不会被删除)。",
|
||||
"bk.dbRestored": "成功还原 {n} 张数据表。先前的数据已保留为 {schema}。",
|
||||
"bk.restoreDb": "还原 {db}",
|
||||
"bk.loading": "正在加载…",
|
||||
"bk.empty": "你的备份将显示在此处。",
|
||||
"bk.restore": "还原",
|
||||
"bk.verify": "校验",
|
||||
"bk.intact": "该备份完整无损。",
|
||||
"bk.problem": "发现问题:{details}",
|
||||
"bk.delete": "删除",
|
||||
"bk.confirmDelete": "确定删除此备份吗?仅会删除此备份文件,服务器本身不受影响。",
|
||||
|
||||
// Friends
|
||||
"fr.title": "好友联机",
|
||||
"fr.looking": "正在检测连接状态…",
|
||||
"fr.ok": "正常",
|
||||
"fr.notYet": "尚未就绪",
|
||||
"fr.mode.lan.title": "局域网联机",
|
||||
"fr.mode.lan.text": "适用于处于同一家庭网络或 Wi-Fi 下的好友。",
|
||||
"fr.mode.direct.title": "公网直连",
|
||||
"fr.mode.direct.text": "跨互联网联机。需要你的路由器支持并开放端口映射。",
|
||||
"fr.mode.private.title": "虚拟私有网",
|
||||
"fr.mode.private.text": "跨互联网联机,无需配置路由器。使用免费的 Tailscale 软件。",
|
||||
"fr.restartToApply": "重启服务器以使配置生效。",
|
||||
"fr.ready": "已准备好接受好友连接。",
|
||||
"fr.exposedTitle": "私有服务正暴露在网络中",
|
||||
"fr.exposedText": "{what} 当前允许来自其他电脑的连接。请通过本管理器重启服务器以关闭外部访问。",
|
||||
"fr.what.database": "数据库",
|
||||
"fr.what.console": "服务器控制台",
|
||||
"fr.and": " 和 ",
|
||||
"fr.status": "状态",
|
||||
"fr.st.running": "服务器正在运行",
|
||||
"fr.st.open": "登录与游戏服务器已向其他电脑开放",
|
||||
"fr.st.firewall": "Windows 防火墙已放行游戏端口",
|
||||
"fr.st.private": "数据库与控制台仅限本机访问",
|
||||
"fr.inUse": "使用中",
|
||||
"fr.yourLan": "你在局域网中的 IP 地址:",
|
||||
"fr.unknown": "未知",
|
||||
"fr.checkConn": "检查我的网络连接",
|
||||
"fr.cgnat": "你的宽带运营商处于大内网环境 (CGNAT),不支持公网直连。请改用虚拟私有网模式。",
|
||||
"fr.publicAddr": "你的公网 IP 地址:",
|
||||
"fr.noRouter": " · 路由器无法自动设置;请手动转发两个游戏端口",
|
||||
"fr.noInternet": "无法连接到互联网以获取公网 IP 地址。",
|
||||
"fr.tsMissing": "尚未安装 Tailscale。请下载并安装该免费应用、登录账号后重试。",
|
||||
"fr.tsOff": "Tailscale 已安装但未连接。请先登录该软件。",
|
||||
"fr.privateAddr": "你的私有 IP 地址:",
|
||||
"fr.checkFirst": "请先检测网络连接",
|
||||
"fr.reapply": "重新应用",
|
||||
"fr.enable": "启用",
|
||||
"fr.onlyLocal": "当前仅限本机连接。",
|
||||
"fr.stopSharing": "停止共享(仅本机连接)",
|
||||
"fr.giveTitle": "将此信息发送给好友",
|
||||
"fr.giveText": "好友只需将这行配置写入游戏客户端的 realmlist.wtf 文件。密码与敏感设置绝不会泄露。",
|
||||
"fr.copied": "已复制",
|
||||
"fr.copy": "复制连接信息",
|
||||
"fr.pkg": "打包好友联机补丁 (zip)",
|
||||
"fr.pkgSaved": "已保存:{path}",
|
||||
|
||||
// Console
|
||||
"con.title": "控制台",
|
||||
"con.tab.world": "世界",
|
||||
"con.tab.auth": "登录",
|
||||
"con.tab.database": "数据库",
|
||||
"con.tab.manager": "管理器",
|
||||
"con.searchLabel": "搜索日志",
|
||||
"con.search": "搜索…",
|
||||
"con.follow": "滚动到底部",
|
||||
"con.copied": "已复制",
|
||||
"con.copyErrors": "仅复制错误日志",
|
||||
"con.empty": "暂无日志输出。",
|
||||
"con.commandsNote": "命令将直接发送给正在运行的世界服务器。高风险操作(关机、删除、封禁)会要求二次确认。",
|
||||
"con.commandLabel": "命令",
|
||||
"con.send": "发送",
|
||||
"con.confirmRisky": "指令“{cmd}”可能导致停机或批量修改数据。确定发送吗?",
|
||||
|
||||
// Server updates
|
||||
"upd.act.create": "新增文件",
|
||||
"upd.act.replace": "已更新",
|
||||
"upd.act.merge-config": "已合并新配置项",
|
||||
"upd.act.skip": "保持不变",
|
||||
"upd.act.conflict": "需要手动决定",
|
||||
"upd.updatedTo": "已成功更新至版本 {v}。",
|
||||
"upd.confirmBack": "是否回滚至上一个版本?你的角色与账号数据不会受到影响。",
|
||||
"upd.wentBack": "已回滚至上一个版本。你的个人数据完好无损。",
|
||||
"upd.dialogTitle": "选择更新包文件夹",
|
||||
"upd.pendingBad": "更新后的服务器未能正常启动",
|
||||
"upd.pendingUnfinished": "先前的更新尚未完成",
|
||||
"upd.safeBack": "你可以安全回滚至先前的稳定版本。",
|
||||
"upd.backNote": "回滚操作将恢复程序文件与配置文件。角色和账号数据绝不会被自动回滚。",
|
||||
"upd.goBackTo": "回滚至版本 {v}",
|
||||
"upd.goBackBefore": "回滚至更新前的版本",
|
||||
"upd.title": "服务器更新",
|
||||
"upd.text": "更新均经过真实性签名校验,并在执行前自动备份,随时可安全撤销。",
|
||||
"upd.check": "检查更新",
|
||||
"upd.folderLabel": "更新包文件夹",
|
||||
"upd.folderHint": "更新包文件夹(留空则从官方源下载)",
|
||||
"upd.available": "检测到新版本 {to}",
|
||||
"upd.availableFrom": "检测到新版本 {to}(当前为 {from})",
|
||||
"upd.summary": "需下载 {size} · 变更 {files} 个文件",
|
||||
"upd.summaryDb": "需下载 {size} · 变更 {files} 个文件 · {db} 次数据库升级",
|
||||
"upd.conflict": "此文件曾在管理器外部被手动修改。",
|
||||
"upd.keep": "保留我的本地文件",
|
||||
"upd.replace": "使用更新覆盖",
|
||||
"upd.now": "立即更新",
|
||||
"upd.stopNote": "更新期间服务器将暂时停止,并在完成后重新启动以验证可用性。",
|
||||
|
||||
// Settings editor
|
||||
"set.restart.runtime": "立即生效",
|
||||
"set.restart.world": "需要重启世界服务器",
|
||||
"set.restart.full": "需要完全重启服务器",
|
||||
"set.on": "开启",
|
||||
"set.off": "关闭",
|
||||
"set.enterNumber": "输入数值",
|
||||
"set.enterInt": "输入整数",
|
||||
"set.atLeast": "不得小于 {n}",
|
||||
"set.atMost": "不得大于 {n}",
|
||||
"set.careful": "谨慎修改",
|
||||
"set.changed": "已修改",
|
||||
"set.default": "默认:{v}",
|
||||
"set.range": "有效范围 {min}–{max}",
|
||||
"set.badValue": "文件中包含无法使用的值 ({problem});当前显示默认值。",
|
||||
"set.drift": "在生成的配置文件中被手动修改 —— 除非在此处保存,否则下次启动时管理器将重置该项。",
|
||||
"set.reset": "恢复默认值",
|
||||
"set.resetItem": "将 {name} 恢复为默认值",
|
||||
"set.nothingYet": "暂无需要配置的内容",
|
||||
"set.loading": "正在加载设置…",
|
||||
"set.confirmCareful": "你正在修改 {n} 项标记为“谨慎修改”的设置。当前配置已先保存为快照以供撤销。是否继续?",
|
||||
"set.driftTitle": "有 {n} 项设置曾在外部被手动修改",
|
||||
"set.driftText": "服务器每次启动都会从模板重新生成 worldserver.conf,以下手动修改的内容将会丢失:",
|
||||
"set.presets": "预设方案:",
|
||||
"set.restoreDefaults": "恢复推荐默认值",
|
||||
"set.matches": "无需更改 —— 你的设置已完全一致。",
|
||||
"set.willChange_one": "将更改 {n} 项设置:",
|
||||
"set.willChange_few": "将更改 {n} 项设置:",
|
||||
"set.willChange_many": "将更改 {n} 项设置:",
|
||||
"set.willChange_other": "将更改 {n} 项设置:",
|
||||
"set.apply": "应用",
|
||||
"set.nothingChanged": "未做任何修改。",
|
||||
"set.saved": "已保存。",
|
||||
"set.restartRequired_one": "应用这 {n} 项设置需要重启服务器。",
|
||||
"set.restartRequired_few": "应用这 {n} 项设置需要重启服务器。",
|
||||
"set.restartRequired_many": "应用这 {n} 项设置需要重启服务器。",
|
||||
"set.restartRequired_other": "应用这 {n} 项设置需要重启服务器。",
|
||||
"set.appliesNextStart": "更改将在下次服务器启动时生效。",
|
||||
"set.restartNow": "立即重启",
|
||||
"set.later": "稍后",
|
||||
"set.notSaved": "未保存任何更改。请修正高亮项后重试。",
|
||||
"set.advanced": "高级设置 ({n})",
|
||||
"set.unknownKept": "配置文件中的其他 {n} 项设置完全保持原样。",
|
||||
"set.unsaved_one": "{n} 项未保存的修改",
|
||||
"set.unsaved_few": "{n} 项未保存的修改",
|
||||
"set.unsaved_many": "{n} 项未保存的修改",
|
||||
"set.unsaved_other": "{n} 项未保存的修改",
|
||||
"set.discard": "放弃修改",
|
||||
"set.save": "保存修改",
|
||||
|
||||
// Download errors
|
||||
"err.package_not_published.title": "该服务器安装包尚未发布",
|
||||
"err.package_not_published.message": "下载源中未找到对应包。请稍后重试,或通过“高级选项”从本地文件夹安装。",
|
||||
"err.network_unreachable.title": "无法连接到下载服务器",
|
||||
"err.network_unreachable.message": "请检查网络连接后重试。",
|
||||
|
||||
// Manager self-update
|
||||
"selfupd.ready": "管理器 {v} 已就绪可安装",
|
||||
"selfupd.onClose": "将在退出管理器时自动安装。你的服务器将继续保持运行。",
|
||||
"selfupd.installing": "正在安装… 管理器即将关闭。",
|
||||
"selfupd.now": "立即安装",
|
||||
"about.auto": "在后台自动下载更新并在退出管理器时安装",
|
||||
"about.autoHint": "管理器的更新绝不会中断或改动你的游戏服务器。",
|
||||
|
||||
// Friends line
|
||||
"fr.copyLine": "复制配置行",
|
||||
|
||||
// Diagnostics checks
|
||||
"dg.title.files": "服务器文件",
|
||||
"dg.title.missing_parts": "缺失组件",
|
||||
"dg.title.mysql": "数据库",
|
||||
"dg.title.auth": "登录服务器",
|
||||
"dg.title.world": "世界服务器",
|
||||
"dg.title.configs": "配置文件",
|
||||
"dg.title.config_values": "配置数值",
|
||||
"dg.title.disk": "磁盘可用空间",
|
||||
"dg.title.permissions": "文件权限",
|
||||
"dg.title.client": "游戏客户端",
|
||||
"dg.title.exposure": "私有服务",
|
||||
"dg.files.ok": "已找到所有预期的服务器组件。",
|
||||
"dg.files.partial": "部分服务器组件缺失。",
|
||||
"dg.files.custom": "这是自定义服务器版本;部分功能受限。",
|
||||
"dg.files.bad": "该文件夹看起来不像有效的 CoA 服务器目录。",
|
||||
"dg.svc.running": "运行中",
|
||||
"dg.svc.port": "端口 {port} 正被其他程序占用 (进程 PID {pid})。",
|
||||
"dg.svc.starting": "正在启动,尚未开始监听响应。",
|
||||
"dg.svc.stopped": "未运行。",
|
||||
"dg.configs.ok": "配置文件读取正常。",
|
||||
"dg.configs.bad": "无法读取以下文件:{files}",
|
||||
"dg.values.bad": "以下项包含无效值:{keys}",
|
||||
"dg.disk.ok": "剩余 {gb} GB 可用空间",
|
||||
"dg.disk.low": "仅剩 {gb} GB 可用空间;备份与更新需要更多存储空间。",
|
||||
"dg.perm.ok": "服务器目录具有正常写入权限。",
|
||||
"dg.perm.bad": "管理器无法写入服务器目录(请尝试更换路径或以管理员身份运行一次)。",
|
||||
"dg.client.missing": "未找到先前设置的游戏客户端路径;请在“设置”中重新选择。",
|
||||
"dg.exposure.ok": "数据库与控制台未向外部网络暴露。",
|
||||
"dg.exposure.bad": "以下服务暴露于外部网络中:{what}。",
|
||||
|
||||
// Update steps
|
||||
"ustep.Starting": "正在启动",
|
||||
"ustep.Checking the update": "正在检查更新",
|
||||
"ustep.Downloading the update": "正在下载更新",
|
||||
"ustep.Verifying the update": "正在校验更新包",
|
||||
"ustep.Making sure the server is stopped": "正在确认服务器已停止",
|
||||
"ustep.Saving a recovery point": "正在创建恢复点",
|
||||
"ustep.Applying the update": "正在应用更新文件",
|
||||
"ustep.Updating the database": "正在更新数据库结构",
|
||||
"ustep.Starting the updated server": "正在启动更新后的服务器",
|
||||
"ustep.Finishing": "正在收尾完成",
|
||||
"ustep.Undoing the update": "正在撤销更新并回滚",
|
||||
"ustep.Done": "已完成",
|
||||
|
||||
// Companion sizes
|
||||
"comp.size.small": "小型",
|
||||
"comp.size.medium": "中型",
|
||||
"comp.size.large": "大型",
|
||||
"comp.warnHardware": "{n} 名随从可能需要超出本机硬件配置的 CPU 和内存资源(本机:{cores} 核,{ram} GB)。",
|
||||
"comp.warnMemory": "请先释放部分系统内存;其他程序当前占用了大部分可用内存。",
|
||||
|
||||
// Friends notes
|
||||
"fr.note.forwarded": "已向路由器请求自动端口映射。",
|
||||
"fr.note.manual": "你的路由器不支持自动端口映射;请手动转发两个游戏端口或使用虚拟私有网。",
|
||||
|
||||
// Import labels and placeholder
|
||||
"scan.label.worldserver": "世界服务器 (worldserver)",
|
||||
"scan.label.authserver": "登录服务器 (authserver)",
|
||||
"scan.label.database_content": "账号 / 角色 / 世界数据库",
|
||||
"scan.label.companions": "CoA 随从伙伴 (机器人)",
|
||||
"scan.label.client": "游戏客户端",
|
||||
"placeholder.soon": "该模块将在后续版本中开放支持。",
|
||||
|
||||
// Tick rate
|
||||
"overview.tick": "世界运算帧率",
|
||||
"overview.tickUnit": "次心跳/秒",
|
||||
"overview.tickGood": "流畅",
|
||||
"overview.tickBusy": "负载较高",
|
||||
"overview.tickLag": "存在卡顿",
|
||||
"overview.tickDetail": "平均心跳延迟 {mean} ms · 95% 低于 {p95} ms · 峰值 {max} ms",
|
||||
"overview.tickHint": "世界服务器的循环处理速度。高于每秒 20 次心跳时体验流畅;低于 10 次会出现明显延迟感。",
|
||||
|
||||
// Companions start
|
||||
"err.companion_templates_missing.title": "尚未生成随从模板数据",
|
||||
"err.companion_templates_missing.message": "新随从基于各职业的 80 级角色模板克隆。请在任意普通玩家账号下为每个职业创建一个 80 级角色,然后重试。",
|
||||
|
||||
// Friends guides
|
||||
"fr.tsDownload": "下载 Tailscale (免费)",
|
||||
"fr.guide": "联机配置指南",
|
||||
"fr.g.net.1": "点击“检查我的网络连接”:管理器会自动获取你的公网 IP,并尝试通过 UPnP 自动配置路由器端口转发。",
|
||||
"fr.g.net.2": "如果无法自动打开,请登录路由器管理后台(通常为 192.168.0.1 或 192.168.1.1),找到“端口转发 (Port Forwarding)”或“虚拟服务器 / NAT”。",
|
||||
"fr.g.net.3": "将两个 TCP 端口映射到本机的内网 IP ({lan}):{auth}(登录)与 {world}(游戏)。内外部端口号保持一致。",
|
||||
"fr.g.net.4": "切勿转发数据库端口 (3307) 或服务器控制台端口 (3443)。",
|
||||
"fr.g.net.5": "点击“启用”,重启服务器,并将上方的配置行(“set realmlist …”)发送给好友。好友将其写入游戏目录下的 realmlist.wtf 文件即可。",
|
||||
"fr.g.net.6": "如果你的宽带是运营商大内网 (CGNAT),将无法开放公网端口:请改用下方的虚拟私有网方案。",
|
||||
"fr.g.routerHelp": "常见路由器端口转发分步指南 (portforward.com)",
|
||||
"fr.g.ts.1": "你和好友均下载安装免费的 Tailscale 客户端(上方链接)并登录账号。",
|
||||
"fr.g.ts.2": "将你的电脑共享给好友:打开 Tailscale 后台管理页面,在设备列表中找到本机,选择“Share…”,将邀请链接发给好友。好友在自己的 Tailscale 账号中接受即可。",
|
||||
"fr.g.ts.3": "无需任何路由器配置。点击“启用”,重启服务器,并将包含你 Tailscale IP 的配置行发送给好友。",
|
||||
"fr.g.ts.4": "联机游玩期间双方均需保持 Tailscale 客户端在后台运行。",
|
||||
"fr.g.ts.admin": "打开 Tailscale 管理控制台",
|
||||
"fr.g.ts.share": "了解设备共享机制 (tailscale.com)",
|
||||
|
||||
// Bots at start
|
||||
"comp.startTitle": "服务器启动时随从设置",
|
||||
"comp.startAuto": "服务器启动时自动让随从上线",
|
||||
"comp.startCount": "自动登录随从数量",
|
||||
"comp.startSave": "保存",
|
||||
"comp.startSaved": "已保存。将在下次服务器启动时生效。",
|
||||
"comp.startHint": "未登录的随从仍保留在数据库中,随时可在需要时手动调出上线。",
|
||||
"comp.startInvalid": "请输入 0 到 5000 之间的整数。",
|
||||
|
||||
// Overview start bots
|
||||
"overview.startBots": "开机自动登录随从:{n}",
|
||||
"overview.startBotsOff": "开机自动登录随从:关闭",
|
||||
|
||||
// Offline bots
|
||||
"comp.offlineDone": "已成功创建 {n} 名随从及初始装备。它们将在下次服务器启动时登录游戏。",
|
||||
|
||||
// Companions progress
|
||||
"comp.progress": "已添加 {done} / {target}",
|
||||
"comp.progressDone": "所有 {n} 名随从创建完毕。正在陆续登录上线。",
|
||||
"comp.progressOffline": "正在为 {n} 名随从配置装备与数据… 这需要几分钟时间。",
|
||||
"comp.progressStalled": "正在等待服务器完成批量生成…",
|
||||
|
||||
// Companions control
|
||||
"comp.stop": "停止创建",
|
||||
"comp.stopped": "已停止。排队中的 {n} 名随从已取消创建;已经生成的随从将保留。",
|
||||
"comp.manageTitle": "管理现有随从",
|
||||
"comp.offline": "全部下线",
|
||||
"comp.offlineConfirm": "是否将所有随从踢出游戏?它们的数据仍完好保存在数据库中,可在下次启动或手动添加时重新上线。",
|
||||
"comp.offlineDone2": "已将 {n} 名随从下线。数据已保留。",
|
||||
"comp.delete": "永久删除所有随从…",
|
||||
"comp.deleteConfirm": "是否彻底删除所有 {n} 名随从?系统会先自动保存恢复点。你自己的玩家角色绝不会受影响。",
|
||||
"comp.deleteDone": "所有随从已成功删除。操作前已保存安全恢复点。",
|
||||
"err.companion_command_unsupported.title": "当前服务器核心版本不支持该命令",
|
||||
"err.companion_command_unsupported.message": "当前构建版本的随从模块缺少该指令。请更新服务器,或通过重启服务器来中止当前任务。",
|
||||
|
||||
// Despawn some
|
||||
"comp.despawnSome": "减少 {n} 名随从",
|
||||
"comp.despawnCount": "让多少名随从下线",
|
||||
"comp.despawnHint": "可立即降低服务器负载:每个在线随从都会消耗计算资源。随从数据保留在数据库中,若开启了自动登录则会在下次启动时恢复。",
|
||||
"comp.despawnSomeDone": "已让 {n} 名随从下线。数据已保存。",
|
||||
|
||||
// Server update button
|
||||
"btn.update": "更新",
|
||||
"btn.updating": "正在更新…",
|
||||
"btn.updateTo": "更新至 {v}",
|
||||
"overview.updateAvail": "检测到服务器新版本:{to}(当前为 {from})。",
|
||||
"overview.updateConflicts": "部分文件被你手动修改过。请在“设置”中选择如何处理冲突。",
|
||||
"overview.openUpdates": "打开更新界面",
|
||||
"overview.updatingNote": "正在更新:服务器将自动停止、备份、应用更新并重新启动以验证可用性。",
|
||||
"nav.updateDot": "有可用更新",
|
||||
|
||||
// Game client download and update
|
||||
"btn.close": "关闭",
|
||||
"btn.setupClient": "配置游戏客户端",
|
||||
"btn.updateClient": "更新客户端",
|
||||
"client.setup.title": "配置游戏客户端",
|
||||
"client.setup.intro": "进行游戏需要安装匹配的客户端。你可以关联已有的游戏客户端,也可以让管理器为你自动下载。",
|
||||
"client.setup.have": "已有游戏客户端",
|
||||
"client.setup.download": "下载全新客户端",
|
||||
"client.setup.downloadHint": "约 43 GB",
|
||||
"client.dl.pickParent": "选择游戏客户端存放位置",
|
||||
"client.dl.confirmText": "版本 {v},体积 {size}。将被保存在以下文件夹中:",
|
||||
"client.dl.free": "该驱动器剩余空间:{free}。",
|
||||
"client.dl.notEnough": "磁盘剩余空间不足:需要 {need},可用 {free}。请选择其他驱动器。",
|
||||
"client.dl.otherFolder": "选择其他文件夹…",
|
||||
"client.dl.start": "开始下载",
|
||||
"client.dl.back": "返回",
|
||||
"client.dl.retry": "重试",
|
||||
"client.dl.resume": "继续下载",
|
||||
"client.dl.cancel": "停止",
|
||||
"client.dl.cancelled": "下载已暂停。已下载的文件将被保留;随时可继续断点续传。",
|
||||
"client.dl.scanning": "正在比对文件…",
|
||||
"client.dl.downloading": "正在下载",
|
||||
"client.dl.progress": "{done} / {total}",
|
||||
"client.dl.speed": "{speed}/秒",
|
||||
"client.dl.done": "游戏客户端已就绪",
|
||||
"client.dl.doneText": "已成功关联至此服务器。你可以点击“开始游戏”了。",
|
||||
"client.upd.title": "客户端更新",
|
||||
"client.upd.available": "检测到更新的游戏客户端版本:{v}。",
|
||||
"client.upd.summary": "需下载 {n} 个文件,共计 {size}。",
|
||||
"client.upd.upToDate": "你的客户端已与版本 {v} 完全一致。",
|
||||
"client.upd.modifiedTitle": "检测到 {n} 个文件曾被你修改",
|
||||
"client.upd.modifiedText": "例如打过补丁的可执行程序。你可以选择保留它们,或替换为官方版本;被替换的文件将保存在客户端的 .coa-manager 文件夹中以作备份。图形渲染增强补丁(如 d3d9.dll 等)及配置文件始终会保留原样。",
|
||||
"client.upd.keep": "保留我修改过的文件",
|
||||
"client.upd.more": "… 以及另外 {n} 个",
|
||||
"client.upd.start": "更新客户端",
|
||||
"client.upd.later": "暂不更新",
|
||||
"client.upd.playAnyway": "跳过更新直接进入游戏",
|
||||
"client.upd.done": "游戏客户端已是最新版本",
|
||||
"client.upd.doneText": "当发布更高版本时,管理器会及时提醒你。",
|
||||
"client.track.title": "保持客户端为最新版本",
|
||||
"client.track.text": "管理器会先比对你的客户端与官方版本,并在后续像检查服务器更新一样检测新版本。除非你明确选择,否则你修改过的文件绝不会被自动替换。",
|
||||
"client.track.start": "保持更新",
|
||||
"client.track.startUpdate": "更新并保持同步",
|
||||
"client.track.button": "为该客户端开启自动检查更新…",
|
||||
"client.version": "客户端版本",
|
||||
"client.versionUntracked": "未由管理器追踪",
|
||||
"client.versionUnfinished": "下载尚未完成",
|
||||
"client.downloadInstead": "下载全新客户端…",
|
||||
|
||||
// Accounts panel, password toggle, install size, addon explanation
|
||||
"pw.show": "显示密码",
|
||||
"pw.hide": "隐藏密码",
|
||||
"install.size": "服务器安装将占用约 {size} 磁盘空间。下载包体积为 {download};安装过程中峰值约需 {peak} 临时空间。",
|
||||
"client.addonWhat": "在游戏内通过小地图图标打开的管理面板,用于指挥你的随从:补齐五人小队、分配坦克治疗输出职责与阵型、下达攻击/拉怪/停留等指令,并实时查看他们的装备与任务状态。即使不安装插件游戏也能正常运行,此时随从将完全由其自主 AI 驱动。",
|
||||
"acc.title": "账号管理",
|
||||
"acc.text": "可登录该服务器的所有账号。修改密码及权限需要服务器处于运行状态。",
|
||||
"acc.refresh": "刷新列表",
|
||||
"acc.unavailable": "账号列表当前不可用。请启动服务器后重试。",
|
||||
"acc.empty": "暂无账号。可在上方创建第一个账号。",
|
||||
"acc.col.name": "账号",
|
||||
"acc.col.chars": "角色数量",
|
||||
"acc.col.access": "权限等级",
|
||||
"acc.col.last": "最后登录",
|
||||
"acc.online": "在线",
|
||||
"acc.never": "从未登录",
|
||||
"acc.level.0": "普通玩家",
|
||||
"acc.level.1": "版主 (Moderator)",
|
||||
"acc.level.2": "游戏管理员 (GM)",
|
||||
"acc.level.3": "最高管理员 (Admin)",
|
||||
"acc.changePassword": "修改密码",
|
||||
"acc.rename": "重命名",
|
||||
"acc.needsRunning": "请先启动服务器再管理账号。",
|
||||
"acc.changeFor": "为 {name} 设置新密码",
|
||||
"acc.renameFor": "重命名账号 {name}",
|
||||
"acc.newName": "新账号名称",
|
||||
"acc.newPassword": "新密码",
|
||||
"acc.nameRule": "3–17 位英文字母或数字。",
|
||||
"acc.passRule": "6–16 位字符,不可包含空格或引号。",
|
||||
"acc.renameNote": "由于魔兽认证协议中的密码散列依赖账号名称,重命名后必须设置新密码。玩家将使用新账号名和此密码登录。操作时该账号必须处于离线状态。",
|
||||
"acc.save": "保存",
|
||||
"acc.passwordChanged": "账号 {name} 的密码已成功修改。",
|
||||
"acc.renamed": "账号 {name} 现已更名为 {new}。",
|
||||
"acc.accessChanged": "账号 {name} 的权限现已调整为:{level}。",
|
||||
|
||||
// Problem report (GitHub issue)
|
||||
"nav.report": "问题反馈",
|
||||
"q.report": "遇到了功能异常?",
|
||||
"rep.title": "报告问题",
|
||||
"rep.intro": "描述遇到的问题。管理器会据此生成一份 GitHub Issue 报告并在浏览器中打开;你可以在网页上核对内容、添加截图并提交。需要免费的 GitHub 账号。本窗口不会直接向外发送任何数据。",
|
||||
"rep.autoTitle": "自动填充的系统环境",
|
||||
"rep.manager": "管理器版本",
|
||||
"rep.windows": "Windows 版本",
|
||||
"rep.kind": "服务器类型",
|
||||
"rep.kindNew": "全新安装",
|
||||
"rep.kindImported": "导入现有服务器",
|
||||
"rep.server": "服务器核心版本",
|
||||
"rep.summary": "问题简述",
|
||||
"rep.summaryHint": "例如:创建角色后卡在加载画面",
|
||||
"rep.what": "具体发生了什么?",
|
||||
"rep.whatHint": "详细描述故障现象。",
|
||||
"rep.expected": "你预期的行为是什么?",
|
||||
"rep.expectedHint": "描述你期望的正常表现。",
|
||||
"rep.steps": "复现步骤",
|
||||
"rep.attachTitle": "日志与截图附件",
|
||||
"rep.attachText": "生成一份诊断包文件(已自动脱敏密码与私有 IP 等敏感信息),并在浏览器打开 GitHub 页面后,将其连同截图或录屏一起拖拽上传。",
|
||||
"rep.makeFile": "生成诊断包文件",
|
||||
"rep.fileSaved": "已保存至 {path}。请将该文件拖入 GitHub Issue 中。",
|
||||
"rep.privacy": "上传前请注意检查并移除日志中可能包含的私有密码、Token 或其他敏感隐私信息。",
|
||||
"rep.open": "在 GitHub 上打开报告",
|
||||
"rep.copy": "复制报告文本",
|
||||
"rep.preview": "预览报告文本",
|
||||
"rep.needFields": "请先填写问题简述和发生的情况。",
|
||||
"rep.githubNote": "报告内容会自动整理为英文以便开发者阅读;你填写的文字将按原样保留。",
|
||||
"rep.opened": "已在浏览器中打开 GitHub。请检查内容、附上日志文件并点击“Submit new issue”。",
|
||||
"rep.openedLong": "报告内容较长超出 URL 长度限制,已自动复制到剪贴板。请在已打开的 GitHub 页面中按 Ctrl+V 粘贴描述,附上文件后提交。",
|
||||
"rep.copied": "已复制到剪贴板。",
|
||||
|
||||
// Realmlist switcher and modules page
|
||||
"realm.label": "服务器列表",
|
||||
"realm.other": "其他",
|
||||
"realm.add": "添加服务器地址…",
|
||||
"realm.addTitle": "新增 realmlist 配置",
|
||||
"realm.editTitle": "编辑 realmlist 配置",
|
||||
"realm.name": "名称",
|
||||
"realm.nameHint": "例如 单机服 或 PTR测试服",
|
||||
"realm.data": "Realmlist 地址",
|
||||
"realm.dataHint": "即 realmlist.wtf 文件的内容,例如:set realmlist play.example.com。也可以直接输入域名或 IP。选择该项会将其写入游戏客户端,先前的配置会自动备份。",
|
||||
"realm.switched": "游戏客户端现已切换至“{name}”。",
|
||||
"realm.edit": "编辑 {name}",
|
||||
"realm.delete": "删除 {name}",
|
||||
"realm.confirmDelete": "是否删除 realmlist 配置“{name}”?游戏客户端将继续保留其当前的文件内容。",
|
||||
"nav.modules": "扩展模块",
|
||||
"q.modules": "服务器支持哪些扩展模块?",
|
||||
"mod.title": "模块管理",
|
||||
"mod.intro": "服务器内置的可选扩展特性。可按需开关、访问其 GitHub 页面或调整独立参数。",
|
||||
"mod.restart": "更改将在世界服务器重启后生效。",
|
||||
"mod.switch": "开启或关闭 {name}",
|
||||
"mod.notHere": "未包含在当前服务器中",
|
||||
"mod.github": "GitHub 页面",
|
||||
"mod.settings": "模块设置",
|
||||
"mod.default": "恢复为默认值 ({v})",
|
||||
"mod.saved": "已保存(修改了 {n} 项)。",
|
||||
|
||||
// Modules page: nothing yet
|
||||
"mod.empty": "此处暂无内容。随着后续添加,可选模块将展示在此页面。",
|
||||
// Settings page: the full searchable list
|
||||
"all.title": "所有服务器设置",
|
||||
"all.intro": "世界服务器的全部其他已收录设置项及详细说明。其他选项卡已有的设置此处不重复罗列,但上方搜索框可全局检索。请仅修改你理解的选项:错误的配置可能导致服务器无法启动。修改前会自动保存旧配置以供随时恢复。",
|
||||
"all.search": "按名称或描述搜索…",
|
||||
"all.onlyChanged": "仅显示已修改",
|
||||
"all.count": "正在显示 {shown} / {total} 项。使用搜索可快速缩小范围。",
|
||||
"all.none": "未找到匹配的设置项。",
|
||||
"all.changed": "已修改",
|
||||
"all.useDefault": "恢复默认值 ({v})",
|
||||
"all.save": "保存 {n} 项修改",
|
||||
"all.saved": "已保存。请重启服务器使更改生效。",
|
||||
"import.suggest.title": "你是否是指此文件夹?",
|
||||
"import.suggest.text": "所选文件夹属于某个服务器子目录。检测到的主服务器根目录为:",
|
||||
"import.suggest.use": "使用该主文件夹",
|
||||
"import.notRepack": "该目录看起来是独立的 AzerothCore 原版服务器。本管理器专为 CoA Repack 架构设计(包含 Core、mysql、Scripts 和 Settings 的目录)。请使用“安装全新服务器”或导入 CoA Repack。",
|
||||
"acc.delete": "删除",
|
||||
"acc.deleteFor": "删除账号 {name}?",
|
||||
"acc.deleteWarn": "此操作将永久删除该账号及其名下的所有角色 ({n})。该操作无法撤销;如有需要请先创建备份。",
|
||||
"acc.deleteConfirm": "请输入 {name} 以确认删除",
|
||||
"acc.deleteButton": "彻底删除账号",
|
||||
"acc.deleted": "账号 {name} 已成功删除。",
|
||||
"mod.status.early": "早期预览",
|
||||
"mod.status.beta": "测试版",
|
||||
"mod.status.release": "正式版",
|
||||
"mod.hint.early": "实验性功能:可能变更或不稳定。",
|
||||
"mod.hint.beta": "功能正常,仍在持续测试中。",
|
||||
"mod.hint.release": "稳定可靠。",
|
||||
"mod.legend": "模块状态",
|
||||
"mod.alwaysOn": "始终启用",
|
||||
"mod.settingsOf": "{name}:详细设置",
|
||||
"col.title": "外观与收藏",
|
||||
"col.intro": "游戏客户端的外观收集与便利功能开关。将在世界服务器重启后生效。",
|
||||
"col.appearances": "解锁全部幻化外观",
|
||||
"col.appearances.text": "所有装备外观从一开始就直接收录在试衣间衣橱中。",
|
||||
"col.vanity": "解锁全部 Vanity 物品收藏",
|
||||
"col.vanity.text": "所有 Vanity 收藏品默认对全服每个账号开放拥有。",
|
||||
"col.auto": "自动收集装备外观",
|
||||
"col.auto.text": "角色获得的装备会自动加入账号幻化外观库。",
|
||||
"col.companions": "自动学会已拥有的坐骑与宠物",
|
||||
"col.companions.text": "背包中的坐骑与宠物直接永久学会。",
|
||||
"col.riding": "出生即可拥有满级骑术",
|
||||
"col.riding.text": "1 级即可掌握所有级别骑术及寒冷飞行技能。",
|
||||
"mod.status.soon": "即将推出",
|
||||
"mod.hint.soon": "规划中:当前版本尚不可用。",
|
||||
"set.tab.collections": "外观收藏",
|
||||
"set.tab.all": "其他设置",
|
||||
"set.searchAll": "按名称或描述搜索全部设置…",
|
||||
"set.search": "搜索设置…",
|
||||
"upd.current": "当前已是最新版本 ({v})。",
|
||||
"client.job.checking": "正在检查游戏客户端…",
|
||||
"client.job.updating": "正在更新游戏客户端",
|
||||
"err.docker_unavailable.title": "Docker 不可用",
|
||||
"err.docker_unavailable.message": "此服务器通过 Docker 运行。请安装并启动 Docker,确保当前用户有权使用它,然后重试。",
|
||||
} as const;
|
||||
|
||||
export default zh;
|
||||
@@ -0,0 +1,601 @@
|
||||
{
|
||||
"categories": {
|
||||
"bots.general": "常规",
|
||||
"bots.population": "人口与数量",
|
||||
"bots.login": "登录",
|
||||
"bots.roles": "职责分配",
|
||||
"bots.openworld": "野外世界",
|
||||
"bots.quests": "任务系统",
|
||||
"bots.combat": "战斗",
|
||||
"bots.dungeon": "地下城",
|
||||
"bots.battlegrounds": "战场",
|
||||
"bots.social": "社交与互助",
|
||||
"bots.advanced": "高级设置",
|
||||
"server.gameplay": "游戏玩法",
|
||||
"server.rates": "倍率",
|
||||
"server.characters": "角色",
|
||||
"server.world": "游戏世界",
|
||||
"server.network": "网络",
|
||||
"server.accounts": "账号",
|
||||
"server.logging": "日志",
|
||||
"server.performance": "性能",
|
||||
"server.advanced": "高级设置"
|
||||
},
|
||||
"units": {
|
||||
"ms": "毫秒",
|
||||
"%": "%",
|
||||
"yards": "码",
|
||||
"levels": "级",
|
||||
"x": "倍",
|
||||
"min": "分钟",
|
||||
"copper": "铜币"
|
||||
},
|
||||
"settings": {
|
||||
"CoaBots.RandomSpawn.DefaultCount": {
|
||||
"t": "单次生成命令创建数量",
|
||||
"d": "当生成命令未指定数量时,默认创建的机器人数量。"
|
||||
},
|
||||
"CoaBots.RandomSpawn.MaxCount": {
|
||||
"t": "单次最大生成上限",
|
||||
"d": "单次生成命令的安全上限。批量创建过多可能导致服务器短暂卡顿,建议仅在无其他玩家在线时调高。"
|
||||
},
|
||||
"CoaBots.LeveledSpawn.Brackets": {
|
||||
"t": "新机器人等级分布",
|
||||
"d": "新生成机器人的等级分布区间与权重(例如 1-20:40 表示等级 1 到 20 占比 40)。"
|
||||
},
|
||||
"CoaBots.RandomSpawn.AutoLogin": {
|
||||
"t": "新机器人立即上线",
|
||||
"d": "新创建的机器人立即登录游戏,而不是留在数据库中等待。"
|
||||
},
|
||||
"CoaBots.RandomSpawn.AccountPrefix": {
|
||||
"t": "机器人账号前缀",
|
||||
"d": "机器人所使用的账号名称前缀。修改此项会导致现有机器人无法自动登录。"
|
||||
},
|
||||
"CoaBots.RandomSpawn.BatchSize": {
|
||||
"t": "每批次生成数量",
|
||||
"d": "将创建过程分批分散进行以保证服务器流畅。数值越大越快,但可能引起卡顿。"
|
||||
},
|
||||
"CoaBots.RandomSpawn.BatchIntervalMs": {
|
||||
"t": "批次生成间隔",
|
||||
"d": "每次批量生成之间的间隔时间。数值越小生成越快,但可能引起卡顿。"
|
||||
},
|
||||
"CoaBots.AutoLoginOnStartup": {
|
||||
"t": "开机自动登录机器人",
|
||||
"d": "服务器每次启动时,现有的机器人自动登录上线。"
|
||||
},
|
||||
"CoaBots.AutoLogin.MaxCount": {
|
||||
"t": "最大在线机器人数量",
|
||||
"d": "服务器启动时自动登录的机器人上限数量。"
|
||||
},
|
||||
"CoaBots.AutoLogin.BatchSize": {
|
||||
"t": "每批次登录数量",
|
||||
"d": "将登录分散进行。数值越高上线越快,但对服务器负载更大。"
|
||||
},
|
||||
"CoaBots.AutoLogin.BatchIntervalMs": {
|
||||
"t": "批次登录间隔",
|
||||
"d": "每次批量登录之间的间隔时间。"
|
||||
},
|
||||
"CoaBots.SpecBalance.TankTargetPct": {
|
||||
"t": "坦克职业目标比例",
|
||||
"d": "机器人中坦克专精的目标占比百分比。"
|
||||
},
|
||||
"CoaBots.SpecBalance.HealerTargetPct": {
|
||||
"t": "治疗职业目标比例",
|
||||
"d": "机器人中治疗专精的目标占比百分比。"
|
||||
},
|
||||
"CoaBots.TalentBuildsPath": {
|
||||
"t": "天赋数据文件路径",
|
||||
"d": "社区天赋方案配置文件的保存路径。留空则使用内置搜索。"
|
||||
},
|
||||
"CoaBots.World.Enable": {
|
||||
"t": "野外差事与漫游",
|
||||
"d": "允许机器人在野外世界中游荡、采集、钓鱼与刷怪。"
|
||||
},
|
||||
"CoaBots.World.ThinkIntervalMs": {
|
||||
"t": "差事决策间隔",
|
||||
"d": "每个机器人重新评估其当前差事的时间间隔。"
|
||||
},
|
||||
"CoaBots.World.IdleBeforeErrandMs": {
|
||||
"t": "开始差事前发呆时间",
|
||||
"d": "机器人在无所事事多久后会开始新的差事活动。"
|
||||
},
|
||||
"CoaBots.World.AreaRadius": {
|
||||
"t": "差事搜索区域半径",
|
||||
"d": "机器人寻找采集或刷怪地点的最大范围。"
|
||||
},
|
||||
"CoaBots.World.ServiceRadius": {
|
||||
"t": "城镇设施搜索半径",
|
||||
"d": "机器人寻找商人、修理工和邮箱的最大距离。"
|
||||
},
|
||||
"CoaBots.World.VerboseLog": {
|
||||
"t": "详细差事日志",
|
||||
"d": "将差事的每一步都记录到日志中。适用于调试,机器人较多时会产生大量日志。"
|
||||
},
|
||||
"CoaBots.Grind.SearchRadius": {
|
||||
"t": "刷怪搜索半径",
|
||||
"d": "机器人寻找野怪进行刷怪升级的范围半径。"
|
||||
},
|
||||
"CoaBots.Grind.MaxLevelAbove": {
|
||||
"t": "刷怪最高超出自身等级",
|
||||
"d": "机器人在野外刷怪时愿意挑战高于自身多少级的怪物。"
|
||||
},
|
||||
"CoaBots.Profile.IntentMinMs": {
|
||||
"t": "意图持续最短时间",
|
||||
"d": "机器人保持从事同一种活动的最短持续时间。"
|
||||
},
|
||||
"CoaBots.Profile.IntentMaxMs": {
|
||||
"t": "意图持续最长时间",
|
||||
"d": "机器人保持从事同一种活动的最长持续时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Enable": {
|
||||
"t": "自主任务AI",
|
||||
"d": "机器人会自主接取并完成任务。关闭时机器人只会采集、钓鱼、刷怪和游荡。"
|
||||
},
|
||||
"CoaBots.WorldBrain.MaxActiveQuests": {
|
||||
"t": "最大同时进行任务数",
|
||||
"d": "单个机器人任务日志中同时拥有的最大任务数量。"
|
||||
},
|
||||
"CoaBots.WorldBrain.AcceptEliteQuests": {
|
||||
"t": "单人接取精英任务",
|
||||
"d": "单人机器人是否接取精英任务。默认关闭,因为通常无法单人完成。"
|
||||
},
|
||||
"CoaBots.WorldBrain.QuestLevelBelow": {
|
||||
"t": "接取低于自身等级任务",
|
||||
"d": "机器人仍愿意接取低于自身多少级的低级任务。"
|
||||
},
|
||||
"CoaBots.WorldBrain.QuestLevelAbove": {
|
||||
"t": "接取高于自身等级任务",
|
||||
"d": "机器人愿意接取高于自身多少级的高级任务。"
|
||||
},
|
||||
"CoaBots.WorldBrain.MaxMobLevelAbove": {
|
||||
"t": "任务怪最高超出等级",
|
||||
"d": "任务目标怪物允许超出机器人自身等级的上限。"
|
||||
},
|
||||
"CoaBots.WorldBrain.MaxObjectiveDistance": {
|
||||
"t": "任务目标最远距离",
|
||||
"d": "目标地点超过此距离的任务将不会被接取。"
|
||||
},
|
||||
"CoaBots.WorldBrain.GiverSearchRadius": {
|
||||
"t": "任务发布者搜索半径",
|
||||
"d": "机器人寻找可接任务 NPC 的搜索范围。"
|
||||
},
|
||||
"CoaBots.WorldBrain.SearchRadius": {
|
||||
"t": "任务目标搜索半径",
|
||||
"d": "机器人在目标区域内寻找任务怪或任务道具的扫描范围。"
|
||||
},
|
||||
"CoaBots.WorldBrain.EngageRange": {
|
||||
"t": "开战交战距离",
|
||||
"d": "机器人发现任务目标怪并开始主动进入战斗的距离。"
|
||||
},
|
||||
"CoaBots.WorldBrain.ApproachTimeoutMs": {
|
||||
"t": "接近目标超时时间",
|
||||
"d": "机器人向已选定目标移动的最长允许时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.SearchTimeoutMs": {
|
||||
"t": "区域搜索超时时间",
|
||||
"d": "机器人在空无一物的区域中搜索多久后会尝试寻找下一个地点。"
|
||||
},
|
||||
"CoaBots.WorldBrain.TravelTimeoutMs": {
|
||||
"t": "路途总时长上限",
|
||||
"d": "前往某区域的整个行程允许花费的最长时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.MaxBadAreasPerObjective": {
|
||||
"t": "每个目标放弃前尝试区域数",
|
||||
"d": "机器人经历多少个无果区域后彻底搁置该任务。"
|
||||
},
|
||||
"CoaBots.WorldBrain.QuestSuspendMs": {
|
||||
"t": "任务短期搁置时长",
|
||||
"d": "机器人暂时放弃某个卡住的任务后,将其搁置的时长。"
|
||||
},
|
||||
"CoaBots.WorldBrain.QuestSuspendMaxMs": {
|
||||
"t": "任务长期搁置最长时间",
|
||||
"d": "任务在反复失败后被搁置的最长封存时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.GatherDetours": {
|
||||
"t": "路过顺手采集草药矿石",
|
||||
"d": "具备采集技能的机器人在行进路线附近发现资源点时会顺道采集。"
|
||||
},
|
||||
"CoaBots.WorldBrain.SessionBreaks": {
|
||||
"t": "像玩家一样休息发呆",
|
||||
"d": "机器人在做任务之余会回城闲逛几分钟,模拟真实玩家的行为习惯。"
|
||||
},
|
||||
"CoaBots.WorldBrain.MountDistanceMin": {
|
||||
"t": "骑乘最小距离",
|
||||
"d": "旅途距离超过此值与最大值之间的随机距离时,机器人会召唤坐骑。"
|
||||
},
|
||||
"CoaBots.WorldBrain.MountDistanceMax": {
|
||||
"t": "骑乘最大距离",
|
||||
"d": "旅途距离超过此数值时,机器人必定会召唤坐骑。"
|
||||
},
|
||||
"CoaBots.WorldBrain.TaxiMinDistance": {
|
||||
"t": "公共飞行路线起用距离",
|
||||
"d": "超过此距离且已探索过航线的长途旅行将乘坐公共飞行管理员。"
|
||||
},
|
||||
"CoaBots.WorldBrain.TemporaryParties": {
|
||||
"t": "临时组队做任务",
|
||||
"d": "相同等级且在做同一个任务的机器人会临时组成队伍互相协助。"
|
||||
},
|
||||
"CoaBots.WorldBrain.PartyMaxSize": {
|
||||
"t": "临时队伍最大人数",
|
||||
"d": "临时任务小队允许容纳的最大成员数量。"
|
||||
},
|
||||
"CoaBots.WorldBrain.PartyRadius": {
|
||||
"t": "组队判定范围",
|
||||
"d": "机器人相距多近时会互相邀请临时组队。"
|
||||
},
|
||||
"CoaBots.WorldBrain.PartyMinMinutes": {
|
||||
"t": "临时组队最短时长",
|
||||
"d": "临时队伍的最短维持时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.PartyMaxMinutes": {
|
||||
"t": "临时组队最长时长",
|
||||
"d": "临时队伍的最长维持时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.HelpOthers": {
|
||||
"t": "路过协助陷入苦战的玩家",
|
||||
"d": "路过的同阵营机器人会主动协助处于危险中的玩家,且不抢夺掉落和经验。"
|
||||
},
|
||||
"CoaBots.WorldBrain.HelpRadius": {
|
||||
"t": "求助援助范围",
|
||||
"d": "机器人相距战斗多近时会加入战局协助。"
|
||||
},
|
||||
"CoaBots.WorldBrain.HelpHealthPct": {
|
||||
"t": "提供援助生命值阈值",
|
||||
"d": "当正在战斗的玩家生命值低于此百分比时机器人会介入援助。"
|
||||
},
|
||||
"CoaBots.WorldBrain.ResurrectOthers": {
|
||||
"t": "复活阵亡玩家",
|
||||
"d": "拥有复活法术的机器人会为附近的友方玩家尸体施放复活术。"
|
||||
},
|
||||
"CoaBots.WorldBrain.PlannerMinMs": {
|
||||
"t": "决策规划最小间隔",
|
||||
"d": "机器人规划下一次行动的最短间隔时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.PlannerMaxMs": {
|
||||
"t": "决策规划最大间隔",
|
||||
"d": "机器人规划下一次行动的最长间隔时间。"
|
||||
},
|
||||
"CoaBots.WorldBrain.ScanMinMs": {
|
||||
"t": "扫描目标最小间隔",
|
||||
"d": "在目标区域内扫描怪物与物体的最短时间间隔。"
|
||||
},
|
||||
"CoaBots.WorldBrain.ScanMaxMs": {
|
||||
"t": "扫描目标最大间隔",
|
||||
"d": "在目标区域内扫描怪物与物体的最长时间间隔。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.TravelPer100Yards": {
|
||||
"t": "权重偏好:每100码路程惩罚",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.CrowdPerBot": {
|
||||
"t": "权重偏好:同区域拥挤度惩罚",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.AreaOccupancy": {
|
||||
"t": "权重偏好:区域占用惩罚",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.Accept": {
|
||||
"t": "权重偏好:接取任务偏好",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.TurnIn": {
|
||||
"t": "权重偏好:交付任务偏好",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.Overlap": {
|
||||
"t": "权重偏好:同路线任务重叠奖励",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.WorldBrain.Weight.TargetReserved": {
|
||||
"t": "权重偏好:目标已被他人锁定惩罚",
|
||||
"d": "机器人在评估下一步行动时代价权重的考量系数。仅在熟悉AI规划器时修改。"
|
||||
},
|
||||
"CoaBots.LfgFill.Enable": {
|
||||
"t": "地下城查找器机器人补位",
|
||||
"d": "当单人排随机地下城时,机器人会自动补齐缺少的坦克、治疗和输出角色。"
|
||||
},
|
||||
"CoaBots.AutoQueueDungeon.Enable": {
|
||||
"t": "机器人自主排地下城",
|
||||
"d": "实验性功能:空闲的坦克机器人会自主报名排地下城,并由上述补位机制补齐队伍。"
|
||||
},
|
||||
"CoaBots.BGFill.Enable": {
|
||||
"t": "战场机器人自动补位",
|
||||
"d": "当有玩家排战场时,双方阵营会自动填充机器人以便迅速开赛。"
|
||||
},
|
||||
"CoaBots.BGFill.TargetPlayersPerTeam": {
|
||||
"t": "战场每队目标人数",
|
||||
"d": "每支队伍自动补齐到的人数。0 表示补满该战场的标准人数。"
|
||||
},
|
||||
"CoaBots.Healer.CriticalHealPct": {
|
||||
"t": "紧急强效治疗生命阈值",
|
||||
"d": "当队友生命值低于此百分比时,治疗职业会切换至最强救急技能。"
|
||||
},
|
||||
"CoaBots.Combat.VerboseLog": {
|
||||
"t": "详细战斗决策日志",
|
||||
"d": "将战斗中的技能决策写入日志。内容非常庞大,建议仅在排查特定问题时开启。"
|
||||
},
|
||||
"Rate.XP.Kill": {
|
||||
"t": "击杀怪物经验倍率",
|
||||
"d": "击杀怪物所获得经验值的乘数倍率。默认为 1。"
|
||||
},
|
||||
"Rate.XP.Quest": {
|
||||
"t": "完成任务经验倍率",
|
||||
"d": "完成任务所获得经验值的乘数倍率。"
|
||||
},
|
||||
"Rate.XP.Quest.DF": {
|
||||
"t": "日常与随机地下城任务经验倍率",
|
||||
"d": "完成地下城查找器奖励及日常任务所获得经验值的乘数倍率。"
|
||||
},
|
||||
"Rate.XP.Explore": {
|
||||
"t": "探索地图经验倍率",
|
||||
"d": "发现新区域探索地图时获得经验值的乘数倍率。"
|
||||
},
|
||||
"Rate.Drop.Item.Normal": {
|
||||
"t": "普通物品掉落率",
|
||||
"d": "白色普通品质物品掉落几率的乘数倍率。"
|
||||
},
|
||||
"Rate.Drop.Money": {
|
||||
"t": "金币掉落倍率",
|
||||
"d": "怪物掉落金币数量的乘数倍率。"
|
||||
},
|
||||
"Rate.Honor": {
|
||||
"t": "荣誉点数获取倍率",
|
||||
"d": "通过PvP获得的荣誉点数乘数倍率。"
|
||||
},
|
||||
"Rate.Reputation.Gain": {
|
||||
"t": "声望获取倍率",
|
||||
"d": "所获阵营声望的乘数倍率。"
|
||||
},
|
||||
"Rate.Rest.InGame": {
|
||||
"t": "在线双倍经验消耗速度",
|
||||
"d": "游戏在线时消耗双倍休息充分经验的速度。"
|
||||
},
|
||||
"Rate.Creature.Normal.Damage": {
|
||||
"t": "普通怪物伤害倍率",
|
||||
"d": "普通怪物造成的伤害乘数。大幅改变游戏战斗难度。"
|
||||
},
|
||||
"Rate.Creature.Normal.HP": {
|
||||
"t": "普通怪物生命值倍率",
|
||||
"d": "普通怪物的生命值上限乘数。大幅改变游戏战斗难度。"
|
||||
},
|
||||
"PlayerLimit": {
|
||||
"t": "最大同时在线玩家数",
|
||||
"d": "服务器允许同时在线的最大玩家数量。设为 0 表示无限制。"
|
||||
},
|
||||
"GameType": {
|
||||
"t": "服务器类型",
|
||||
"d": "在服务器列表(Realm List)中显示的类型标识。"
|
||||
},
|
||||
"RealmZone": {
|
||||
"t": "服务器区域语言分组",
|
||||
"d": "向客户端展示的语言/地理区域代码。"
|
||||
},
|
||||
"PlayerSaveInterval": {
|
||||
"t": "角色数据自动保存间隔",
|
||||
"d": "在线玩家角色数据写入数据库的时间间隔。"
|
||||
},
|
||||
"CharactersPerAccount": {
|
||||
"t": "每个账号最大角色数",
|
||||
"d": "单个账号在所有服务器可创建的角色总数上限。"
|
||||
},
|
||||
"CharactersPerRealm": {
|
||||
"t": "单个服务器最大角色数",
|
||||
"d": "单个账号在此服务器上允许创建的角色数量上限。"
|
||||
},
|
||||
"StartPlayerLevel": {
|
||||
"t": "新角色初始等级",
|
||||
"d": "新创建的角色出生时的初始等级。"
|
||||
},
|
||||
"StartPlayerMoney": {
|
||||
"t": "新角色初始金币",
|
||||
"d": "新角色出生时背包携带的铜币数(10000 铜币 = 1 金币)。"
|
||||
},
|
||||
"MaxPlayerLevel": {
|
||||
"t": "最高等级上限",
|
||||
"d": "角色能够达到的最高等级。游戏客户端原生最高支持 80 级。"
|
||||
},
|
||||
"SkipCinematics": {
|
||||
"t": "跳过开场动画",
|
||||
"d": "新创建的角色是否跳过开场过场动画。"
|
||||
},
|
||||
"DurabilityLoss.OnDeath": {
|
||||
"t": "死亡耐久度损失比例",
|
||||
"d": "角色死亡时装备耐久度损失的百分比。"
|
||||
},
|
||||
"Death.SicknessLevel": {
|
||||
"t": "最高复活虚弱等级",
|
||||
"d": "高于此等级的角色在天使处复活会获得复活虚弱。设置为 -10 则彻底关闭。"
|
||||
},
|
||||
"LeaveGroupOnLogout.Enabled": {
|
||||
"t": "下线自动退组",
|
||||
"d": "玩家退出游戏注销登录时自动移出当前队伍。"
|
||||
},
|
||||
"GM.LoginState": {
|
||||
"t": "GM登录默认状态",
|
||||
"d": "游戏管理员登录时是否默认开启 GM 模式。"
|
||||
},
|
||||
"AllowTwoSide.Accounts": {
|
||||
"t": "同账号双阵营创建",
|
||||
"d": "允许同一个账号下同时创建联盟和部落角色。"
|
||||
},
|
||||
"AllowTwoSide.Interaction.Chat": {
|
||||
"t": "跨阵营聊天",
|
||||
"d": "允许联盟与部落玩家在公共频道互相交流发言。"
|
||||
},
|
||||
"AutoBroadcast.On": {
|
||||
"t": "定时系统全服广播",
|
||||
"d": "按固定时间间隔循环广播数据库中配置的系统公告信息。"
|
||||
},
|
||||
"AutoBroadcast.Timer": {
|
||||
"t": "系统广播间隔时间",
|
||||
"d": "两次自动广播消息之间的时间间隔。"
|
||||
},
|
||||
"Warden.Enabled": {
|
||||
"t": "反作弊系统 (Warden)",
|
||||
"d": "启用客户端反作弊检测机制。在局域网/单人私服上通常可保持关闭。"
|
||||
},
|
||||
"MapUpdateInterval": {
|
||||
"t": "地图循环更新间隔",
|
||||
"d": "世界服务器更新地图周期的间隔。越低越平滑但消耗更多CPU。"
|
||||
},
|
||||
"MapUpdate.Threads": {
|
||||
"t": "地图处理CPU核心数",
|
||||
"d": "用于处理世界地图更新的CPU核心线程数。多张地图活动时调高可大幅提升性能。世界服务器重启后生效。"
|
||||
},
|
||||
"MinWorldUpdateTime": {
|
||||
"t": "最小世界更新时间",
|
||||
"d": "世界循环之间的最短更新时间。调高可降低CPU占用率。"
|
||||
},
|
||||
"ThreadPool": {
|
||||
"t": "后台工作线程数",
|
||||
"d": "后台工作线程池大小。人口较多时增加此值有助于提高并发吞吐。"
|
||||
},
|
||||
"Network.Threads": {
|
||||
"t": "网络IO线程数",
|
||||
"d": "处理网络连接的线程数。小规模私服通常设置为 1 即可。"
|
||||
},
|
||||
"Ra.Enable": {
|
||||
"t": "远程控制台 (RA)",
|
||||
"d": "允许管理器和自动化脚本向服务器发送控制台指令。仅监听本地回环地址即可。"
|
||||
},
|
||||
"Ra.IP": {
|
||||
"t": "远程控制台监听地址",
|
||||
"d": "远程控制台绑定的IP地址。请保持 127.0.0.1 以防止来自外网的未授权访问。"
|
||||
},
|
||||
"Updates.EnableDatabases": {
|
||||
"t": "启动时自动执行数据库升级",
|
||||
"d": "允许服务器在启动时自行更改数据库。请保持 0:管理器会安全跟踪并执行数据库迁移。"
|
||||
},
|
||||
"Rate.Drop.Item.Uncommon": {
|
||||
"t": "优秀(绿色)物品掉落率",
|
||||
"d": "优秀品质(绿色装备)掉落频率的乘数倍率。"
|
||||
},
|
||||
"Rate.Drop.Item.Rare": {
|
||||
"t": "精良(蓝色)物品掉落率",
|
||||
"d": "精良品质(蓝色装备)掉落频率的乘数倍率。"
|
||||
},
|
||||
"Rate.Drop.Item.Epic": {
|
||||
"t": "史诗(紫色)物品掉落率",
|
||||
"d": "史诗品质(紫色装备)掉落频率的乘数倍率。"
|
||||
},
|
||||
"Rate.Drop.Item.Legendary": {
|
||||
"t": "传说(橙色)物品掉落率",
|
||||
"d": "传说品质(橙色装备)掉落频率的乘数倍率。"
|
||||
},
|
||||
"Rate.Talent": {
|
||||
"t": "每级天赋点数倍率",
|
||||
"d": "角色每升一级所获得天赋点数的乘数倍率。"
|
||||
},
|
||||
"Rate.Skill.Discovery": {
|
||||
"t": "专业配方领悟几率",
|
||||
"d": "制造物品时领悟新配方的几率乘数倍率。"
|
||||
},
|
||||
"Rate.RepairCost": {
|
||||
"t": "装备修理费用倍率",
|
||||
"d": "修理装备费用的乘数。设置为 0 则免费修理。"
|
||||
},
|
||||
"Rate.Auction.Cut": {
|
||||
"t": "拍卖行手续费抽成比例",
|
||||
"d": "拍卖行完成交易所扣除的手续费抽成乘数。设置为 0 则不抽成。"
|
||||
},
|
||||
"Rate.ArenaPoints": {
|
||||
"t": "竞技场点数获取倍率",
|
||||
"d": "所获竞技场点数的乘数倍率。"
|
||||
},
|
||||
"Rate.XP.Pet": {
|
||||
"t": "猎人宠物经验倍率",
|
||||
"d": "猎人宠物获得经验值的乘数倍率。"
|
||||
},
|
||||
"Instance.IgnoreLevel": {
|
||||
"t": "无视地下城等级要求",
|
||||
"d": "允许任何等级的角色进入地下城和团队副本。"
|
||||
},
|
||||
"Instance.IgnoreRaid": {
|
||||
"t": "无团队队伍进入团本",
|
||||
"d": "玩家无需身处团队队伍中即可进入团队副本。"
|
||||
},
|
||||
"Instance.ResetTimeHour": {
|
||||
"t": "副本进度重置时间点",
|
||||
"d": "地下城与团队副本进度重置的小时(0-23点)。"
|
||||
},
|
||||
"MaxPrimaryTradeSkill": {
|
||||
"t": "角色主专业技能上限",
|
||||
"d": "单个角色允许学习的主要专业(例如锻造、草药学)数量上限。"
|
||||
},
|
||||
"AlwaysMaxSkillForLevel": {
|
||||
"t": "武器技能自动升满",
|
||||
"d": "武器及其他熟练度技能自动保持在当前角色等级上限,无需反复练习。"
|
||||
},
|
||||
"ActivateWeather": {
|
||||
"t": "天气系统",
|
||||
"d": "开启或关闭降雨、降雪以及风暴等动态天气效果。"
|
||||
},
|
||||
"Group.Raid.LevelRestriction": {
|
||||
"t": "团队副本邀请最低等级",
|
||||
"d": "低于此等级的角色无法被邀请加入团队队伍。"
|
||||
},
|
||||
"AllowTwoSide.Interaction.Group": {
|
||||
"t": "跨阵营组队",
|
||||
"d": "允许联盟和部落玩家共同组成队伍。"
|
||||
},
|
||||
"AllowTwoSide.Interaction.Guild": {
|
||||
"t": "跨阵营公会",
|
||||
"d": "允许联盟和部落玩家加入同一个公会。"
|
||||
},
|
||||
"AllowTwoSide.Interaction.Auction": {
|
||||
"t": "全阵营共享拍卖行",
|
||||
"d": "联盟和部落玩家共享同一拍卖行市场。"
|
||||
},
|
||||
"Achievement.RealmFirstBlockBots": {
|
||||
"t": "禁止机器人获取“服务器第一”成就",
|
||||
"d": "随从(机器人)无法获得“服务器第一!”成就,绝不抢占真实玩家的第一名荣誉。需要 2026-10-02 或更新的服务器核心版本。"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"GameType.0": "普通",
|
||||
"GameType.1": "PvP",
|
||||
"GameType.6": "角色扮演 (RP)",
|
||||
"GameType.8": "角色扮演 + PvP (RP-PvP)",
|
||||
"SkipCinematics.0": "全部播放",
|
||||
"SkipCinematics.1": "仅跳过非首个角色",
|
||||
"SkipCinematics.2": "全部跳过",
|
||||
"GM.LoginState.0": "关闭",
|
||||
"GM.LoginState.1": "开启",
|
||||
"GM.LoginState.2": "保持上次状态"
|
||||
},
|
||||
"presets": {
|
||||
"balanced": {
|
||||
"t": "均衡模式",
|
||||
"d": "推荐的日常设置:任务、地下城补位、战场补位均开启,日志安静。"
|
||||
},
|
||||
"solo-friendly": {
|
||||
"t": "单人友好",
|
||||
"d": "机器人会协助你并补齐你的队伍,世界人口较少且稳定。"
|
||||
},
|
||||
"living-world": {
|
||||
"t": "生机世界",
|
||||
"d": "更热闹的世界:更多机器人、休息漫步、采集资源并偶尔组队。"
|
||||
},
|
||||
"performance": {
|
||||
"t": "性能优先",
|
||||
"d": "更少的机器人以及更低的运算消耗——适合配置较低的电脑。"
|
||||
},
|
||||
"vanilla": {
|
||||
"t": "标准倍率",
|
||||
"d": "所有内容均保持标准速度 (1倍)。"
|
||||
},
|
||||
"relaxed": {
|
||||
"t": "休闲惬意",
|
||||
"d": "升级更快,掉落更多,适合轻松体验游戏 (2倍 / 3倍)。"
|
||||
},
|
||||
"fast": {
|
||||
"t": "快速体验",
|
||||
"d": "极快的成长进度,适合测试或短时间游玩 (5倍)。"
|
||||
},
|
||||
"defaults": {
|
||||
"t": "推荐默认值",
|
||||
"d": "所有设置恢复为默认值。"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ const en = load("en");
|
||||
let errors = 0;
|
||||
|
||||
console.log(`en: ${en.size} keys (source of truth)`);
|
||||
for (const loc of ["ru", "de", "fr", "es"]) {
|
||||
for (const loc of ["ru", "de", "fr", "es", "zh"]) {
|
||||
const d = load(loc);
|
||||
let missing = 0;
|
||||
for (const [k, v] of d) {
|
||||
@@ -41,7 +41,7 @@ for (const loc of ["ru", "de", "fr", "es"]) {
|
||||
// Settings-schema overlays (src/i18n/schema/<locale>.json) must cover every setting, category, option and preset.
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const schemas = ["bots", "server"].map((sc) => ({ sc, d: JSON.parse(readFileSync(join(root, "schemas", `${sc}.json`), "utf8")), p: JSON.parse(readFileSync(join(root, "schemas", "presets", `${sc}.json`), "utf8")).presets }));
|
||||
for (const loc of ["ru", "de", "fr", "es"]) {
|
||||
for (const loc of ["ru", "de", "fr", "es", "zh"]) {
|
||||
const o = JSON.parse(readFileSync(join(root, "src", "i18n", "schema", `${loc}.json`), "utf8"));
|
||||
let miss = 0;
|
||||
for (const { sc, d, p } of schemas) {
|
||||
|
||||
Reference in new issue
Block a user