mirror of
https://github.com/Corfirean/coa-server-manager.git
synced 2026-11-11 03:51:01 +00:00
Translations: settings schema overlays (ru/de/fr/es), diagnostics, update steps, companion sizes, friends notes; dev mock for settings pages; docs/TRANSLATIONS.md
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a4b9ae81c7
commit
38b5b86be1
22 files changed
+2552
-33
No files matched your search
@@ -484,9 +484,11 @@ The reference install classifies as **Healthy (customised)**: repack shape, bina
|
|||||||
translations are reviewed by native speakers before release, with an English fallback for missing keys and a CI check
|
translations are reviewed by native speakers before release, with an English fallback for missing keys and a CI check
|
||||||
that every locale has every key. Do this before the first public release so strings are not retro-fitted.
|
that every locale has every key. Do this before the first public release so strings are not retro-fitted.
|
||||||
|
|
||||||
**Status (2026-09-30):** catalogue + picker + all screens translated (en/ru/de/fr/es drafts, `tools/check-i18n.mjs` checks
|
**Status (2026-09-30, updated):** catalogue + picker + every screen translated (en/ru/de/fr/es drafts); settings-schema titles,
|
||||||
keys/placeholders). Still English: settings-schema titles/descriptions/presets, companion size names, diagnostics check
|
descriptions, categories, presets, options and units are translated through overlays in `src/i18n/schema/`; diagnostics
|
||||||
texts and update step names coming from the backend (need `schemas/i18n/<locale>.json` overlays and code-keyed backend strings).
|
checks, update steps, companion sizes and friends notes are recognised and translated in the UI. `tools/check-i18n.mjs`
|
||||||
|
verifies keys, placeholders and overlay coverage. Still English: free-form backend technical messages. Native-speaker
|
||||||
|
review is still needed (see `docs/TRANSLATIONS.md`).
|
||||||
|
|
||||||
* **Language choice on the very first screen** (requested 2026-09-30): the welcome screen must offer the language picker
|
* **Language choice on the very first screen** (requested 2026-09-30): the welcome screen must offer the language picker
|
||||||
right away (before any other text is read), preselected from the OS language; the choice is persisted and shared with
|
right away (before any other text is read), preselected from the OS language; the choice is persisted and shared with
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Translations
|
||||||
|
|
||||||
|
The Manager interface exists in English (source), Russian, German, French and Spanish. Everything except English is a
|
||||||
|
**draft written by an AI assistant and needs review by a native speaker** before it is treated as final.
|
||||||
|
|
||||||
|
## Where the texts are
|
||||||
|
|
||||||
|
| What | File | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Interface texts | `src/i18n/locales/<lang>.ts` | flat `"key": "text"` lists; `en.ts` is the source of truth, other languages fall back to it |
|
||||||
|
| Setting titles, descriptions, categories, presets, units, option labels | `src/i18n/schema/<lang>.json` | generated once from `schemas/*.json`; edit the JSON directly |
|
||||||
|
| Backend error messages | keys `err.<code>.title` / `err.<code>.message` in the locale files | codes come from `crates/coa-core/src/error.rs` |
|
||||||
|
|
||||||
|
`{name}` placeholders must stay exactly as they are. Plural forms use the suffixes `_one`, `_few`, `_many`, `_other`
|
||||||
|
(the browser picks the right one for the language).
|
||||||
|
|
||||||
|
## Checking your work
|
||||||
|
|
||||||
|
```
|
||||||
|
node tools/check-i18n.mjs # unknown keys, changed placeholders, coverage, schema overlays complete
|
||||||
|
npx tsc --noEmit # types
|
||||||
|
npx vite # UI with mock data in a browser; pick the language on the welcome screen
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding a language
|
||||||
|
|
||||||
|
1. Copy `src/i18n/locales/en.ts` to `<lang>.ts` (keep the keys), translate, and register it in `src/i18n/index.tsx`
|
||||||
|
(`Locale`, `LOCALES`, `DICTS`).
|
||||||
|
2. Copy `src/i18n/schema/ru.json` to `<lang>.json`, translate the values, and register it in `SCHEMA`.
|
||||||
|
3. Run the check above.
|
||||||
|
|
||||||
|
## Known gaps
|
||||||
|
|
||||||
|
* Free-form technical messages produced deep inside the backend (`Error::Invalid("...")`) stay in English; they are
|
||||||
|
shown as "technical details".
|
||||||
|
* Texts inside the game itself (client, server data) are not part of the Manager.
|
||||||
+11
-1
@@ -1,4 +1,8 @@
|
|||||||
// Dev-only: lets the UI run in a plain browser for visual review. Never bundled in production builds.
|
// Dev-only: lets the UI run in a plain browser for visual review. Never bundled in production builds.
|
||||||
|
import botsSchema from "../../schemas/bots.json";
|
||||||
|
import serverSchema from "../../schemas/server.json";
|
||||||
|
import botsPresets from "../../schemas/presets/bots.json";
|
||||||
|
import serverPresets from "../../schemas/presets/server.json";
|
||||||
export {};
|
export {};
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
@@ -14,7 +18,7 @@ export {};
|
|||||||
const svc=(n: string,p: number,st: string)=>({name:n,state:st,pid:st==="running"?100:null,port:p,port_ready:st==="running",conflict:null,uptime_secs:st==="running"?4206:null});
|
const svc=(n: string,p: number,st: string)=>({name:n,state:st,pid:st==="running"?100:null,port:p,port_ready:st==="running",conflict:null,uptime_secs:st==="running"?4206:null});
|
||||||
(window as any).__TAURI_INTERNALS__ = {
|
(window as any).__TAURI_INTERNALS__ = {
|
||||||
transformCallback: (cb: unknown)=>cb, unregisterCallback(){}, convertFileSrc:(x: unknown)=>x,
|
transformCallback: (cb: unknown)=>cb, unregisterCallback(){}, convertFileSrc:(x: unknown)=>x,
|
||||||
invoke: async (cmd: string)=>{
|
invoke: async (cmd: string, args?: any)=>{
|
||||||
if(cmd==="list_servers") return added?[{id:"1",name:"CoA-Repack",path:report.path}]:[];
|
if(cmd==="list_servers") return added?[{id:"1",name:"CoA-Repack",path:report.path}]:[];
|
||||||
if(cmd==="scan_server") return report;
|
if(cmd==="scan_server") return report;
|
||||||
if(cmd==="add_server"){added=true;return {id:"1",name:"CoA-Repack",path:report.path};}
|
if(cmd==="add_server"){added=true;return {id:"1",name:"CoA-Repack",path:report.path};}
|
||||||
@@ -22,6 +26,12 @@ export {};
|
|||||||
if(cmd==="start_server"){await new Promise((r: any)=>setTimeout(r,1500));running=true;return {ok:true,exit_code:0,code:null,human:null,output:""};}
|
if(cmd==="start_server"){await new Promise((r: any)=>setTimeout(r,1500));running=true;return {ok:true,exit_code:0,code:null,human:null,output:""};}
|
||||||
if(cmd==="stop_server"){await new Promise((r: any)=>setTimeout(r,1500));running=false;return {ok:true,exit_code:0,code:null,human:null,output:""};}
|
if(cmd==="stop_server"){await new Promise((r: any)=>setTimeout(r,1500));running=false;return {ok:true,exit_code:0,code:null,human:null,output:""};}
|
||||||
if(cmd.startsWith("plugin:dialog")) return "C:\games\CoA-Repack";
|
if(cmd.startsWith("plugin:dialog")) return "C:\games\CoA-Repack";
|
||||||
|
if(cmd==="get_settings"){const sc=args?.scope==="server"?serverSchema:botsSchema;return {scope:args?.scope,categories:sc.categories,settings:(sc.settings as any[]).map(x=>({...x,options:x.options??[],value:x.default,is_default:true,present:true,problem:null,drift:false})),unknown_keys:3,drift_keys:[],files:[]};}
|
||||||
|
if(cmd==="list_presets"){const pr=args?.scope==="server"?serverPresets:botsPresets;return (pr.presets as any[]).map(p=>({id:p.id,title:p.title,description:p.description}));}
|
||||||
|
if(cmd==="preview_preset"){const a=args;const sc=a.scope==="server"?serverSchema:botsSchema;const pr=(a.scope==="server"?serverPresets:botsPresets).presets as any[];const p=pr.find(x=>x.id===a.preset)??{id:a.preset??"defaults",title:"Recommended defaults",description:"Every setting returns to its default value."};const st=(sc.settings as any[]).filter(x=>x.type==="int"||x.type==="float"||x.type==="enum").slice(0,3);return {id:p.id,title:p.title,description:p.description,changes:st.map(x=>({key:x.key,title:x.title,from:x.default,to:x.type==="enum"?(x.options?.[1]?.value??x.default):(Number(x.default)||1)*2,dangerous:false}))};}
|
||||||
|
if(cmd==="companion_sizes") return {hardware:{cores:16,ram_gb:31,free_ram_gb:12},sizes:[{id:"small",title:"Small",bots:50,warning:null},{id:"medium",title:"Medium",bots:250,warning:null},{id:"large",title:"Large",bots:500,warning:"500 companions may need more CPU and memory than this computer has (8 cores, 16 GB)."}]};
|
||||||
|
if(cmd==="get_population") return null;
|
||||||
|
if(cmd==="run_diagnostics") return {problems:2,checks:[{id:"files",title:"Server files",level:"ok",detail:"All expected server parts were found."},{id:"world",title:"World server",level:"warn",detail:"Not running."},{id:"disk",title:"Free disk space",level:"warn",detail:"Only 3 GB free; backups and updates need room."},{id:"exposure",title:"Private services",level:"ok",detail:"Database and server console are not reachable from the network."}]};
|
||||||
if(cmd==="plugin:event|listen") return 1;
|
if(cmd==="plugin:event|listen") return 1;
|
||||||
if(cmd==="plugin:event|unlisten") return null;
|
if(cmd==="plugin:event|unlisten") return null;
|
||||||
throw new Error("unmocked "+cmd);
|
throw new Error("unmocked "+cmd);
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import ru from "./locales/ru";
|
|||||||
import de from "./locales/de";
|
import de from "./locales/de";
|
||||||
import fr from "./locales/fr";
|
import fr from "./locales/fr";
|
||||||
import es from "./locales/es";
|
import es from "./locales/es";
|
||||||
|
import ruSchema from "./schema/ru.json";
|
||||||
|
import deSchema from "./schema/de.json";
|
||||||
|
import frSchema from "./schema/fr.json";
|
||||||
|
import esSchema from "./schema/es.json";
|
||||||
|
|
||||||
export type Locale = "en" | "ru" | "de" | "fr" | "es";
|
export type Locale = "en" | "ru" | "de" | "fr" | "es";
|
||||||
export type Key = keyof typeof en;
|
export type Key = keyof typeof en;
|
||||||
@@ -83,6 +87,29 @@ export function I18nProvider({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
export const useI18n = () => useContext(I18n);
|
export const useI18n = () => useContext(I18n);
|
||||||
|
|
||||||
|
/** Translated text of the settings schemas (titles, descriptions, categories, presets, units). English comes from the backend. */
|
||||||
|
interface SchemaOverlay {
|
||||||
|
categories: Record<string, string>;
|
||||||
|
units: Record<string, string>;
|
||||||
|
settings: Record<string, { t: string; d: string }>;
|
||||||
|
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 };
|
||||||
|
|
||||||
|
export function useSchemaText() {
|
||||||
|
const { locale } = useContext(I18n);
|
||||||
|
const o = SCHEMA[locale];
|
||||||
|
return {
|
||||||
|
title: (s: { key: string; title: string }) => o?.settings[s.key]?.t ?? s.title,
|
||||||
|
description: (s: { key: string; description: string }) => o?.settings[s.key]?.d ?? s.description,
|
||||||
|
category: (scope: string, c: { id: string; title: string }) => o?.categories[`${scope}.${c.id}`] ?? c.title,
|
||||||
|
option: (key: string, opt: { value: unknown; label: string }) => o?.options[`${key}.${String(opt.value)}`] ?? opt.label,
|
||||||
|
unit: (u: string) => o?.units[u] ?? u,
|
||||||
|
preset: (p: { id: string; title: string; description: string }) => ({ title: o?.presets[p.id]?.t ?? p.title, description: o?.presets[p.id]?.d ?? p.description }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** Translated title/message for a backend error; falls back to the backend's English text for unknown codes. */
|
/** Translated title/message for a backend error; falls back to the backend's English text for unknown codes. */
|
||||||
export function useHuman() {
|
export function useHuman() {
|
||||||
const { t } = useContext(I18n);
|
const { t } = useContext(I18n);
|
||||||
@@ -93,3 +120,6 @@ export function useHuman() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
export const useT = () => useContext(I18n).t;
|
export const useT = () => useContext(I18n).t;
|
||||||
|
|
||||||
|
/** True when `key` exists in the catalogue (backend-supplied texts are translated only when a key is defined for them). */
|
||||||
|
export const hasKey = (key: string): key is Key => key in en;
|
||||||
@@ -433,6 +433,70 @@ const de: Partial<Record<keyof typeof en, string>> = {
|
|||||||
|
|
||||||
// Friends line
|
// Friends line
|
||||||
"fr.copyLine": "Zeile kopieren",
|
"fr.copyLine": "Zeile kopieren",
|
||||||
|
|
||||||
|
// Diagnostics checks
|
||||||
|
"dg.title.files": "Serverdateien",
|
||||||
|
"dg.title.missing_parts": "Fehlende Teile",
|
||||||
|
"dg.title.mysql": "Datenbank",
|
||||||
|
"dg.title.auth": "Anmeldeserver",
|
||||||
|
"dg.title.world": "Weltserver",
|
||||||
|
"dg.title.configs": "Konfiguration",
|
||||||
|
"dg.title.config_values": "Einstellungswerte",
|
||||||
|
"dg.title.disk": "Freier Speicherplatz",
|
||||||
|
"dg.title.permissions": "Berechtigungen",
|
||||||
|
"dg.title.client": "Spielclient",
|
||||||
|
"dg.title.exposure": "Private Dienste",
|
||||||
|
"dg.files.ok": "Alle erwarteten Serverteile wurden gefunden.",
|
||||||
|
"dg.files.partial": "Einige Serverteile fehlen.",
|
||||||
|
"dg.files.custom": "Dies ist ein angepasster Server-Build; einige Funktionen sind eingeschränkt.",
|
||||||
|
"dg.files.bad": "Dieser Ordner sieht nicht wie ein CoA-Server aus.",
|
||||||
|
"dg.svc.running": "Läuft",
|
||||||
|
"dg.svc.port": "Port {port} wird von einem anderen Programm verwendet (Prozess {pid}).",
|
||||||
|
"dg.svc.starting": "Startet, antwortet noch nicht.",
|
||||||
|
"dg.svc.stopped": "Läuft nicht.",
|
||||||
|
"dg.configs.ok": "Konfigurationsdateien können gelesen werden.",
|
||||||
|
"dg.configs.bad": "Nicht lesbar: {files}",
|
||||||
|
"dg.values.bad": "Unbrauchbare Werte bei: {keys}",
|
||||||
|
"dg.disk.ok": "{gb} GB frei",
|
||||||
|
"dg.disk.low": "Nur {gb} GB frei; Sicherungen und Updates brauchen Platz.",
|
||||||
|
"dg.perm.ok": "Der Serverordner ist beschreibbar.",
|
||||||
|
"dg.perm.bad": "Der Manager kann nicht in den Serverordner schreiben (wähle einen anderen Ort oder starte einmal als Administrator).",
|
||||||
|
"dg.client.missing": "Der gespeicherte Spielordner wurde nicht gefunden; wähle ihn in den Einstellungen erneut.",
|
||||||
|
"dg.exposure.ok": "Datenbank und Serverkonsole sind aus dem Netzwerk nicht erreichbar.",
|
||||||
|
"dg.exposure.bad": "Aus dem Netzwerk erreichbar: {what}.",
|
||||||
|
|
||||||
|
// Update steps
|
||||||
|
"ustep.Starting": "Start",
|
||||||
|
"ustep.Checking the update": "Update wird geprüft",
|
||||||
|
"ustep.Downloading the update": "Update wird heruntergeladen",
|
||||||
|
"ustep.Verifying the update": "Update wird verifiziert",
|
||||||
|
"ustep.Making sure the server is stopped": "Es wird sichergestellt, dass der Server gestoppt ist",
|
||||||
|
"ustep.Saving a recovery point": "Wiederherstellungspunkt wird gespeichert",
|
||||||
|
"ustep.Applying the update": "Update wird angewendet",
|
||||||
|
"ustep.Updating the database": "Datenbank wird aktualisiert",
|
||||||
|
"ustep.Starting the updated server": "Aktualisierter Server wird gestartet",
|
||||||
|
"ustep.Finishing": "Abschluss",
|
||||||
|
"ustep.Undoing the update": "Update wird rückgängig gemacht",
|
||||||
|
"ustep.Done": "Fertig",
|
||||||
|
|
||||||
|
// Companion sizes
|
||||||
|
"comp.size.small": "Klein",
|
||||||
|
"comp.size.medium": "Mittel",
|
||||||
|
"comp.size.large": "Groß",
|
||||||
|
"comp.warnHardware": "{n} Begleiter brauchen möglicherweise mehr CPU und Speicher, als dieser Computer hat ({cores} Kerne, {ram} GB).",
|
||||||
|
"comp.warnMemory": "Gib zuerst etwas Speicher frei; andere Programme belegen den größten Teil.",
|
||||||
|
|
||||||
|
// Friends notes
|
||||||
|
"fr.note.forwarded": "Dein Router wurde gebeten, die Spielports weiterzuleiten.",
|
||||||
|
"fr.note.manual": "Dein Router unterstützt keine automatische Einrichtung; leite die beiden Spielports manuell weiter oder nutze das private Netzwerk.",
|
||||||
|
|
||||||
|
// Import labels and placeholder
|
||||||
|
"scan.label.worldserver": "Weltserver",
|
||||||
|
"scan.label.authserver": "Anmeldeserver",
|
||||||
|
"scan.label.database_content": "Datenbanken für Anmeldung, Charaktere und Welt",
|
||||||
|
"scan.label.companions": "CoA-Begleiter (Bots)",
|
||||||
|
"scan.label.client": "Spielclient",
|
||||||
|
"placeholder.soon": "Dieser Bereich entsteht in einer späteren Version.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default de;
|
export default de;
|
||||||
@@ -433,6 +433,70 @@ const en = {
|
|||||||
|
|
||||||
// Friends line
|
// Friends line
|
||||||
"fr.copyLine": "Copy line",
|
"fr.copyLine": "Copy line",
|
||||||
|
|
||||||
|
// Diagnostics checks
|
||||||
|
"dg.title.files": "Server files",
|
||||||
|
"dg.title.missing_parts": "Missing parts",
|
||||||
|
"dg.title.mysql": "Database",
|
||||||
|
"dg.title.auth": "Login server",
|
||||||
|
"dg.title.world": "World server",
|
||||||
|
"dg.title.configs": "Configuration",
|
||||||
|
"dg.title.config_values": "Setting values",
|
||||||
|
"dg.title.disk": "Free disk space",
|
||||||
|
"dg.title.permissions": "Permissions",
|
||||||
|
"dg.title.client": "Game client",
|
||||||
|
"dg.title.exposure": "Private services",
|
||||||
|
"dg.files.ok": "All expected server parts were found.",
|
||||||
|
"dg.files.partial": "Some server parts are missing.",
|
||||||
|
"dg.files.custom": "This is a custom server build; some features are limited.",
|
||||||
|
"dg.files.bad": "This folder does not look like a CoA server.",
|
||||||
|
"dg.svc.running": "Running",
|
||||||
|
"dg.svc.port": "Port {port} is used by another program (process {pid}).",
|
||||||
|
"dg.svc.starting": "Starting, not answering yet.",
|
||||||
|
"dg.svc.stopped": "Not running.",
|
||||||
|
"dg.configs.ok": "Configuration files can be read.",
|
||||||
|
"dg.configs.bad": "Cannot read: {files}",
|
||||||
|
"dg.values.bad": "Unusable values for: {keys}",
|
||||||
|
"dg.disk.ok": "{gb} GB free",
|
||||||
|
"dg.disk.low": "Only {gb} GB free; backups and updates need room.",
|
||||||
|
"dg.perm.ok": "The server folder is writable.",
|
||||||
|
"dg.perm.bad": "The Manager cannot write to the server folder (try another location or run once as administrator).",
|
||||||
|
"dg.client.missing": "The saved game folder was not found; choose it again in Settings.",
|
||||||
|
"dg.exposure.ok": "Database and server console are not reachable from the network.",
|
||||||
|
"dg.exposure.bad": "Reachable from the network: {what}.",
|
||||||
|
|
||||||
|
// Update steps
|
||||||
|
"ustep.Starting": "Starting",
|
||||||
|
"ustep.Checking the update": "Checking the update",
|
||||||
|
"ustep.Downloading the update": "Downloading the update",
|
||||||
|
"ustep.Verifying the update": "Verifying the update",
|
||||||
|
"ustep.Making sure the server is stopped": "Making sure the server is stopped",
|
||||||
|
"ustep.Saving a recovery point": "Saving a recovery point",
|
||||||
|
"ustep.Applying the update": "Applying the update",
|
||||||
|
"ustep.Updating the database": "Updating the database",
|
||||||
|
"ustep.Starting the updated server": "Starting the updated server",
|
||||||
|
"ustep.Finishing": "Finishing",
|
||||||
|
"ustep.Undoing the update": "Undoing the update",
|
||||||
|
"ustep.Done": "Done",
|
||||||
|
|
||||||
|
// Companion sizes
|
||||||
|
"comp.size.small": "Small",
|
||||||
|
"comp.size.medium": "Medium",
|
||||||
|
"comp.size.large": "Large",
|
||||||
|
"comp.warnHardware": "{n} companions may need more CPU and memory than this computer has ({cores} cores, {ram} GB).",
|
||||||
|
"comp.warnMemory": "Free some memory first; other programs are using most of it.",
|
||||||
|
|
||||||
|
// Friends notes
|
||||||
|
"fr.note.forwarded": "Your router was asked to forward the game ports.",
|
||||||
|
"fr.note.manual": "Your router does not support automatic setup; forward the two game ports by hand or use the private network.",
|
||||||
|
|
||||||
|
// Import labels and placeholder
|
||||||
|
"scan.label.worldserver": "World server",
|
||||||
|
"scan.label.authserver": "Auth server",
|
||||||
|
"scan.label.database_content": "Auth / Characters / World databases",
|
||||||
|
"scan.label.companions": "CoA Companions (bots)",
|
||||||
|
"scan.label.client": "Game client",
|
||||||
|
"placeholder.soon": "This section is being built in a later release.",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default en;
|
export default en;
|
||||||
@@ -433,6 +433,70 @@ const es: Partial<Record<keyof typeof en, string>> = {
|
|||||||
|
|
||||||
// Friends line
|
// Friends line
|
||||||
"fr.copyLine": "Copiar línea",
|
"fr.copyLine": "Copiar línea",
|
||||||
|
|
||||||
|
// Diagnostics checks
|
||||||
|
"dg.title.files": "Archivos del servidor",
|
||||||
|
"dg.title.missing_parts": "Partes que faltan",
|
||||||
|
"dg.title.mysql": "Base de datos",
|
||||||
|
"dg.title.auth": "Servidor de acceso",
|
||||||
|
"dg.title.world": "Servidor del mundo",
|
||||||
|
"dg.title.configs": "Configuración",
|
||||||
|
"dg.title.config_values": "Valores de los ajustes",
|
||||||
|
"dg.title.disk": "Espacio libre en disco",
|
||||||
|
"dg.title.permissions": "Permisos",
|
||||||
|
"dg.title.client": "Cliente del juego",
|
||||||
|
"dg.title.exposure": "Servicios privados",
|
||||||
|
"dg.files.ok": "Se encontraron todas las partes esperadas del servidor.",
|
||||||
|
"dg.files.partial": "Faltan algunas partes del servidor.",
|
||||||
|
"dg.files.custom": "Esta es una versión personalizada del servidor; algunas funciones están limitadas.",
|
||||||
|
"dg.files.bad": "Esta carpeta no parece un servidor de CoA.",
|
||||||
|
"dg.svc.running": "En marcha",
|
||||||
|
"dg.svc.port": "El puerto {port} lo usa otro programa (proceso {pid}).",
|
||||||
|
"dg.svc.starting": "Iniciándose, aún no responde.",
|
||||||
|
"dg.svc.stopped": "No está en marcha.",
|
||||||
|
"dg.configs.ok": "Los archivos de configuración se pueden leer.",
|
||||||
|
"dg.configs.bad": "No se puede leer: {files}",
|
||||||
|
"dg.values.bad": "Valores inutilizables en: {keys}",
|
||||||
|
"dg.disk.ok": "{gb} GB libres",
|
||||||
|
"dg.disk.low": "Solo {gb} GB libres; las copias y las actualizaciones necesitan espacio.",
|
||||||
|
"dg.perm.ok": "La carpeta del servidor admite escritura.",
|
||||||
|
"dg.perm.bad": "El Manager no puede escribir en la carpeta del servidor (prueba otra ubicación o ejecútalo una vez como administrador).",
|
||||||
|
"dg.client.missing": "No se encontró la carpeta del juego guardada; elígela de nuevo en Ajustes.",
|
||||||
|
"dg.exposure.ok": "La base de datos y la consola del servidor no son accesibles desde la red.",
|
||||||
|
"dg.exposure.bad": "Accesible desde la red: {what}.",
|
||||||
|
|
||||||
|
// Update steps
|
||||||
|
"ustep.Starting": "Iniciando",
|
||||||
|
"ustep.Checking the update": "Comprobando la actualización",
|
||||||
|
"ustep.Downloading the update": "Descargando la actualización",
|
||||||
|
"ustep.Verifying the update": "Verificando la actualización",
|
||||||
|
"ustep.Making sure the server is stopped": "Comprobando que el servidor está detenido",
|
||||||
|
"ustep.Saving a recovery point": "Guardando un punto de recuperación",
|
||||||
|
"ustep.Applying the update": "Aplicando la actualización",
|
||||||
|
"ustep.Updating the database": "Actualizando la base de datos",
|
||||||
|
"ustep.Starting the updated server": "Iniciando el servidor actualizado",
|
||||||
|
"ustep.Finishing": "Finalizando",
|
||||||
|
"ustep.Undoing the update": "Deshaciendo la actualización",
|
||||||
|
"ustep.Done": "Hecho",
|
||||||
|
|
||||||
|
// Companion sizes
|
||||||
|
"comp.size.small": "Pequeño",
|
||||||
|
"comp.size.medium": "Mediano",
|
||||||
|
"comp.size.large": "Grande",
|
||||||
|
"comp.warnHardware": "{n} compañeros pueden necesitar más CPU y memoria de las que tiene este equipo ({cores} núcleos, {ram} GB).",
|
||||||
|
"comp.warnMemory": "Libera primero algo de memoria; otros programas usan la mayor parte.",
|
||||||
|
|
||||||
|
// Friends notes
|
||||||
|
"fr.note.forwarded": "Se pidió a tu router que redirigiera los puertos del juego.",
|
||||||
|
"fr.note.manual": "Tu router no admite la configuración automática; redirige los dos puertos del juego a mano o usa la red privada.",
|
||||||
|
|
||||||
|
// Import labels and placeholder
|
||||||
|
"scan.label.worldserver": "Servidor del mundo",
|
||||||
|
"scan.label.authserver": "Servidor de acceso",
|
||||||
|
"scan.label.database_content": "Bases de datos de acceso, personajes y mundo",
|
||||||
|
"scan.label.companions": "Compañeros de CoA (bots)",
|
||||||
|
"scan.label.client": "Cliente del juego",
|
||||||
|
"placeholder.soon": "Esta sección se está desarrollando para una versión posterior.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default es;
|
export default es;
|
||||||
@@ -433,6 +433,70 @@ const fr: Partial<Record<keyof typeof en, string>> = {
|
|||||||
|
|
||||||
// Friends line
|
// Friends line
|
||||||
"fr.copyLine": "Copier la ligne",
|
"fr.copyLine": "Copier la ligne",
|
||||||
|
|
||||||
|
// Diagnostics checks
|
||||||
|
"dg.title.files": "Fichiers du serveur",
|
||||||
|
"dg.title.missing_parts": "Parties manquantes",
|
||||||
|
"dg.title.mysql": "Base de données",
|
||||||
|
"dg.title.auth": "Serveur de connexion",
|
||||||
|
"dg.title.world": "Serveur de monde",
|
||||||
|
"dg.title.configs": "Configuration",
|
||||||
|
"dg.title.config_values": "Valeurs des paramètres",
|
||||||
|
"dg.title.disk": "Espace disque libre",
|
||||||
|
"dg.title.permissions": "Autorisations",
|
||||||
|
"dg.title.client": "Client du jeu",
|
||||||
|
"dg.title.exposure": "Services privés",
|
||||||
|
"dg.files.ok": "Toutes les parties attendues du serveur ont été trouvées.",
|
||||||
|
"dg.files.partial": "Certaines parties du serveur manquent.",
|
||||||
|
"dg.files.custom": "Il s’agit d’une version personnalisée du serveur ; certaines fonctions sont limitées.",
|
||||||
|
"dg.files.bad": "Ce dossier ne ressemble pas à un serveur CoA.",
|
||||||
|
"dg.svc.running": "En cours",
|
||||||
|
"dg.svc.port": "Le port {port} est utilisé par un autre programme (processus {pid}).",
|
||||||
|
"dg.svc.starting": "Démarrage, ne répond pas encore.",
|
||||||
|
"dg.svc.stopped": "Non démarré.",
|
||||||
|
"dg.configs.ok": "Les fichiers de configuration sont lisibles.",
|
||||||
|
"dg.configs.bad": "Lecture impossible : {files}",
|
||||||
|
"dg.values.bad": "Valeurs inutilisables pour : {keys}",
|
||||||
|
"dg.disk.ok": "{gb} Go libres",
|
||||||
|
"dg.disk.low": "Seulement {gb} Go libres ; les sauvegardes et mises à jour ont besoin de place.",
|
||||||
|
"dg.perm.ok": "Le dossier du serveur est accessible en écriture.",
|
||||||
|
"dg.perm.bad": "Le Manager ne peut pas écrire dans le dossier du serveur (essayez un autre emplacement ou lancez-le une fois en administrateur).",
|
||||||
|
"dg.client.missing": "Le dossier de jeu enregistré est introuvable ; choisissez-le à nouveau dans les Paramètres.",
|
||||||
|
"dg.exposure.ok": "La base de données et la console du serveur ne sont pas joignables depuis le réseau.",
|
||||||
|
"dg.exposure.bad": "Joignable depuis le réseau : {what}.",
|
||||||
|
|
||||||
|
// Update steps
|
||||||
|
"ustep.Starting": "Démarrage",
|
||||||
|
"ustep.Checking the update": "Vérification de la mise à jour",
|
||||||
|
"ustep.Downloading the update": "Téléchargement de la mise à jour",
|
||||||
|
"ustep.Verifying the update": "Vérification de la mise à jour",
|
||||||
|
"ustep.Making sure the server is stopped": "Vérification que le serveur est arrêté",
|
||||||
|
"ustep.Saving a recovery point": "Enregistrement d’un point de restauration",
|
||||||
|
"ustep.Applying the update": "Application de la mise à jour",
|
||||||
|
"ustep.Updating the database": "Mise à jour de la base de données",
|
||||||
|
"ustep.Starting the updated server": "Démarrage du serveur mis à jour",
|
||||||
|
"ustep.Finishing": "Finalisation",
|
||||||
|
"ustep.Undoing the update": "Annulation de la mise à jour",
|
||||||
|
"ustep.Done": "Terminé",
|
||||||
|
|
||||||
|
// Companion sizes
|
||||||
|
"comp.size.small": "Petit",
|
||||||
|
"comp.size.medium": "Moyen",
|
||||||
|
"comp.size.large": "Grand",
|
||||||
|
"comp.warnHardware": "{n} compagnons peuvent demander plus de processeur et de mémoire que cet ordinateur n’en a ({cores} cœurs, {ram} Go).",
|
||||||
|
"comp.warnMemory": "Libérez d’abord de la mémoire ; d’autres programmes en utilisent la plus grande partie.",
|
||||||
|
|
||||||
|
// Friends notes
|
||||||
|
"fr.note.forwarded": "Votre routeur a été invité à rediriger les ports du jeu.",
|
||||||
|
"fr.note.manual": "Votre routeur ne prend pas en charge la configuration automatique ; redirigez les deux ports du jeu à la main ou utilisez le réseau privé.",
|
||||||
|
|
||||||
|
// Import labels and placeholder
|
||||||
|
"scan.label.worldserver": "Serveur de monde",
|
||||||
|
"scan.label.authserver": "Serveur de connexion",
|
||||||
|
"scan.label.database_content": "Bases de données connexion / personnages / monde",
|
||||||
|
"scan.label.companions": "Compagnons CoA (bots)",
|
||||||
|
"scan.label.client": "Client du jeu",
|
||||||
|
"placeholder.soon": "Cette section sera développée dans une prochaine version.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default fr;
|
export default fr;
|
||||||
@@ -433,6 +433,70 @@ const ru: Partial<Record<keyof typeof en, string>> = {
|
|||||||
|
|
||||||
// Friends line
|
// Friends line
|
||||||
"fr.copyLine": "Скопировать строку",
|
"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}).",
|
||||||
|
"dg.svc.starting": "Запускается, пока не отвечает.",
|
||||||
|
"dg.svc.stopped": "Не запущено.",
|
||||||
|
"dg.configs.ok": "Файлы конфигурации читаются.",
|
||||||
|
"dg.configs.bad": "Не удаётся прочитать: {files}",
|
||||||
|
"dg.values.bad": "Недопустимые значения у: {keys}",
|
||||||
|
"dg.disk.ok": "Свободно {gb} ГБ",
|
||||||
|
"dg.disk.low": "Свободно только {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} компаньонов может не хватить процессора и памяти этого компьютера (ядер — {cores}, памяти — {ram} ГБ).",
|
||||||
|
"comp.warnMemory": "Сначала освободите память: большую её часть занимают другие программы.",
|
||||||
|
|
||||||
|
// Friends notes
|
||||||
|
"fr.note.forwarded": "Роутеру отправлена просьба пробросить игровые порты.",
|
||||||
|
"fr.note.manual": "Ваш роутер не поддерживает автоматическую настройку; пробросьте два игровых порта вручную или используйте частную сеть.",
|
||||||
|
|
||||||
|
// Import labels and placeholder
|
||||||
|
"scan.label.worldserver": "Игровой сервер (мир)",
|
||||||
|
"scan.label.authserver": "Сервер входа",
|
||||||
|
"scan.label.database_content": "Базы данных входа, персонажей и мира",
|
||||||
|
"scan.label.companions": "Компаньоны CoA (боты)",
|
||||||
|
"scan.label.client": "Клиент игры",
|
||||||
|
"placeholder.soon": "Этот раздел появится в одном из следующих выпусков.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ru;
|
export default ru;
|
||||||
@@ -0,0 +1,513 @@
|
|||||||
|
{
|
||||||
|
"categories": {
|
||||||
|
"bots.general": "Allgemein",
|
||||||
|
"bots.population": "Population",
|
||||||
|
"bots.login": "Anmeldung",
|
||||||
|
"bots.roles": "Rollen",
|
||||||
|
"bots.openworld": "Offene Welt",
|
||||||
|
"bots.quests": "Quests",
|
||||||
|
"bots.combat": "Kampf",
|
||||||
|
"bots.dungeon": "Dungeonsuche",
|
||||||
|
"bots.battlegrounds": "Schlachtfelder",
|
||||||
|
"bots.social": "Soziales Verhalten",
|
||||||
|
"bots.advanced": "Erweitert",
|
||||||
|
"server.gameplay": "Spielablauf",
|
||||||
|
"server.rates": "Raten",
|
||||||
|
"server.characters": "Charaktere",
|
||||||
|
"server.world": "Welt",
|
||||||
|
"server.network": "Netzwerk",
|
||||||
|
"server.accounts": "Konten",
|
||||||
|
"server.logging": "Protokolle",
|
||||||
|
"server.performance": "Leistung",
|
||||||
|
"server.advanced": "Erweitert"
|
||||||
|
},
|
||||||
|
"units": {
|
||||||
|
"ms": "ms",
|
||||||
|
"%": "%",
|
||||||
|
"yards": "Yards",
|
||||||
|
"levels": "Stufen",
|
||||||
|
"x": "×",
|
||||||
|
"min": "Min.",
|
||||||
|
"copper": "Kupfer"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"CoaBots.RandomSpawn.DefaultCount": {
|
||||||
|
"t": "Bots pro Erstellungsbefehl",
|
||||||
|
"d": "Wie viele Bots der Erstellungsbefehl anlegt, wenn du keine Zahl angibst."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.MaxCount": {
|
||||||
|
"t": "Größte einzelne Erstellung",
|
||||||
|
"d": "Sicherheitsgrenze für einen Erstellungsbefehl. Sehr große Mengen können den Server kurz einfrieren lassen; erhöhe den Wert daher nur, wenn sonst niemand spielt."
|
||||||
|
},
|
||||||
|
"CoaBots.LeveledSpawn.Brackets": {
|
||||||
|
"t": "Stufenmix neuer Bots",
|
||||||
|
"d": "Wie neue Level-Bots auf Stufen verteilt werden, als Bereiche mit Gewichten (1-20:40 bedeutet 40 Teile Bots zwischen Stufe 1 und 20)."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.AutoLogin": {
|
||||||
|
"t": "Neue Bots sofort online bringen",
|
||||||
|
"d": "Neu erstellte Bots melden sich sofort an, statt in der Datenbank zu warten."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.AccountPrefix": {
|
||||||
|
"t": "Namenspräfix der Bot-Konten",
|
||||||
|
"d": "Bots leben auf Konten, deren Name mit diesem Präfix beginnt. Wird es geändert, melden sich vorhandene Bots nicht mehr automatisch an."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.BatchSize": {
|
||||||
|
"t": "Bots pro Erstellungsschritt",
|
||||||
|
"d": "Die Erstellung wird zeitlich gestreckt, damit der Server flüssig bleibt. Höhere Werte sind schneller, können aber Ruckler verursachen."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.BatchIntervalMs": {
|
||||||
|
"t": "Pause zwischen Erstellungsschritten",
|
||||||
|
"d": "Zeit zwischen den Erstellungsschritten. Niedrigere Werte sind schneller, können aber Ruckler verursachen."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLoginOnStartup": {
|
||||||
|
"t": "Automatische Bot-Anmeldung",
|
||||||
|
"d": "Vorhandene Bots melden sich bei jedem Serverstart selbst an."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.MaxCount": {
|
||||||
|
"t": "Maximale Bots online",
|
||||||
|
"d": "Die höchste Anzahl an Bots, die sich beim Start automatisch anmelden."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.BatchSize": {
|
||||||
|
"t": "Bots pro Anmeldeschritt",
|
||||||
|
"d": "Anmeldungen werden zeitlich gestreckt. Höhere Werte bringen Bots schneller online, belasten den Server aber stärker."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.BatchIntervalMs": {
|
||||||
|
"t": "Pause zwischen Anmeldeschritten",
|
||||||
|
"d": "Zeit zwischen den Anmeldeschritten."
|
||||||
|
},
|
||||||
|
"CoaBots.SpecBalance.TankTargetPct": {
|
||||||
|
"t": "Zielanteil an Tanks",
|
||||||
|
"d": "Anteil der Bots, die Tanks sein sollen."
|
||||||
|
},
|
||||||
|
"CoaBots.SpecBalance.HealerTargetPct": {
|
||||||
|
"t": "Zielanteil an Heilern",
|
||||||
|
"d": "Anteil der Bots, die Heiler sein sollen."
|
||||||
|
},
|
||||||
|
"CoaBots.TalentBuildsPath": {
|
||||||
|
"t": "Talentdatendatei",
|
||||||
|
"d": "Wo die Talent-Builds der Community gespeichert sind. Leer lassen, um die eingebaute Suche zu nutzen."
|
||||||
|
},
|
||||||
|
"CoaBots.World.Enable": {
|
||||||
|
"t": "Bots streifen durch die Welt",
|
||||||
|
"d": "Untätige Bots erledigen Besorgungen: Sie besuchen Stadtdienste, reisen zu Sammel- oder Grind-Gebieten oder wandern ein wenig umher."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Enable": {
|
||||||
|
"t": "Quest-KI",
|
||||||
|
"d": "Bots nehmen Quests selbstständig an und erledigen sie. Wenn ausgeschaltet, sammeln, angeln, grinden und wandern Bots nur."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ServiceRadius": {
|
||||||
|
"t": "Suchradius für Stadtdienste",
|
||||||
|
"d": "Wie weit ein Bot nach Händlern und Briefkästen sucht."
|
||||||
|
},
|
||||||
|
"CoaBots.World.AreaRadius": {
|
||||||
|
"t": "Radius des Besorgungsgebiets",
|
||||||
|
"d": "Wie weit ein Bot nach Sammel- oder Grind-Gebieten sucht."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ThinkIntervalMs": {
|
||||||
|
"t": "Prüfintervall für Besorgungen",
|
||||||
|
"d": "Wie oft jeder Bot seine Besorgung neu überdenkt."
|
||||||
|
},
|
||||||
|
"CoaBots.World.IdleBeforeErrandMs": {
|
||||||
|
"t": "Leerlaufzeit vor einer Besorgung",
|
||||||
|
"d": "Wie lange ein Bot nichts zu tun finden muss, bevor er eine Besorgung beginnt."
|
||||||
|
},
|
||||||
|
"CoaBots.World.VerboseLog": {
|
||||||
|
"t": "Ausführliches Besorgungsprotokoll",
|
||||||
|
"d": "Schreibt jeden Schritt einer Besorgung ins Protokoll. Nützlich zur Fehlersuche, bei vielen Bots aber sehr laut."
|
||||||
|
},
|
||||||
|
"CoaBots.Combat.VerboseLog": {
|
||||||
|
"t": "Ausführliches Kampfprotokoll",
|
||||||
|
"d": "Schreibt Kampfentscheidungen ins Protokoll. Sehr laut; nur einschalten, wenn du ein bestimmtes Problem suchst."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMinMs": {
|
||||||
|
"t": "Kürzeste Aktivität",
|
||||||
|
"d": "Die kürzeste Zeit, die ein Bot bei einer Art von Aktivität bleibt."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMaxMs": {
|
||||||
|
"t": "Längste Aktivität",
|
||||||
|
"d": "Die längste Zeit, die ein Bot bei einer Art von Aktivität bleibt."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.SearchRadius": {
|
||||||
|
"t": "Suchradius fürs Grinden",
|
||||||
|
"d": "Wie weit ein Bot nach Monstern zum Grinden sucht."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.MaxLevelAbove": {
|
||||||
|
"t": "Höchste Monsterstufe fürs Grinden",
|
||||||
|
"d": "Um wie viele Stufen über sich selbst ein Bot beim Grinden kämpft."
|
||||||
|
},
|
||||||
|
"CoaBots.Healer.CriticalHealPct": {
|
||||||
|
"t": "Schwelle für Notheilung",
|
||||||
|
"d": "Heiler wechseln zu ihren stärksten Heilungen, wenn die Gesundheit eines Verbündeten darunter fällt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchRadius": {
|
||||||
|
"t": "Suchradius für Ziele",
|
||||||
|
"d": "Wie weit ein Bot innerhalb eines Zielgebiets nach Questzielen sucht."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.EngageRange": {
|
||||||
|
"t": "Angriffsentfernung",
|
||||||
|
"d": "Entfernung, ab der ein Bot einen Quest-Gegner bekämpft."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMin": {
|
||||||
|
"t": "Aufsitzen ab (Min.)",
|
||||||
|
"d": "Jeder Bot sitzt bei Reisen auf, die länger sind als eine persönliche Entfernung, die zwischen diesem Wert und dem Maximum gewählt wird."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMax": {
|
||||||
|
"t": "Aufsitzen ab (Max.)",
|
||||||
|
"d": "Oberes Ende der persönlichen Aufsitzentfernung."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TaxiMinDistance": {
|
||||||
|
"t": "Flugrouten nutzen ab",
|
||||||
|
"d": "Reisen, die länger sind, nutzen eine Flugroute, wenn der Bot eine kennt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SessionBreaks": {
|
||||||
|
"t": "Pausen einlegen",
|
||||||
|
"d": "Bots wechseln Questen mit ein paar Minuten Stadtleben ab, wie ein Spieler."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GatherDetours": {
|
||||||
|
"t": "Kräuter und Erz in der Nähe sammeln",
|
||||||
|
"d": "Sammler weichen vom Weg ab, wenn direkt daneben ein Vorkommen liegt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxActiveQuests": {
|
||||||
|
"t": "Maximale aktive Quests",
|
||||||
|
"d": "Wie viele Quests ein Bot gleichzeitig trägt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.AcceptEliteQuests": {
|
||||||
|
"t": "Elite-Quests annehmen",
|
||||||
|
"d": "Einzelne Bots übernehmen Elite-Quests. Standardmäßig aus, weil sie diese allein meist nicht schaffen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestLevelBelow": {
|
||||||
|
"t": "Quests unter der eigenen Stufe",
|
||||||
|
"d": "Um wie viele Stufen unter sich selbst ein Bot noch Quests annimmt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestLevelAbove": {
|
||||||
|
"t": "Quests über der eigenen Stufe",
|
||||||
|
"d": "Um wie viele Stufen über sich selbst ein Bot noch Quests annimmt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxMobLevelAbove": {
|
||||||
|
"t": "Höchste Stufe von Quest-Monstern",
|
||||||
|
"d": "Wie weit über seiner Stufe ein Quest-Monster sein darf."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxObjectiveDistance": {
|
||||||
|
"t": "Am weitesten entferntes Questziel",
|
||||||
|
"d": "Quests, deren Ziele weiter entfernt sind, werden nicht angenommen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GiverSearchRadius": {
|
||||||
|
"t": "Suchradius für Questgeber",
|
||||||
|
"d": "Wie weit ein Bot nach Questgebern sucht."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxBadAreasPerObjective": {
|
||||||
|
"t": "Versuchte Gebiete pro Ziel",
|
||||||
|
"d": "Wie viele Gebiete ein Bot aufgibt, bevor er die Quest zurückstellt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMs": {
|
||||||
|
"t": "Zurückstellzeit (kurz)",
|
||||||
|
"d": "Wie lange eine Quest zurückgestellt wird, nachdem der Bot sie aufgegeben hat."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMaxMs": {
|
||||||
|
"t": "Zurückstellzeit (lang)",
|
||||||
|
"d": "Die längste Zeit, die eine Quest nach wiederholtem Scheitern zurückgestellt bleiben kann."
|
||||||
|
},
|
||||||
|
"CoaBots.LfgFill.Enable": {
|
||||||
|
"t": "Bot-Auffüllung der Dungeonsuche",
|
||||||
|
"d": "Wenn du allein für einen Dungeon anstehst, übernehmen Bots die fehlenden Rollen Tank, Heiler und Schaden."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoQueueDungeon.Enable": {
|
||||||
|
"t": "Bots stellen sich selbst für Dungeons an",
|
||||||
|
"d": "Experimentell: Untätige Tank-Bots stellen sich selbst für einen Dungeon an, und die Auffüllung oben vervollständigt die Gruppe."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.Enable": {
|
||||||
|
"t": "Bot-Auffüllung für Schlachtfelder",
|
||||||
|
"d": "Wenn jemand für ein Schlachtfeld ansteht, werden beide Teams mit Bots aufgefüllt, damit das Spiel sofort beginnt."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.TargetPlayersPerTeam": {
|
||||||
|
"t": "Teamgröße auf Schlachtfeldern",
|
||||||
|
"d": "Bis zu wie vielen Bots pro Team aufgefüllt wird. 0 bedeutet ein volles Team für dieses Schlachtfeld."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpOthers": {
|
||||||
|
"t": "Bots helfen Spielern in der Nähe",
|
||||||
|
"d": "Ein vorbeikommender Bot steigt in einen Kampf ein, den ein befreundeter Spieler verliert, ohne dessen Beute oder Anrechnung zu nehmen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpRadius": {
|
||||||
|
"t": "Hilfsentfernung",
|
||||||
|
"d": "Wie nah ein Bot sein muss, um in einen Kampf einzugreifen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpHealthPct": {
|
||||||
|
"t": "Helfen unter Gesundheit",
|
||||||
|
"d": "Bots helfen, wenn die Gesundheit des kämpfenden Spielers darunter liegt."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ResurrectOthers": {
|
||||||
|
"t": "Bots beleben gefallene Spieler",
|
||||||
|
"d": "Bots, die einen Wiederbelebungszauber kennen, beleben befreundete Leichen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TemporaryParties": {
|
||||||
|
"t": "Vorübergehende Bot-Gruppen",
|
||||||
|
"d": "Bots ähnlicher Stufe mit derselben Quest tun sich kurz zusammen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMaxSize": {
|
||||||
|
"t": "Größe vorübergehender Gruppen",
|
||||||
|
"d": "Größte vorübergehende Gruppe."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyRadius": {
|
||||||
|
"t": "Entfernung zur Gruppenbildung",
|
||||||
|
"d": "Wie nah Bots sein müssen, um sich zusammenzutun."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMinMinutes": {
|
||||||
|
"t": "Kürzeste Gruppendauer",
|
||||||
|
"d": "Mindestdauer einer vorübergehenden Gruppe."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMaxMinutes": {
|
||||||
|
"t": "Längste Gruppendauer",
|
||||||
|
"d": "Höchstdauer einer vorübergehenden Gruppe."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMinMs": {
|
||||||
|
"t": "Planerintervall (Min.)",
|
||||||
|
"d": "Kürzeste Zeit zwischen den Planungsdurchläufen eines Bots."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMaxMs": {
|
||||||
|
"t": "Planerintervall (Max.)",
|
||||||
|
"d": "Längste Zeit zwischen den Planungsdurchläufen eines Bots."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMinMs": {
|
||||||
|
"t": "Zielsuchintervall (Min.)",
|
||||||
|
"d": "Kürzeste Zeit zwischen Zielsuchen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMaxMs": {
|
||||||
|
"t": "Zielsuchintervall (Max.)",
|
||||||
|
"d": "Längste Zeit zwischen Zielsuchen."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchTimeoutMs": {
|
||||||
|
"t": "Zeitlimit der Gebietssuche",
|
||||||
|
"d": "Wie lange ein Bot ein leeres Gebiet absucht, bevor er ein anderes versucht."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ApproachTimeoutMs": {
|
||||||
|
"t": "Zeitlimit der Annäherung",
|
||||||
|
"d": "Wie lange ein Bot zu einem beanspruchten Ziel läuft."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TravelTimeoutMs": {
|
||||||
|
"t": "Zeitlimit der Reise",
|
||||||
|
"d": "Wie lange eine ganze Reise in ein Gebiet dauern darf."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TravelPer100Yards": {
|
||||||
|
"t": "Präferenzgewicht: TravelPer100Yards",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.CrowdPerBot": {
|
||||||
|
"t": "Präferenzgewicht: CrowdPerBot",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Overlap": {
|
||||||
|
"t": "Präferenzgewicht: Overlap",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TurnIn": {
|
||||||
|
"t": "Präferenzgewicht: TurnIn",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Accept": {
|
||||||
|
"t": "Präferenzgewicht: Accept",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.AreaOccupancy": {
|
||||||
|
"t": "Präferenzgewicht: AreaOccupancy",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TargetReserved": {
|
||||||
|
"t": "Präferenzgewicht: TargetReserved",
|
||||||
|
"d": "Wie stark Bots diesen Faktor gewichten, wenn sie entscheiden, was sie als Nächstes tun. Nur ändern, wenn du den Planer kennst."
|
||||||
|
},
|
||||||
|
"Rate.XP.Kill": {
|
||||||
|
"t": "Erfahrung durch Kills",
|
||||||
|
"d": "Multiplikator für Erfahrung durch das Töten von Monstern. 1 ist normal."
|
||||||
|
},
|
||||||
|
"Rate.XP.Quest": {
|
||||||
|
"t": "Erfahrung durch Quests",
|
||||||
|
"d": "Multiplikator für Erfahrung aus Quests."
|
||||||
|
},
|
||||||
|
"Rate.XP.Quest.DF": {
|
||||||
|
"t": "Erfahrung durch tägliche Quests / Dungeonsuche",
|
||||||
|
"d": "Multiplikator für Erfahrung aus Quests der Dungeonsuche."
|
||||||
|
},
|
||||||
|
"Rate.XP.Explore": {
|
||||||
|
"t": "Erfahrung durch Erkunden",
|
||||||
|
"d": "Multiplikator für Erfahrung beim Entdecken neuer Gebiete."
|
||||||
|
},
|
||||||
|
"Rate.Drop.Item.Normal": {
|
||||||
|
"t": "Gegenstands-Droprate",
|
||||||
|
"d": "Multiplikator dafür, wie oft Gegenstände normaler Qualität fallen."
|
||||||
|
},
|
||||||
|
"Rate.Drop.Money": {
|
||||||
|
"t": "Gold-Droprate",
|
||||||
|
"d": "Multiplikator für das Gold, das Monster fallen lassen."
|
||||||
|
},
|
||||||
|
"Rate.Honor": {
|
||||||
|
"t": "Ehregewinn",
|
||||||
|
"d": "Multiplikator für verdiente Ehrenpunkte."
|
||||||
|
},
|
||||||
|
"Rate.Reputation.Gain": {
|
||||||
|
"t": "Rufgewinn",
|
||||||
|
"d": "Multiplikator für verdienten Ruf."
|
||||||
|
},
|
||||||
|
"Rate.Rest.InGame": {
|
||||||
|
"t": "Ruhebonus beim Spielen",
|
||||||
|
"d": "Geschwindigkeit, mit der Ruhe-Erfahrung beim Spielen aufgebraucht wird."
|
||||||
|
},
|
||||||
|
"Rate.Creature.Normal.Damage": {
|
||||||
|
"t": "Monsterschaden",
|
||||||
|
"d": "Multiplikator für den Schaden normaler Monster. Verändert den Schwierigkeitsgrad stark."
|
||||||
|
},
|
||||||
|
"Rate.Creature.Normal.HP": {
|
||||||
|
"t": "Monstergesundheit",
|
||||||
|
"d": "Multiplikator für die Gesundheit normaler Monster. Verändert den Schwierigkeitsgrad stark."
|
||||||
|
},
|
||||||
|
"PlayerLimit": {
|
||||||
|
"t": "Maximale Spielerzahl",
|
||||||
|
"d": "Wie viele Spieler gleichzeitig online sein können. 0 bedeutet kein Limit."
|
||||||
|
},
|
||||||
|
"GameType": {
|
||||||
|
"t": "Realmtyp",
|
||||||
|
"d": "Der in der Realmliste angezeigte Realmtyp."
|
||||||
|
},
|
||||||
|
"RealmZone": {
|
||||||
|
"t": "Realmzone",
|
||||||
|
"d": "Die Sprach- bzw. Regionsgruppe des Realms, die Clients angezeigt wird."
|
||||||
|
},
|
||||||
|
"PlayerSaveInterval": {
|
||||||
|
"t": "Autospeicher-Intervall",
|
||||||
|
"d": "Wie oft Spielercharaktere gespeichert werden, solange sie online sind."
|
||||||
|
},
|
||||||
|
"CharactersPerAccount": {
|
||||||
|
"t": "Charaktere pro Konto",
|
||||||
|
"d": "Maximale Zahl an Charakteren, die ein Konto über alle Realms hat."
|
||||||
|
},
|
||||||
|
"CharactersPerRealm": {
|
||||||
|
"t": "Charaktere pro Realm",
|
||||||
|
"d": "Maximale Zahl an Charakteren, die ein Konto auf diesem Realm hat."
|
||||||
|
},
|
||||||
|
"StartPlayerLevel": {
|
||||||
|
"t": "Startstufe",
|
||||||
|
"d": "Stufe, mit der neue Charaktere beginnen."
|
||||||
|
},
|
||||||
|
"StartPlayerMoney": {
|
||||||
|
"t": "Startgold",
|
||||||
|
"d": "Kupfer, mit dem neue Charaktere beginnen (10000 Kupfer = 1 Gold)."
|
||||||
|
},
|
||||||
|
"MaxPlayerLevel": {
|
||||||
|
"t": "Maximale Stufe",
|
||||||
|
"d": "Höchste Stufe, die ein Charakter erreichen kann. Der Spielclient unterstützt nur 80."
|
||||||
|
},
|
||||||
|
"SkipCinematics": {
|
||||||
|
"t": "Intro-Videos überspringen",
|
||||||
|
"d": "Ob neue Charaktere ihr Intro-Video sehen."
|
||||||
|
},
|
||||||
|
"DurabilityLoss.OnDeath": {
|
||||||
|
"t": "Haltbarkeitsverlust beim Tod",
|
||||||
|
"d": "Prozent der Haltbarkeit von Gegenständen, die beim Tod verloren gehen."
|
||||||
|
},
|
||||||
|
"Death.SicknessLevel": {
|
||||||
|
"t": "Wiederbelebungsschwäche bis Stufe",
|
||||||
|
"d": "Charaktere über dieser Stufe erhalten Wiederbelebungsschwäche. -10 schaltet sie aus."
|
||||||
|
},
|
||||||
|
"LeaveGroupOnLogout.Enabled": {
|
||||||
|
"t": "Gruppe beim Abmelden verlassen",
|
||||||
|
"d": "Spieler werden aus ihrer Gruppe entfernt, wenn sie sich abmelden."
|
||||||
|
},
|
||||||
|
"GM.LoginState": {
|
||||||
|
"t": "GM-Modus bei der Anmeldung",
|
||||||
|
"d": "Ob Gamemaster mit eingeschaltetem GM-Modus starten."
|
||||||
|
},
|
||||||
|
"AllowTwoSide.Accounts": {
|
||||||
|
"t": "Beide Fraktionen auf einem Konto",
|
||||||
|
"d": "Ein Konto darf Allianz- und Horde-Charaktere haben."
|
||||||
|
},
|
||||||
|
"AllowTwoSide.Interaction.Chat": {
|
||||||
|
"t": "Fraktionsübergreifender Chat",
|
||||||
|
"d": "Allianz- und Horde-Spieler können miteinander sprechen."
|
||||||
|
},
|
||||||
|
"AutoBroadcast.On": {
|
||||||
|
"t": "Automatische Ankündigungen",
|
||||||
|
"d": "Sendet die in der Datenbank gespeicherten Nachrichten in regelmäßigen Abständen."
|
||||||
|
},
|
||||||
|
"AutoBroadcast.Timer": {
|
||||||
|
"t": "Ankündigungsintervall",
|
||||||
|
"d": "Zeit zwischen automatischen Ankündigungen."
|
||||||
|
},
|
||||||
|
"Warden.Enabled": {
|
||||||
|
"t": "Anti-Cheat (Warden)",
|
||||||
|
"d": "Aktiviert die Anti-Cheat-Prüfung des Clients. Auf einem privaten Server meist unnötig."
|
||||||
|
},
|
||||||
|
"MapUpdateInterval": {
|
||||||
|
"t": "Karten-Aktualisierungsintervall",
|
||||||
|
"d": "Wie oft die Welt Karten aktualisiert. Niedriger ist flüssiger, braucht aber mehr CPU."
|
||||||
|
},
|
||||||
|
"MinWorldUpdateTime": {
|
||||||
|
"t": "Minimale Weltaktualisierungszeit",
|
||||||
|
"d": "Kürzeste Zeit zwischen Weltaktualisierungen. Erhöhe sie, um die CPU-Last zu senken."
|
||||||
|
},
|
||||||
|
"ThreadPool": {
|
||||||
|
"t": "Arbeitsthreads",
|
||||||
|
"d": "Anzahl der Hintergrund-Arbeitsthreads. Mehr hilft bei großen Spielerzahlen."
|
||||||
|
},
|
||||||
|
"Network.Threads": {
|
||||||
|
"t": "Netzwerk-Threads",
|
||||||
|
"d": "Threads, die Spielerverbindungen verarbeiten. Für kleine Server genügt einer."
|
||||||
|
},
|
||||||
|
"Ra.Enable": {
|
||||||
|
"t": "Remote-Konsole",
|
||||||
|
"d": "Erlaubt dem Manager und Skripten, Befehle an den Server zu senden. Sie lauscht nur auf diesem Computer; lass es dabei."
|
||||||
|
},
|
||||||
|
"Ra.IP": {
|
||||||
|
"t": "Adresse der Remote-Konsole",
|
||||||
|
"d": "Adresse, auf der die Remote-Konsole lauscht. Behalte 127.0.0.1, damit sie nicht aus dem Internet erreichbar ist."
|
||||||
|
},
|
||||||
|
"Updates.EnableDatabases": {
|
||||||
|
"t": "Automatische Datenbank-Updates",
|
||||||
|
"d": "Erlaubt dem Server, seine Datenbanken beim Start selbst zu ändern. Lass es auf 0: Der Manager wendet Datenbank-Updates sicher an und verfolgt sie."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"GameType.0": "Normal",
|
||||||
|
"GameType.1": "Spieler gegen Spieler",
|
||||||
|
"GameType.6": "Rollenspiel",
|
||||||
|
"GameType.8": "Rollenspiel + PvP",
|
||||||
|
"SkipCinematics.0": "Alle zeigen",
|
||||||
|
"SkipCinematics.1": "Für alle außer dem ersten Charakter überspringen",
|
||||||
|
"SkipCinematics.2": "Alle überspringen",
|
||||||
|
"GM.LoginState.0": "Aus",
|
||||||
|
"GM.LoginState.1": "An",
|
||||||
|
"GM.LoginState.2": "Wie beim letzten Mal"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"balanced": {
|
||||||
|
"t": "Ausgewogen",
|
||||||
|
"d": "Die empfohlene Alltagseinstellung: Quests, Dungeon- und Schlachtfeld-Auffüllung an, ruhige Protokolle."
|
||||||
|
},
|
||||||
|
"solo-friendly": {
|
||||||
|
"t": "Solo-freundlich",
|
||||||
|
"d": "Bots, die dir helfen und deine Gruppen auffüllen, mit einer kleinen, ruhigen Population."
|
||||||
|
},
|
||||||
|
"living-world": {
|
||||||
|
"t": "Lebendige Welt",
|
||||||
|
"d": "Eine belebtere Welt: mehr Bots, Pausen, Sammel-Abstecher und vorübergehende Gruppen."
|
||||||
|
},
|
||||||
|
"performance": {
|
||||||
|
"t": "Leistung",
|
||||||
|
"d": "Weniger Bots und weniger Bot-Denken, für schwächere Computer."
|
||||||
|
},
|
||||||
|
"vanilla": {
|
||||||
|
"t": "Standardraten",
|
||||||
|
"d": "Alles in normaler Geschwindigkeit (×1)."
|
||||||
|
},
|
||||||
|
"relaxed": {
|
||||||
|
"t": "Entspannt",
|
||||||
|
"d": "Schnelleres Leveln und mehr Beute für Gelegenheitsspieler (×2 / ×3)."
|
||||||
|
},
|
||||||
|
"fast": {
|
||||||
|
"t": "Schnell",
|
||||||
|
"d": "Schneller Fortschritt für Tests oder kurze Sitzungen (×5)."
|
||||||
|
},
|
||||||
|
"defaults": {
|
||||||
|
"t": "Empfohlene Standardwerte",
|
||||||
|
"d": "Alle Einstellungen kehren zu ihren Standardwerten zurück."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,513 @@
|
|||||||
|
{
|
||||||
|
"categories": {
|
||||||
|
"bots.general": "General",
|
||||||
|
"bots.population": "Población",
|
||||||
|
"bots.login": "Inicio de sesión",
|
||||||
|
"bots.roles": "Roles",
|
||||||
|
"bots.openworld": "Mundo abierto",
|
||||||
|
"bots.quests": "Misiones",
|
||||||
|
"bots.combat": "Combate",
|
||||||
|
"bots.dungeon": "Buscador de mazmorras",
|
||||||
|
"bots.battlegrounds": "Campos de batalla",
|
||||||
|
"bots.social": "Comportamiento social",
|
||||||
|
"bots.advanced": "Avanzado",
|
||||||
|
"server.gameplay": "Jugabilidad",
|
||||||
|
"server.rates": "Tasas",
|
||||||
|
"server.characters": "Personajes",
|
||||||
|
"server.world": "Mundo",
|
||||||
|
"server.network": "Red",
|
||||||
|
"server.accounts": "Cuentas",
|
||||||
|
"server.logging": "Registros",
|
||||||
|
"server.performance": "Rendimiento",
|
||||||
|
"server.advanced": "Avanzado"
|
||||||
|
},
|
||||||
|
"units": {
|
||||||
|
"ms": "ms",
|
||||||
|
"%": "%",
|
||||||
|
"yards": "yardas",
|
||||||
|
"levels": "niveles",
|
||||||
|
"x": "×",
|
||||||
|
"min": "min",
|
||||||
|
"copper": "cobre"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"CoaBots.RandomSpawn.DefaultCount": {
|
||||||
|
"t": "Bots creados por comando",
|
||||||
|
"d": "Cuántos bots crea el comando de creación cuando no indicas un número."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.MaxCount": {
|
||||||
|
"t": "Mayor creación individual",
|
||||||
|
"d": "Límite de seguridad para un comando de creación. Los lotes muy grandes pueden congelar el servidor un momento, así que súbelo solo cuando nadie más esté jugando."
|
||||||
|
},
|
||||||
|
"CoaBots.LeveledSpawn.Brackets": {
|
||||||
|
"t": "Reparto de niveles de los bots nuevos",
|
||||||
|
"d": "Cómo se reparten por niveles los nuevos bots que suben de nivel, como rangos con pesos (1-20:40 significa 40 partes de bots entre los niveles 1 y 20)."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.AutoLogin": {
|
||||||
|
"t": "Conectar enseguida a los bots nuevos",
|
||||||
|
"d": "Los bots recién creados inician sesión de inmediato en lugar de esperar en la base de datos."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.AccountPrefix": {
|
||||||
|
"t": "Prefijo de los nombres de cuenta de bots",
|
||||||
|
"d": "Los bots viven en cuentas cuyo nombre empieza por este prefijo. Cambiarlo hace que los bots existentes dejen de conectarse automáticamente."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.BatchSize": {
|
||||||
|
"t": "Bots creados por paso",
|
||||||
|
"d": "La creación se reparte en el tiempo para que el servidor vaya fluido. Valores altos son más rápidos, pero pueden causar tirones."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.BatchIntervalMs": {
|
||||||
|
"t": "Pausa entre pasos de creación",
|
||||||
|
"d": "Tiempo entre los pasos de creación. Valores bajos son más rápidos, pero pueden causar tirones."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLoginOnStartup": {
|
||||||
|
"t": "Conexión automática de bots",
|
||||||
|
"d": "Los bots existentes inician sesión solos cada vez que arranca el servidor."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.MaxCount": {
|
||||||
|
"t": "Máximo de bots conectados",
|
||||||
|
"d": "El mayor número de bots que inician sesión automáticamente al arrancar."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.BatchSize": {
|
||||||
|
"t": "Bots que se conectan por paso",
|
||||||
|
"d": "Las conexiones se reparten en el tiempo. Valores altos conectan bots más rápido, pero cargan más el servidor."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.BatchIntervalMs": {
|
||||||
|
"t": "Pausa entre pasos de conexión",
|
||||||
|
"d": "Tiempo entre los pasos de conexión."
|
||||||
|
},
|
||||||
|
"CoaBots.SpecBalance.TankTargetPct": {
|
||||||
|
"t": "Proporción objetivo de tanques",
|
||||||
|
"d": "Proporción de bots que deben ser tanques."
|
||||||
|
},
|
||||||
|
"CoaBots.SpecBalance.HealerTargetPct": {
|
||||||
|
"t": "Proporción objetivo de sanadores",
|
||||||
|
"d": "Proporción de bots que deben ser sanadores."
|
||||||
|
},
|
||||||
|
"CoaBots.TalentBuildsPath": {
|
||||||
|
"t": "Archivo de datos de talentos",
|
||||||
|
"d": "Dónde se guardan las builds de talentos de la comunidad. Déjalo vacío para usar la búsqueda integrada."
|
||||||
|
},
|
||||||
|
"CoaBots.World.Enable": {
|
||||||
|
"t": "Los bots vagan por el mundo",
|
||||||
|
"d": "Los bots inactivos hacen recados: visitan servicios de la ciudad, viajan a zonas de recolección o de farmeo o deambulan un poco."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Enable": {
|
||||||
|
"t": "IA de misiones",
|
||||||
|
"d": "Los bots aceptan y completan misiones por su cuenta. Si se apaga, los bots solo recolectan, pescan, farmean y deambulan."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ServiceRadius": {
|
||||||
|
"t": "Radio de búsqueda de servicios de la ciudad",
|
||||||
|
"d": "Hasta dónde busca un bot vendedores y buzones."
|
||||||
|
},
|
||||||
|
"CoaBots.World.AreaRadius": {
|
||||||
|
"t": "Radio de la zona de recados",
|
||||||
|
"d": "Hasta dónde busca un bot zonas de recolección o de farmeo."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ThinkIntervalMs": {
|
||||||
|
"t": "Intervalo de revisión de recados",
|
||||||
|
"d": "Con qué frecuencia cada bot reconsidera su recado."
|
||||||
|
},
|
||||||
|
"CoaBots.World.IdleBeforeErrandMs": {
|
||||||
|
"t": "Inactividad antes de un recado",
|
||||||
|
"d": "Cuánto tiempo debe un bot no encontrar nada que hacer antes de empezar un recado."
|
||||||
|
},
|
||||||
|
"CoaBots.World.VerboseLog": {
|
||||||
|
"t": "Registro detallado de recados",
|
||||||
|
"d": "Escribe cada paso de los recados en el registro. Útil para depurar, ruidoso con muchos bots."
|
||||||
|
},
|
||||||
|
"CoaBots.Combat.VerboseLog": {
|
||||||
|
"t": "Registro detallado de combate",
|
||||||
|
"d": "Escribe las decisiones de combate en el registro. Muy ruidoso; actívalo solo mientras buscas un problema concreto."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMinMs": {
|
||||||
|
"t": "Actividad más corta",
|
||||||
|
"d": "El menor tiempo que un bot se mantiene en un mismo tipo de actividad."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMaxMs": {
|
||||||
|
"t": "Actividad más larga",
|
||||||
|
"d": "El mayor tiempo que un bot se mantiene en un mismo tipo de actividad."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.SearchRadius": {
|
||||||
|
"t": "Radio de búsqueda para farmear",
|
||||||
|
"d": "Hasta dónde busca un bot monstruos para farmear."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.MaxLevelAbove": {
|
||||||
|
"t": "Nivel máximo de monstruo para farmear",
|
||||||
|
"d": "Cuántos niveles por encima del suyo combate un bot al farmear."
|
||||||
|
},
|
||||||
|
"CoaBots.Healer.CriticalHealPct": {
|
||||||
|
"t": "Umbral de curación de emergencia",
|
||||||
|
"d": "Los sanadores pasan a sus curas más fuertes cuando la salud de un aliado cae por debajo de este valor."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchRadius": {
|
||||||
|
"t": "Radio de búsqueda de objetivos",
|
||||||
|
"d": "Hasta dónde examina un bot en busca de objetivos de misión dentro de una zona de objetivo."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.EngageRange": {
|
||||||
|
"t": "Distancia de enfrentamiento",
|
||||||
|
"d": "Distancia a la que un bot empieza a combatir a un monstruo de misión."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMin": {
|
||||||
|
"t": "Montar a partir de (mín.)",
|
||||||
|
"d": "Cada bot monta en viajes más largos que una distancia personal elegida entre este valor y el máximo."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMax": {
|
||||||
|
"t": "Montar a partir de (máx.)",
|
||||||
|
"d": "Extremo superior de la distancia personal para montar."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TaxiMinDistance": {
|
||||||
|
"t": "Usar rutas de vuelo a partir de",
|
||||||
|
"d": "Los viajes más largos usan una ruta de vuelo si el bot conoce alguna."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SessionBreaks": {
|
||||||
|
"t": "Hacer descansos",
|
||||||
|
"d": "Los bots alternan las misiones con unos minutos de vida en la ciudad, como haría un jugador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GatherDetours": {
|
||||||
|
"t": "Recolectar hierbas y minerales cercanos",
|
||||||
|
"d": "Los recolectores se desvían de su camino por un nodo justo al lado."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxActiveQuests": {
|
||||||
|
"t": "Máximo de misiones activas",
|
||||||
|
"d": "Cuántas misiones lleva un bot a la vez."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.AcceptEliteQuests": {
|
||||||
|
"t": "Aceptar misiones de élite",
|
||||||
|
"d": "Los bots en solitario aceptan misiones de élite. Desactivado por defecto porque normalmente no pueden completarlas solos."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestLevelBelow": {
|
||||||
|
"t": "Misiones por debajo de su nivel",
|
||||||
|
"d": "Cuántos niveles por debajo del suyo sigue aceptando misiones un bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestLevelAbove": {
|
||||||
|
"t": "Misiones por encima de su nivel",
|
||||||
|
"d": "Cuántos niveles por encima del suyo sigue aceptando misiones un bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxMobLevelAbove": {
|
||||||
|
"t": "Nivel máximo del monstruo de misión",
|
||||||
|
"d": "Cuánto por encima de su nivel puede estar un monstruo de misión."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxObjectiveDistance": {
|
||||||
|
"t": "Objetivo de misión más lejano",
|
||||||
|
"d": "No se aceptan las misiones cuyos objetivos estén más lejos."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GiverSearchRadius": {
|
||||||
|
"t": "Radio de búsqueda de dadores de misiones",
|
||||||
|
"d": "Hasta dónde busca un bot a quienes dan misiones."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxBadAreasPerObjective": {
|
||||||
|
"t": "Zonas probadas por objetivo",
|
||||||
|
"d": "Cuántas zonas descarta un bot antes de dejar la misión aparcada."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMs": {
|
||||||
|
"t": "Tiempo aparcada (corto)",
|
||||||
|
"d": "Cuánto tiempo se aparca una misión después de que el bot renuncie a ella."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMaxMs": {
|
||||||
|
"t": "Tiempo aparcada (largo)",
|
||||||
|
"d": "El máximo tiempo que una misión puede quedar aparcada tras fallos repetidos."
|
||||||
|
},
|
||||||
|
"CoaBots.LfgFill.Enable": {
|
||||||
|
"t": "Relleno con bots del Buscador de mazmorras",
|
||||||
|
"d": "Cuando te pones en cola solo para una mazmorra, los bots ocupan los roles de tanque, sanador y daño que falten."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoQueueDungeon.Enable": {
|
||||||
|
"t": "Los bots se ponen en cola para mazmorras solos",
|
||||||
|
"d": "Experimental: los bots tanque inactivos se ponen en cola para una mazmorra por su cuenta y el relleno anterior completa el grupo."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.Enable": {
|
||||||
|
"t": "Relleno con bots de campos de batalla",
|
||||||
|
"d": "Cuando alguien se pone en cola para un campo de batalla, ambos equipos se completan con bots para que la partida empiece enseguida."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.TargetPlayersPerTeam": {
|
||||||
|
"t": "Tamaño de equipo en campos de batalla",
|
||||||
|
"d": "Bots por equipo hasta los que rellenar. 0 significa un equipo completo para ese campo de batalla."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpOthers": {
|
||||||
|
"t": "Los bots ayudan a jugadores cercanos",
|
||||||
|
"d": "Un bot que pasa por allí se une a un combate que un jugador amigo está perdiendo, sin quedarse con su botín ni su crédito."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpRadius": {
|
||||||
|
"t": "Distancia de ayuda",
|
||||||
|
"d": "Lo cerca que debe estar un bot para meterse en un combate."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpHealthPct": {
|
||||||
|
"t": "Ayudar por debajo de salud",
|
||||||
|
"d": "Los bots ayudan cuando la salud del jugador que combate está por debajo de este valor."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ResurrectOthers": {
|
||||||
|
"t": "Los bots resucitan a jugadores caídos",
|
||||||
|
"d": "Los bots que conocen un hechizo de resurrección reviven cadáveres amigos."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TemporaryParties": {
|
||||||
|
"t": "Grupos temporales de bots",
|
||||||
|
"d": "Bots de nivel parecido con la misma misión se unen brevemente."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMaxSize": {
|
||||||
|
"t": "Tamaño del grupo temporal",
|
||||||
|
"d": "El mayor tamaño de un grupo temporal."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyRadius": {
|
||||||
|
"t": "Distancia para formar grupo",
|
||||||
|
"d": "Lo cerca que deben estar los bots para unirse."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMinMinutes": {
|
||||||
|
"t": "Duración mínima del grupo",
|
||||||
|
"d": "Duración mínima de un grupo temporal."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMaxMinutes": {
|
||||||
|
"t": "Duración máxima del grupo",
|
||||||
|
"d": "Duración máxima de un grupo temporal."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMinMs": {
|
||||||
|
"t": "Intervalo del planificador (mín.)",
|
||||||
|
"d": "El menor tiempo entre las pasadas de planificación de un bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMaxMs": {
|
||||||
|
"t": "Intervalo del planificador (máx.)",
|
||||||
|
"d": "El mayor tiempo entre las pasadas de planificación de un bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMinMs": {
|
||||||
|
"t": "Intervalo de búsqueda de objetivos (mín.)",
|
||||||
|
"d": "El menor tiempo entre búsquedas de objetivos."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMaxMs": {
|
||||||
|
"t": "Intervalo de búsqueda de objetivos (máx.)",
|
||||||
|
"d": "El mayor tiempo entre búsquedas de objetivos."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchTimeoutMs": {
|
||||||
|
"t": "Límite de tiempo de búsqueda en una zona",
|
||||||
|
"d": "Cuánto tiempo rastrea un bot una zona vacía antes de probar otra."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ApproachTimeoutMs": {
|
||||||
|
"t": "Límite de tiempo de aproximación",
|
||||||
|
"d": "Cuánto tiempo camina un bot hacia un objetivo reservado."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TravelTimeoutMs": {
|
||||||
|
"t": "Límite de tiempo de viaje",
|
||||||
|
"d": "Cuánto puede durar todo un viaje a una zona."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TravelPer100Yards": {
|
||||||
|
"t": "Peso de preferencia: TravelPer100Yards",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.CrowdPerBot": {
|
||||||
|
"t": "Peso de preferencia: CrowdPerBot",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Overlap": {
|
||||||
|
"t": "Peso de preferencia: Overlap",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TurnIn": {
|
||||||
|
"t": "Peso de preferencia: TurnIn",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Accept": {
|
||||||
|
"t": "Peso de preferencia: Accept",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.AreaOccupancy": {
|
||||||
|
"t": "Peso de preferencia: AreaOccupancy",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TargetReserved": {
|
||||||
|
"t": "Peso de preferencia: TargetReserved",
|
||||||
|
"d": "Cuánto peso dan los bots a este factor al elegir qué hacer a continuación. Cámbialo solo si conoces el planificador."
|
||||||
|
},
|
||||||
|
"Rate.XP.Kill": {
|
||||||
|
"t": "Experiencia por muertes",
|
||||||
|
"d": "Multiplicador de la experiencia ganada al matar monstruos. 1 es lo normal."
|
||||||
|
},
|
||||||
|
"Rate.XP.Quest": {
|
||||||
|
"t": "Experiencia por misiones",
|
||||||
|
"d": "Multiplicador de la experiencia ganada con las misiones."
|
||||||
|
},
|
||||||
|
"Rate.XP.Quest.DF": {
|
||||||
|
"t": "Experiencia por misiones diarias / Buscador de mazmorras",
|
||||||
|
"d": "Multiplicador de la experiencia de las misiones del Buscador de mazmorras."
|
||||||
|
},
|
||||||
|
"Rate.XP.Explore": {
|
||||||
|
"t": "Experiencia por explorar",
|
||||||
|
"d": "Multiplicador de la experiencia por descubrir nuevas zonas."
|
||||||
|
},
|
||||||
|
"Rate.Drop.Item.Normal": {
|
||||||
|
"t": "Tasa de botín de objetos",
|
||||||
|
"d": "Multiplicador de la frecuencia con que caen objetos de calidad normal."
|
||||||
|
},
|
||||||
|
"Rate.Drop.Money": {
|
||||||
|
"t": "Tasa de botín de oro",
|
||||||
|
"d": "Multiplicador del oro que sueltan los monstruos."
|
||||||
|
},
|
||||||
|
"Rate.Honor": {
|
||||||
|
"t": "Ganancia de honor",
|
||||||
|
"d": "Multiplicador de los puntos de honor obtenidos."
|
||||||
|
},
|
||||||
|
"Rate.Reputation.Gain": {
|
||||||
|
"t": "Ganancia de reputación",
|
||||||
|
"d": "Multiplicador de la reputación obtenida."
|
||||||
|
},
|
||||||
|
"Rate.Rest.InGame": {
|
||||||
|
"t": "Bonificación de descanso al jugar",
|
||||||
|
"d": "Velocidad a la que se consume la experiencia de descanso mientras juegas."
|
||||||
|
},
|
||||||
|
"Rate.Creature.Normal.Damage": {
|
||||||
|
"t": "Daño de los monstruos",
|
||||||
|
"d": "Multiplicador del daño de los monstruos normales. Cambia mucho la dificultad."
|
||||||
|
},
|
||||||
|
"Rate.Creature.Normal.HP": {
|
||||||
|
"t": "Salud de los monstruos",
|
||||||
|
"d": "Multiplicador de la salud de los monstruos normales. Cambia mucho la dificultad."
|
||||||
|
},
|
||||||
|
"PlayerLimit": {
|
||||||
|
"t": "Máximo de jugadores",
|
||||||
|
"d": "Cuántos jugadores pueden estar conectados a la vez. 0 significa sin límite."
|
||||||
|
},
|
||||||
|
"GameType": {
|
||||||
|
"t": "Tipo de reino",
|
||||||
|
"d": "El tipo de reino que se muestra en la lista de reinos."
|
||||||
|
},
|
||||||
|
"RealmZone": {
|
||||||
|
"t": "Zona del reino",
|
||||||
|
"d": "El grupo de idioma / región del reino que se muestra a los clientes."
|
||||||
|
},
|
||||||
|
"PlayerSaveInterval": {
|
||||||
|
"t": "Intervalo de autoguardado",
|
||||||
|
"d": "Con qué frecuencia se guardan los personajes de los jugadores mientras están conectados."
|
||||||
|
},
|
||||||
|
"CharactersPerAccount": {
|
||||||
|
"t": "Personajes por cuenta",
|
||||||
|
"d": "Máximo de personajes que puede tener una cuenta entre todos los reinos."
|
||||||
|
},
|
||||||
|
"CharactersPerRealm": {
|
||||||
|
"t": "Personajes por reino",
|
||||||
|
"d": "Máximo de personajes que puede tener una cuenta en este reino."
|
||||||
|
},
|
||||||
|
"StartPlayerLevel": {
|
||||||
|
"t": "Nivel inicial",
|
||||||
|
"d": "Nivel con el que empiezan los personajes nuevos."
|
||||||
|
},
|
||||||
|
"StartPlayerMoney": {
|
||||||
|
"t": "Oro inicial",
|
||||||
|
"d": "Cobre con el que empiezan los personajes nuevos (10000 de cobre = 1 de oro)."
|
||||||
|
},
|
||||||
|
"MaxPlayerLevel": {
|
||||||
|
"t": "Nivel máximo",
|
||||||
|
"d": "El nivel más alto que puede alcanzar un personaje. El cliente del juego solo admite 80."
|
||||||
|
},
|
||||||
|
"SkipCinematics": {
|
||||||
|
"t": "Omitir cinemáticas de introducción",
|
||||||
|
"d": "Si los personajes nuevos ven su película de introducción."
|
||||||
|
},
|
||||||
|
"DurabilityLoss.OnDeath": {
|
||||||
|
"t": "Durabilidad perdida al morir",
|
||||||
|
"d": "Porcentaje de durabilidad de los objetos que se pierde al morir."
|
||||||
|
},
|
||||||
|
"Death.SicknessLevel": {
|
||||||
|
"t": "Enfermedad de resurrección hasta el nivel",
|
||||||
|
"d": "Los personajes por encima de este nivel sufren la enfermedad de resurrección. -10 la desactiva."
|
||||||
|
},
|
||||||
|
"LeaveGroupOnLogout.Enabled": {
|
||||||
|
"t": "Dejar el grupo al desconectarse",
|
||||||
|
"d": "Los jugadores salen de su grupo cuando cierran sesión."
|
||||||
|
},
|
||||||
|
"GM.LoginState": {
|
||||||
|
"t": "Modo GM al iniciar sesión",
|
||||||
|
"d": "Si los maestros del juego empiezan con el modo GM activado."
|
||||||
|
},
|
||||||
|
"AllowTwoSide.Accounts": {
|
||||||
|
"t": "Ambas facciones en una cuenta",
|
||||||
|
"d": "Una cuenta puede tener personajes de la Alianza y de la Horda."
|
||||||
|
},
|
||||||
|
"AllowTwoSide.Interaction.Chat": {
|
||||||
|
"t": "Chat entre facciones",
|
||||||
|
"d": "Los jugadores de la Alianza y de la Horda pueden hablar entre sí."
|
||||||
|
},
|
||||||
|
"AutoBroadcast.On": {
|
||||||
|
"t": "Anuncios automáticos",
|
||||||
|
"d": "Difunde a intervalos regulares los mensajes guardados en la base de datos."
|
||||||
|
},
|
||||||
|
"AutoBroadcast.Timer": {
|
||||||
|
"t": "Intervalo de anuncios",
|
||||||
|
"d": "Tiempo entre los anuncios automáticos."
|
||||||
|
},
|
||||||
|
"Warden.Enabled": {
|
||||||
|
"t": "Antitrampas (Warden)",
|
||||||
|
"d": "Activa la comprobación antitrampas del cliente. Normalmente innecesaria en un servidor privado."
|
||||||
|
},
|
||||||
|
"MapUpdateInterval": {
|
||||||
|
"t": "Intervalo de actualización de mapas",
|
||||||
|
"d": "Con qué frecuencia el mundo actualiza los mapas. Más bajo es más fluido, pero usa más CPU."
|
||||||
|
},
|
||||||
|
"MinWorldUpdateTime": {
|
||||||
|
"t": "Tiempo mínimo de actualización del mundo",
|
||||||
|
"d": "El menor tiempo entre actualizaciones del mundo. Súbelo para reducir el uso de CPU."
|
||||||
|
},
|
||||||
|
"ThreadPool": {
|
||||||
|
"t": "Hilos de trabajo",
|
||||||
|
"d": "Número de hilos de trabajo en segundo plano. Más ayuda con muchos jugadores."
|
||||||
|
},
|
||||||
|
"Network.Threads": {
|
||||||
|
"t": "Hilos de red",
|
||||||
|
"d": "Hilos que gestionan las conexiones de los jugadores. Uno basta para servidores pequeños."
|
||||||
|
},
|
||||||
|
"Ra.Enable": {
|
||||||
|
"t": "Consola remota",
|
||||||
|
"d": "Permite que el Manager y los scripts envíen comandos al servidor. Solo escucha en este equipo; déjalo así."
|
||||||
|
},
|
||||||
|
"Ra.IP": {
|
||||||
|
"t": "Dirección de la consola remota",
|
||||||
|
"d": "Dirección en la que escucha la consola remota. Mantén 127.0.0.1 para que no sea accesible desde internet."
|
||||||
|
},
|
||||||
|
"Updates.EnableDatabases": {
|
||||||
|
"t": "Actualizaciones automáticas de bases de datos",
|
||||||
|
"d": "Permite que el servidor cambie él mismo sus bases de datos al arrancar. Déjalo en 0: el Manager aplica y registra las actualizaciones de bases de datos de forma segura."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"GameType.0": "Normal",
|
||||||
|
"GameType.1": "Jugador contra jugador",
|
||||||
|
"GameType.6": "Juego de rol",
|
||||||
|
"GameType.8": "Juego de rol + JcJ",
|
||||||
|
"SkipCinematics.0": "Mostrar todas",
|
||||||
|
"SkipCinematics.1": "Omitir salvo para el primer personaje",
|
||||||
|
"SkipCinematics.2": "Omitir todas",
|
||||||
|
"GM.LoginState.0": "Apagado",
|
||||||
|
"GM.LoginState.1": "Encendido",
|
||||||
|
"GM.LoginState.2": "Igual que la última vez"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"balanced": {
|
||||||
|
"t": "Equilibrado",
|
||||||
|
"d": "La configuración recomendada para el día a día: misiones, relleno de mazmorras y de campos de batalla activados, registros discretos."
|
||||||
|
},
|
||||||
|
"solo-friendly": {
|
||||||
|
"t": "Apto para jugar solo",
|
||||||
|
"d": "Bots que te ayudan y completan tus grupos, con una población pequeña y tranquila."
|
||||||
|
},
|
||||||
|
"living-world": {
|
||||||
|
"t": "Mundo vivo",
|
||||||
|
"d": "Un mundo más animado: más bots, descansos, desvíos para recolectar y grupos temporales."
|
||||||
|
},
|
||||||
|
"performance": {
|
||||||
|
"t": "Rendimiento",
|
||||||
|
"d": "Menos bots y menos cálculo de los bots, para equipos más modestos."
|
||||||
|
},
|
||||||
|
"vanilla": {
|
||||||
|
"t": "Tasas estándar",
|
||||||
|
"d": "Todo a velocidad normal (×1)."
|
||||||
|
},
|
||||||
|
"relaxed": {
|
||||||
|
"t": "Relajado",
|
||||||
|
"d": "Subida de nivel más rápida y más botín para jugar sin prisa (×2 / ×3)."
|
||||||
|
},
|
||||||
|
"fast": {
|
||||||
|
"t": "Rápido",
|
||||||
|
"d": "Progreso rápido para pruebas o sesiones cortas (×5)."
|
||||||
|
},
|
||||||
|
"defaults": {
|
||||||
|
"t": "Valores recomendados",
|
||||||
|
"d": "Todos los ajustes vuelven a su valor predeterminado."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,513 @@
|
|||||||
|
{
|
||||||
|
"categories": {
|
||||||
|
"bots.general": "Général",
|
||||||
|
"bots.population": "Population",
|
||||||
|
"bots.login": "Connexion",
|
||||||
|
"bots.roles": "Rôles",
|
||||||
|
"bots.openworld": "Monde ouvert",
|
||||||
|
"bots.quests": "Quêtes",
|
||||||
|
"bots.combat": "Combat",
|
||||||
|
"bots.dungeon": "Recherche de donjon",
|
||||||
|
"bots.battlegrounds": "Champs de bataille",
|
||||||
|
"bots.social": "Comportement social",
|
||||||
|
"bots.advanced": "Avancé",
|
||||||
|
"server.gameplay": "Jeu",
|
||||||
|
"server.rates": "Taux",
|
||||||
|
"server.characters": "Personnages",
|
||||||
|
"server.world": "Monde",
|
||||||
|
"server.network": "Réseau",
|
||||||
|
"server.accounts": "Comptes",
|
||||||
|
"server.logging": "Journaux",
|
||||||
|
"server.performance": "Performances",
|
||||||
|
"server.advanced": "Avancé"
|
||||||
|
},
|
||||||
|
"units": {
|
||||||
|
"ms": "ms",
|
||||||
|
"%": "%",
|
||||||
|
"yards": "yards",
|
||||||
|
"levels": "niveaux",
|
||||||
|
"x": "×",
|
||||||
|
"min": "min",
|
||||||
|
"copper": "cuivre"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"CoaBots.RandomSpawn.DefaultCount": {
|
||||||
|
"t": "Bots créés par commande",
|
||||||
|
"d": "Nombre de bots que la commande de création crée quand vous n’indiquez pas de nombre."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.MaxCount": {
|
||||||
|
"t": "Plus grande création en une fois",
|
||||||
|
"d": "Limite de sécurité pour une commande de création. De très gros lots peuvent figer brièvement le serveur ; n’augmentez donc cette valeur que si personne d’autre ne joue."
|
||||||
|
},
|
||||||
|
"CoaBots.LeveledSpawn.Brackets": {
|
||||||
|
"t": "Répartition des niveaux des nouveaux bots",
|
||||||
|
"d": "Comment les nouveaux bots à faire progresser sont répartis par niveau, sous forme de plages pondérées (1-20:40 signifie 40 parts de bots entre les niveaux 1 et 20)."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.AutoLogin": {
|
||||||
|
"t": "Connecter tout de suite les nouveaux bots",
|
||||||
|
"d": "Les bots tout juste créés se connectent immédiatement au lieu d’attendre dans la base de données."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.AccountPrefix": {
|
||||||
|
"t": "Préfixe des noms de comptes de bots",
|
||||||
|
"d": "Les bots vivent sur des comptes dont le nom commence par ce préfixe. Le modifier empêche les bots existants de se connecter automatiquement."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.BatchSize": {
|
||||||
|
"t": "Bots créés par étape",
|
||||||
|
"d": "La création est étalée dans le temps pour garder le serveur fluide. Des valeurs plus élevées sont plus rapides mais peuvent causer des saccades."
|
||||||
|
},
|
||||||
|
"CoaBots.RandomSpawn.BatchIntervalMs": {
|
||||||
|
"t": "Pause entre les étapes de création",
|
||||||
|
"d": "Temps entre les étapes de création. Des valeurs plus basses sont plus rapides mais peuvent causer des saccades."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLoginOnStartup": {
|
||||||
|
"t": "Connexion automatique des bots",
|
||||||
|
"d": "Les bots existants se connectent eux-mêmes à chaque démarrage du serveur."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.MaxCount": {
|
||||||
|
"t": "Maximum de bots en ligne",
|
||||||
|
"d": "Le plus grand nombre de bots qui se connectent automatiquement au démarrage."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.BatchSize": {
|
||||||
|
"t": "Bots connectés par étape",
|
||||||
|
"d": "Les connexions sont étalées dans le temps. Des valeurs plus élevées mettent les bots en ligne plus vite mais chargent davantage le serveur."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoLogin.BatchIntervalMs": {
|
||||||
|
"t": "Pause entre les étapes de connexion",
|
||||||
|
"d": "Temps entre les étapes de connexion."
|
||||||
|
},
|
||||||
|
"CoaBots.SpecBalance.TankTargetPct": {
|
||||||
|
"t": "Part visée de tanks",
|
||||||
|
"d": "Part des bots qui doivent être des tanks."
|
||||||
|
},
|
||||||
|
"CoaBots.SpecBalance.HealerTargetPct": {
|
||||||
|
"t": "Part visée de soigneurs",
|
||||||
|
"d": "Part des bots qui doivent être des soigneurs."
|
||||||
|
},
|
||||||
|
"CoaBots.TalentBuildsPath": {
|
||||||
|
"t": "Fichier de données de talents",
|
||||||
|
"d": "Emplacement des builds de talents de la communauté. Laissez vide pour utiliser la recherche intégrée."
|
||||||
|
},
|
||||||
|
"CoaBots.World.Enable": {
|
||||||
|
"t": "Les bots se promènent dans le monde",
|
||||||
|
"d": "Les bots inactifs font des courses : ils visitent les services de la ville, vont vers des zones de récolte ou de farm, ou se promènent un peu."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Enable": {
|
||||||
|
"t": "IA de quêtes",
|
||||||
|
"d": "Les bots prennent et accomplissent des quêtes seuls. Désactivée, les bots ne font que récolter, pêcher, farmer et se promener."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ServiceRadius": {
|
||||||
|
"t": "Rayon de recherche des services de la ville",
|
||||||
|
"d": "Jusqu’où un bot cherche des marchands et des boîtes aux lettres."
|
||||||
|
},
|
||||||
|
"CoaBots.World.AreaRadius": {
|
||||||
|
"t": "Rayon de la zone de courses",
|
||||||
|
"d": "Jusqu’où un bot cherche des zones de récolte ou de farm."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ThinkIntervalMs": {
|
||||||
|
"t": "Intervalle de vérification des courses",
|
||||||
|
"d": "Fréquence à laquelle chaque bot reconsidère sa course."
|
||||||
|
},
|
||||||
|
"CoaBots.World.IdleBeforeErrandMs": {
|
||||||
|
"t": "Inactivité avant une course",
|
||||||
|
"d": "Durée pendant laquelle un bot ne doit rien trouver à faire avant de commencer une course."
|
||||||
|
},
|
||||||
|
"CoaBots.World.VerboseLog": {
|
||||||
|
"t": "Journal détaillé des courses",
|
||||||
|
"d": "Écrit chaque étape des courses dans le journal. Utile pour le débogage, bruyant avec beaucoup de bots."
|
||||||
|
},
|
||||||
|
"CoaBots.Combat.VerboseLog": {
|
||||||
|
"t": "Journal détaillé des combats",
|
||||||
|
"d": "Écrit les décisions de combat dans le journal. Très bruyant ; à activer seulement pour traquer un problème précis."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMinMs": {
|
||||||
|
"t": "Activité la plus courte",
|
||||||
|
"d": "La durée la plus courte pendant laquelle un bot reste sur un même type d’activité."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMaxMs": {
|
||||||
|
"t": "Activité la plus longue",
|
||||||
|
"d": "La durée la plus longue pendant laquelle un bot reste sur un même type d’activité."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.SearchRadius": {
|
||||||
|
"t": "Rayon de recherche pour le farm",
|
||||||
|
"d": "Jusqu’où un bot cherche des monstres à farmer."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.MaxLevelAbove": {
|
||||||
|
"t": "Niveau maximal des monstres à farmer",
|
||||||
|
"d": "De combien de niveaux au-dessus de lui un bot accepte de combattre en farmant."
|
||||||
|
},
|
||||||
|
"CoaBots.Healer.CriticalHealPct": {
|
||||||
|
"t": "Seuil de soin d’urgence",
|
||||||
|
"d": "Les soigneurs passent à leurs soins les plus puissants quand la vie d’un allié tombe sous cette valeur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchRadius": {
|
||||||
|
"t": "Rayon de recherche des cibles",
|
||||||
|
"d": "Jusqu’où un bot cherche des cibles de quête dans une zone d’objectif."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.EngageRange": {
|
||||||
|
"t": "Distance d’engagement",
|
||||||
|
"d": "Distance à laquelle un bot commence à combattre un monstre de quête."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMin": {
|
||||||
|
"t": "Monter en selle au-delà de (min.)",
|
||||||
|
"d": "Chaque bot monte pour les trajets plus longs qu’une distance personnelle tirée entre cette valeur et le maximum."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMax": {
|
||||||
|
"t": "Monter en selle au-delà de (max.)",
|
||||||
|
"d": "Borne supérieure de la distance personnelle de monte."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TaxiMinDistance": {
|
||||||
|
"t": "Utiliser les trajets aériens au-delà de",
|
||||||
|
"d": "Les trajets plus longs utilisent un trajet aérien quand le bot connaît un itinéraire."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SessionBreaks": {
|
||||||
|
"t": "Faire des pauses",
|
||||||
|
"d": "Les bots alternent quêtes et quelques minutes de vie en ville, comme un joueur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GatherDetours": {
|
||||||
|
"t": "Récolter herbes et minerai à proximité",
|
||||||
|
"d": "Les récolteurs quittent leur chemin pour un filon juste à côté."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxActiveQuests": {
|
||||||
|
"t": "Maximum de quêtes actives",
|
||||||
|
"d": "Nombre de quêtes qu’un bot porte en même temps."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.AcceptEliteQuests": {
|
||||||
|
"t": "Accepter les quêtes d’élite",
|
||||||
|
"d": "Les bots solo prennent des quêtes d’élite. Désactivé par défaut car ils ne peuvent généralement pas les finir seuls."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestLevelBelow": {
|
||||||
|
"t": "Quêtes sous son propre niveau",
|
||||||
|
"d": "De combien de niveaux en dessous de lui un bot accepte encore des quêtes."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestLevelAbove": {
|
||||||
|
"t": "Quêtes au-dessus de son propre niveau",
|
||||||
|
"d": "De combien de niveaux au-dessus de lui un bot accepte encore des quêtes."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxMobLevelAbove": {
|
||||||
|
"t": "Niveau maximal des monstres de quête",
|
||||||
|
"d": "De combien un monstre de quête peut dépasser le niveau du bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxObjectiveDistance": {
|
||||||
|
"t": "Objectif de quête le plus éloigné",
|
||||||
|
"d": "Les quêtes dont les objectifs sont plus loin ne sont pas prises."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GiverSearchRadius": {
|
||||||
|
"t": "Rayon de recherche des donneurs de quêtes",
|
||||||
|
"d": "Jusqu’où un bot cherche des donneurs de quêtes."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxBadAreasPerObjective": {
|
||||||
|
"t": "Zones essayées par objectif",
|
||||||
|
"d": "Nombre de zones qu’un bot abandonne avant de mettre la quête de côté."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMs": {
|
||||||
|
"t": "Durée de mise de côté (courte)",
|
||||||
|
"d": "Durée pendant laquelle une quête est mise de côté après l’abandon du bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMaxMs": {
|
||||||
|
"t": "Durée de mise de côté (longue)",
|
||||||
|
"d": "La durée maximale pendant laquelle une quête peut rester de côté après des échecs répétés."
|
||||||
|
},
|
||||||
|
"CoaBots.LfgFill.Enable": {
|
||||||
|
"t": "Complétion par bots de la recherche de donjon",
|
||||||
|
"d": "Quand vous vous inscrivez seul pour un donjon, des bots comblent les rôles manquants de tank, soigneur et dégâts."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoQueueDungeon.Enable": {
|
||||||
|
"t": "Les bots s’inscrivent seuls aux donjons",
|
||||||
|
"d": "Expérimental : des bots tanks inactifs s’inscrivent seuls à un donjon et la complétion ci-dessus termine le groupe."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.Enable": {
|
||||||
|
"t": "Complétion par bots des champs de bataille",
|
||||||
|
"d": "Quand quelqu’un s’inscrit à un champ de bataille, les deux équipes sont complétées par des bots pour que la partie commence tout de suite."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.TargetPlayersPerTeam": {
|
||||||
|
"t": "Taille d’équipe en champ de bataille",
|
||||||
|
"d": "Nombre de bots par équipe jusqu’auquel compléter. 0 signifie une équipe complète pour ce champ de bataille."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpOthers": {
|
||||||
|
"t": "Les bots aident les joueurs proches",
|
||||||
|
"d": "Un bot de passage rejoint un combat qu’un joueur ami est en train de perdre, sans prendre son butin ni son crédit."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpRadius": {
|
||||||
|
"t": "Distance d’aide",
|
||||||
|
"d": "À quelle distance un bot doit être pour rejoindre un combat."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpHealthPct": {
|
||||||
|
"t": "Aider sous une vie de",
|
||||||
|
"d": "Les bots aident quand la vie du joueur qui combat est inférieure à cette valeur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ResurrectOthers": {
|
||||||
|
"t": "Les bots ressuscitent les joueurs tombés",
|
||||||
|
"d": "Les bots qui connaissent un sort de résurrection relèvent les cadavres amis."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TemporaryParties": {
|
||||||
|
"t": "Groupes de bots temporaires",
|
||||||
|
"d": "Des bots de niveau proche avec la même quête s’unissent brièvement."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMaxSize": {
|
||||||
|
"t": "Taille des groupes temporaires",
|
||||||
|
"d": "Plus grand groupe temporaire."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyRadius": {
|
||||||
|
"t": "Distance de formation de groupe",
|
||||||
|
"d": "À quelle distance les bots doivent être pour s’unir."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMinMinutes": {
|
||||||
|
"t": "Durée minimale de groupe",
|
||||||
|
"d": "Durée minimale d’un groupe temporaire."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PartyMaxMinutes": {
|
||||||
|
"t": "Durée maximale de groupe",
|
||||||
|
"d": "Durée maximale d’un groupe temporaire."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMinMs": {
|
||||||
|
"t": "Intervalle du planificateur (min.)",
|
||||||
|
"d": "Temps le plus court entre deux passes de planification d’un bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMaxMs": {
|
||||||
|
"t": "Intervalle du planificateur (max.)",
|
||||||
|
"d": "Temps le plus long entre deux passes de planification d’un bot."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMinMs": {
|
||||||
|
"t": "Intervalle de recherche de cibles (min.)",
|
||||||
|
"d": "Temps le plus court entre deux recherches de cibles."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMaxMs": {
|
||||||
|
"t": "Intervalle de recherche de cibles (max.)",
|
||||||
|
"d": "Temps le plus long entre deux recherches de cibles."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchTimeoutMs": {
|
||||||
|
"t": "Limite de temps de recherche de zone",
|
||||||
|
"d": "Durée pendant laquelle un bot fouille une zone vide avant d’en essayer une autre."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ApproachTimeoutMs": {
|
||||||
|
"t": "Limite de temps d’approche",
|
||||||
|
"d": "Durée pendant laquelle un bot marche vers une cible réservée."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TravelTimeoutMs": {
|
||||||
|
"t": "Limite de temps de trajet",
|
||||||
|
"d": "Durée maximale d’un trajet complet vers une zone."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TravelPer100Yards": {
|
||||||
|
"t": "Poids de préférence : TravelPer100Yards",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.CrowdPerBot": {
|
||||||
|
"t": "Poids de préférence : CrowdPerBot",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Overlap": {
|
||||||
|
"t": "Poids de préférence : Overlap",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TurnIn": {
|
||||||
|
"t": "Poids de préférence : TurnIn",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Accept": {
|
||||||
|
"t": "Poids de préférence : Accept",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.AreaOccupancy": {
|
||||||
|
"t": "Poids de préférence : AreaOccupancy",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TargetReserved": {
|
||||||
|
"t": "Poids de préférence : TargetReserved",
|
||||||
|
"d": "Importance que les bots accordent à ce facteur pour choisir ce qu’ils font ensuite. Ne modifiez que si vous connaissez le planificateur."
|
||||||
|
},
|
||||||
|
"Rate.XP.Kill": {
|
||||||
|
"t": "Expérience des morts",
|
||||||
|
"d": "Multiplicateur de l’expérience gagnée en tuant des monstres. 1 est normal."
|
||||||
|
},
|
||||||
|
"Rate.XP.Quest": {
|
||||||
|
"t": "Expérience des quêtes",
|
||||||
|
"d": "Multiplicateur de l’expérience gagnée avec les quêtes."
|
||||||
|
},
|
||||||
|
"Rate.XP.Quest.DF": {
|
||||||
|
"t": "Expérience des quêtes quotidiennes / recherche de donjon",
|
||||||
|
"d": "Multiplicateur de l’expérience des quêtes de la recherche de donjon."
|
||||||
|
},
|
||||||
|
"Rate.XP.Explore": {
|
||||||
|
"t": "Expérience d’exploration",
|
||||||
|
"d": "Multiplicateur de l’expérience de la découverte de nouvelles zones."
|
||||||
|
},
|
||||||
|
"Rate.Drop.Item.Normal": {
|
||||||
|
"t": "Taux de butin d’objets",
|
||||||
|
"d": "Multiplicateur de la fréquence de chute des objets de qualité normale."
|
||||||
|
},
|
||||||
|
"Rate.Drop.Money": {
|
||||||
|
"t": "Taux de butin d’or",
|
||||||
|
"d": "Multiplicateur de l’or laissé par les monstres."
|
||||||
|
},
|
||||||
|
"Rate.Honor": {
|
||||||
|
"t": "Gain d’honneur",
|
||||||
|
"d": "Multiplicateur des points d’honneur gagnés."
|
||||||
|
},
|
||||||
|
"Rate.Reputation.Gain": {
|
||||||
|
"t": "Gain de réputation",
|
||||||
|
"d": "Multiplicateur de la réputation gagnée."
|
||||||
|
},
|
||||||
|
"Rate.Rest.InGame": {
|
||||||
|
"t": "Bonus de repos en jeu",
|
||||||
|
"d": "Vitesse à laquelle l’expérience de repos est consommée pendant que vous jouez."
|
||||||
|
},
|
||||||
|
"Rate.Creature.Normal.Damage": {
|
||||||
|
"t": "Dégâts des monstres",
|
||||||
|
"d": "Multiplicateur des dégâts des monstres normaux. Change beaucoup la difficulté."
|
||||||
|
},
|
||||||
|
"Rate.Creature.Normal.HP": {
|
||||||
|
"t": "Vie des monstres",
|
||||||
|
"d": "Multiplicateur de la vie des monstres normaux. Change beaucoup la difficulté."
|
||||||
|
},
|
||||||
|
"PlayerLimit": {
|
||||||
|
"t": "Nombre maximal de joueurs",
|
||||||
|
"d": "Combien de joueurs peuvent être en ligne en même temps. 0 signifie aucune limite."
|
||||||
|
},
|
||||||
|
"GameType": {
|
||||||
|
"t": "Type de royaume",
|
||||||
|
"d": "Le type de royaume affiché dans la liste des royaumes."
|
||||||
|
},
|
||||||
|
"RealmZone": {
|
||||||
|
"t": "Zone du royaume",
|
||||||
|
"d": "Le groupe de langue / de région du royaume montré aux clients."
|
||||||
|
},
|
||||||
|
"PlayerSaveInterval": {
|
||||||
|
"t": "Intervalle de sauvegarde automatique",
|
||||||
|
"d": "Fréquence de sauvegarde des personnages des joueurs pendant qu’ils sont en ligne."
|
||||||
|
},
|
||||||
|
"CharactersPerAccount": {
|
||||||
|
"t": "Personnages par compte",
|
||||||
|
"d": "Nombre maximal de personnages qu’un compte peut avoir sur tous les royaumes."
|
||||||
|
},
|
||||||
|
"CharactersPerRealm": {
|
||||||
|
"t": "Personnages par royaume",
|
||||||
|
"d": "Nombre maximal de personnages qu’un compte peut avoir sur ce royaume."
|
||||||
|
},
|
||||||
|
"StartPlayerLevel": {
|
||||||
|
"t": "Niveau de départ",
|
||||||
|
"d": "Niveau auquel commencent les nouveaux personnages."
|
||||||
|
},
|
||||||
|
"StartPlayerMoney": {
|
||||||
|
"t": "Or de départ",
|
||||||
|
"d": "Cuivre avec lequel commencent les nouveaux personnages (10000 cuivre = 1 or)."
|
||||||
|
},
|
||||||
|
"MaxPlayerLevel": {
|
||||||
|
"t": "Niveau maximal",
|
||||||
|
"d": "Niveau le plus élevé qu’un personnage peut atteindre. Le client du jeu ne gère que 80."
|
||||||
|
},
|
||||||
|
"SkipCinematics": {
|
||||||
|
"t": "Ignorer les cinématiques d’introduction",
|
||||||
|
"d": "Si les nouveaux personnages voient leur film d’introduction."
|
||||||
|
},
|
||||||
|
"DurabilityLoss.OnDeath": {
|
||||||
|
"t": "Durabilité perdue à la mort",
|
||||||
|
"d": "Pourcentage de durabilité des objets perdu à la mort."
|
||||||
|
},
|
||||||
|
"Death.SicknessLevel": {
|
||||||
|
"t": "Maladie de résurrection jusqu’au niveau",
|
||||||
|
"d": "Les personnages au-dessus de ce niveau reçoivent la maladie de résurrection. -10 la désactive."
|
||||||
|
},
|
||||||
|
"LeaveGroupOnLogout.Enabled": {
|
||||||
|
"t": "Quitter le groupe à la déconnexion",
|
||||||
|
"d": "Les joueurs sont retirés de leur groupe quand ils se déconnectent."
|
||||||
|
},
|
||||||
|
"GM.LoginState": {
|
||||||
|
"t": "Mode MJ à la connexion",
|
||||||
|
"d": "Si les maîtres de jeu démarrent avec le mode MJ activé."
|
||||||
|
},
|
||||||
|
"AllowTwoSide.Accounts": {
|
||||||
|
"t": "Les deux factions sur un compte",
|
||||||
|
"d": "Un compte peut avoir des personnages de l’Alliance et de la Horde."
|
||||||
|
},
|
||||||
|
"AllowTwoSide.Interaction.Chat": {
|
||||||
|
"t": "Discussion entre factions",
|
||||||
|
"d": "Les joueurs de l’Alliance et de la Horde peuvent se parler."
|
||||||
|
},
|
||||||
|
"AutoBroadcast.On": {
|
||||||
|
"t": "Annonces automatiques",
|
||||||
|
"d": "Diffuse à intervalles réguliers les messages stockés dans la base de données."
|
||||||
|
},
|
||||||
|
"AutoBroadcast.Timer": {
|
||||||
|
"t": "Intervalle des annonces",
|
||||||
|
"d": "Temps entre les annonces automatiques."
|
||||||
|
},
|
||||||
|
"Warden.Enabled": {
|
||||||
|
"t": "Anti-triche (Warden)",
|
||||||
|
"d": "Active la vérification anti-triche du client. Généralement inutile sur un serveur privé."
|
||||||
|
},
|
||||||
|
"MapUpdateInterval": {
|
||||||
|
"t": "Intervalle de mise à jour des cartes",
|
||||||
|
"d": "Fréquence à laquelle le monde met à jour les cartes. Plus bas est plus fluide mais utilise plus de processeur."
|
||||||
|
},
|
||||||
|
"MinWorldUpdateTime": {
|
||||||
|
"t": "Temps minimal de mise à jour du monde",
|
||||||
|
"d": "Temps le plus court entre deux mises à jour du monde. Augmentez-le pour réduire l’utilisation du processeur."
|
||||||
|
},
|
||||||
|
"ThreadPool": {
|
||||||
|
"t": "Threads de travail",
|
||||||
|
"d": "Nombre de threads de travail en arrière-plan. Plus aide avec beaucoup de joueurs."
|
||||||
|
},
|
||||||
|
"Network.Threads": {
|
||||||
|
"t": "Threads réseau",
|
||||||
|
"d": "Threads qui gèrent les connexions des joueurs. Un seul suffit pour les petits serveurs."
|
||||||
|
},
|
||||||
|
"Ra.Enable": {
|
||||||
|
"t": "Console distante",
|
||||||
|
"d": "Permet au Manager et aux scripts d’envoyer des commandes au serveur. Elle n’écoute que cet ordinateur ; laissez-la ainsi."
|
||||||
|
},
|
||||||
|
"Ra.IP": {
|
||||||
|
"t": "Adresse de la console distante",
|
||||||
|
"d": "Adresse sur laquelle écoute la console distante. Gardez 127.0.0.1 pour qu’elle ne soit pas accessible depuis Internet."
|
||||||
|
},
|
||||||
|
"Updates.EnableDatabases": {
|
||||||
|
"t": "Mises à jour automatiques des bases de données",
|
||||||
|
"d": "Permet au serveur de modifier lui-même ses bases de données au démarrage. Gardez 0 : le Manager applique et suit les mises à jour de base de données en toute sécurité."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"GameType.0": "Normal",
|
||||||
|
"GameType.1": "Joueur contre joueur",
|
||||||
|
"GameType.6": "Jeu de rôle",
|
||||||
|
"GameType.8": "Jeu de rôle + JcJ",
|
||||||
|
"SkipCinematics.0": "Tout afficher",
|
||||||
|
"SkipCinematics.1": "Ignorer sauf pour le premier personnage",
|
||||||
|
"SkipCinematics.2": "Tout ignorer",
|
||||||
|
"GM.LoginState.0": "Désactivé",
|
||||||
|
"GM.LoginState.1": "Activé",
|
||||||
|
"GM.LoginState.2": "Comme la dernière fois"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"balanced": {
|
||||||
|
"t": "Équilibré",
|
||||||
|
"d": "La configuration recommandée au quotidien : quêtes, complétion des donjons et des champs de bataille activées, journaux discrets."
|
||||||
|
},
|
||||||
|
"solo-friendly": {
|
||||||
|
"t": "Adapté au solo",
|
||||||
|
"d": "Des bots qui vous aident et complètent vos groupes, avec une petite population tranquille."
|
||||||
|
},
|
||||||
|
"living-world": {
|
||||||
|
"t": "Monde vivant",
|
||||||
|
"d": "Un monde plus animé : plus de bots, pauses, détours de récolte et groupes temporaires."
|
||||||
|
},
|
||||||
|
"performance": {
|
||||||
|
"t": "Performances",
|
||||||
|
"d": "Moins de bots et moins de réflexion des bots, pour les ordinateurs plus modestes."
|
||||||
|
},
|
||||||
|
"vanilla": {
|
||||||
|
"t": "Taux standard",
|
||||||
|
"d": "Tout à vitesse normale (×1)."
|
||||||
|
},
|
||||||
|
"relaxed": {
|
||||||
|
"t": "Détendu",
|
||||||
|
"d": "Progression plus rapide et plus de butin pour un jeu décontracté (×2 / ×3)."
|
||||||
|
},
|
||||||
|
"fast": {
|
||||||
|
"t": "Rapide",
|
||||||
|
"d": "Progression rapide pour des tests ou de courtes sessions (×5)."
|
||||||
|
},
|
||||||
|
"defaults": {
|
||||||
|
"t": "Valeurs recommandées",
|
||||||
|
"d": "Tous les paramètres reviennent à leur valeur par défaut."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,513 @@
|
|||||||
|
{
|
||||||
|
"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 означает 40 частей ботов с уровнями от 1 до 20)."
|
||||||
|
},
|
||||||
|
"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.WorldBrain.Enable": {
|
||||||
|
"t": "ИИ заданий",
|
||||||
|
"d": "Боты сами берут и выполняют задания. Если выключить, боты только собирают ресурсы, ловят рыбу, гриндят и бродят."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ServiceRadius": {
|
||||||
|
"t": "Радиус поиска городских служб",
|
||||||
|
"d": "Как далеко бот ищет торговцев и почтовые ящики."
|
||||||
|
},
|
||||||
|
"CoaBots.World.AreaRadius": {
|
||||||
|
"t": "Радиус области дел",
|
||||||
|
"d": "Как далеко бот ищет места для сбора ресурсов или гринда."
|
||||||
|
},
|
||||||
|
"CoaBots.World.ThinkIntervalMs": {
|
||||||
|
"t": "Интервал выбора дела",
|
||||||
|
"d": "Как часто каждый бот пересматривает своё дело."
|
||||||
|
},
|
||||||
|
"CoaBots.World.IdleBeforeErrandMs": {
|
||||||
|
"t": "Простой до начала дела",
|
||||||
|
"d": "Сколько времени бот должен не находить себе занятия, прежде чем начнёт дело."
|
||||||
|
},
|
||||||
|
"CoaBots.World.VerboseLog": {
|
||||||
|
"t": "Подробный журнал дел",
|
||||||
|
"d": "Записывает в журнал каждый шаг дел. Полезно для отладки, но при большом числе ботов создаёт много шума."
|
||||||
|
},
|
||||||
|
"CoaBots.Combat.VerboseLog": {
|
||||||
|
"t": "Подробный журнал боя",
|
||||||
|
"d": "Записывает в журнал решения в бою. Очень шумно; включайте только при поиске конкретной проблемы."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMinMs": {
|
||||||
|
"t": "Кратчайшее занятие",
|
||||||
|
"d": "Наименьшее время, в течение которого бот держится одного вида занятий."
|
||||||
|
},
|
||||||
|
"CoaBots.Profile.IntentMaxMs": {
|
||||||
|
"t": "Самое длинное занятие",
|
||||||
|
"d": "Наибольшее время, в течение которого бот держится одного вида занятий."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.SearchRadius": {
|
||||||
|
"t": "Радиус поиска для гринда",
|
||||||
|
"d": "Как далеко бот ищет монстров для гринда."
|
||||||
|
},
|
||||||
|
"CoaBots.Grind.MaxLevelAbove": {
|
||||||
|
"t": "Наибольший уровень монстра для гринда",
|
||||||
|
"d": "На сколько уровней выше себя бот согласен сражаться при гринде."
|
||||||
|
},
|
||||||
|
"CoaBots.Healer.CriticalHealPct": {
|
||||||
|
"t": "Порог экстренного лечения",
|
||||||
|
"d": "Целители переключаются на самые сильные исцеления, когда здоровье союзника падает ниже этого значения."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchRadius": {
|
||||||
|
"t": "Радиус поиска целей",
|
||||||
|
"d": "Как далеко бот высматривает цели заданий внутри области задачи."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.EngageRange": {
|
||||||
|
"t": "Дистанция начала боя",
|
||||||
|
"d": "Расстояние, на котором бот начинает бой с монстром из задания."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMin": {
|
||||||
|
"t": "Садиться на транспорт при пути от (мин.)",
|
||||||
|
"d": "Каждый бот садится на ездовое животное в поездках длиннее личного расстояния, выбираемого между этим значением и максимумом."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MountDistanceMax": {
|
||||||
|
"t": "Садиться на транспорт при пути от (макс.)",
|
||||||
|
"d": "Верхняя граница личного расстояния для посадки на ездовое животное."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TaxiMinDistance": {
|
||||||
|
"t": "Летать по маршрутам при пути от",
|
||||||
|
"d": "Поездки длиннее этого значения выполняются на маршрутах перелёта, если бот знает подходящий."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SessionBreaks": {
|
||||||
|
"t": "Делать перерывы",
|
||||||
|
"d": "Боты чередуют задания с несколькими минутами городской жизни, как игрок."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.GatherDetours": {
|
||||||
|
"t": "Собирать травы и руду поблизости",
|
||||||
|
"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": "Как далеко бот ищет тех, кто раздаёт задания."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.MaxBadAreasPerObjective": {
|
||||||
|
"t": "Областей на одну цель",
|
||||||
|
"d": "От скольких областей бот отказывается, прежде чем отложить задание."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMs": {
|
||||||
|
"t": "Время откладывания (короткое)",
|
||||||
|
"d": "Как долго задание откладывается после того, как бот от него отказался."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.QuestSuspendMaxMs": {
|
||||||
|
"t": "Время откладывания (длинное)",
|
||||||
|
"d": "Наибольший срок, на который задание можно отложить после повторных неудач."
|
||||||
|
},
|
||||||
|
"CoaBots.LfgFill.Enable": {
|
||||||
|
"t": "Дополнение группы ботами в Поиске подземелий",
|
||||||
|
"d": "Если вы встаёте в очередь в подземелье в одиночку, боты занимают недостающие роли танка, целителя и бойцов урона."
|
||||||
|
},
|
||||||
|
"CoaBots.AutoQueueDungeon.Enable": {
|
||||||
|
"t": "Боты сами встают в очередь в подземелья",
|
||||||
|
"d": "Экспериментально: бездействующие боты-танки сами встают в очередь в подземелье, а дополнение выше собирает группу."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.Enable": {
|
||||||
|
"t": "Дополнение поля боя ботами",
|
||||||
|
"d": "Когда кто-то встаёт в очередь на поле боя, обе команды пополняются ботами, чтобы матч начался сразу."
|
||||||
|
},
|
||||||
|
"CoaBots.BGFill.TargetPlayersPerTeam": {
|
||||||
|
"t": "Размер команды на поле боя",
|
||||||
|
"d": "Сколько ботов в команде добавлять. 0 означает полную команду для этого поля боя."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpOthers": {
|
||||||
|
"t": "Боты помогают игрокам поблизости",
|
||||||
|
"d": "Проходящий мимо бот вступает в бой, который проигрывает дружественный игрок, не забирая его добычу и не претендуя на зачёт."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpRadius": {
|
||||||
|
"t": "Дистанция помощи",
|
||||||
|
"d": "Как близко бот должен находиться, чтобы вступить в бой."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.HelpHealthPct": {
|
||||||
|
"t": "Помогать при здоровье ниже",
|
||||||
|
"d": "Боты помогают, когда здоровье сражающегося игрока ниже этого значения."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ResurrectOthers": {
|
||||||
|
"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.PlannerMinMs": {
|
||||||
|
"t": "Интервал планировщика (мин.)",
|
||||||
|
"d": "Кратчайшее время между проходами планирования бота."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.PlannerMaxMs": {
|
||||||
|
"t": "Интервал планировщика (макс.)",
|
||||||
|
"d": "Наибольшее время между проходами планирования бота."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMinMs": {
|
||||||
|
"t": "Интервал поиска целей (мин.)",
|
||||||
|
"d": "Кратчайшее время между поисками целей."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ScanMaxMs": {
|
||||||
|
"t": "Интервал поиска целей (макс.)",
|
||||||
|
"d": "Наибольшее время между поисками целей."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.SearchTimeoutMs": {
|
||||||
|
"t": "Лимит времени поиска в области",
|
||||||
|
"d": "Как долго бот обыскивает пустую область, прежде чем попробовать другую."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.ApproachTimeoutMs": {
|
||||||
|
"t": "Лимит времени подхода",
|
||||||
|
"d": "Как долго бот идёт к выбранной цели."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.TravelTimeoutMs": {
|
||||||
|
"t": "Лимит времени пути",
|
||||||
|
"d": "Сколько может занять вся поездка в область."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TravelPer100Yards": {
|
||||||
|
"t": "Вес предпочтения: TravelPer100Yards",
|
||||||
|
"d": "Насколько сильно боты учитывают этот фактор при выборе следующего дела. Меняйте, только если разбираетесь в планировщике."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.CrowdPerBot": {
|
||||||
|
"t": "Вес предпочтения: CrowdPerBot",
|
||||||
|
"d": "Насколько сильно боты учитывают этот фактор при выборе следующего дела. Меняйте, только если разбираетесь в планировщике."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Overlap": {
|
||||||
|
"t": "Вес предпочтения: Overlap",
|
||||||
|
"d": "Насколько сильно боты учитывают этот фактор при выборе следующего дела. Меняйте, только если разбираетесь в планировщике."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TurnIn": {
|
||||||
|
"t": "Вес предпочтения: TurnIn",
|
||||||
|
"d": "Насколько сильно боты учитывают этот фактор при выборе следующего дела. Меняйте, только если разбираетесь в планировщике."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.Accept": {
|
||||||
|
"t": "Вес предпочтения: Accept",
|
||||||
|
"d": "Насколько сильно боты учитывают этот фактор при выборе следующего дела. Меняйте, только если разбираетесь в планировщике."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.AreaOccupancy": {
|
||||||
|
"t": "Вес предпочтения: AreaOccupancy",
|
||||||
|
"d": "Насколько сильно боты учитывают этот фактор при выборе следующего дела. Меняйте, только если разбираетесь в планировщике."
|
||||||
|
},
|
||||||
|
"CoaBots.WorldBrain.Weight.TargetReserved": {
|
||||||
|
"t": "Вес предпочтения: TargetReserved",
|
||||||
|
"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": "Множитель получаемых очков чести."
|
||||||
|
},
|
||||||
|
"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": "Тип мира, отображаемый в списке миров."
|
||||||
|
},
|
||||||
|
"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": "Режим ГМ при входе",
|
||||||
|
"d": "Включён ли режим ГМ у игровых мастеров при входе."
|
||||||
|
},
|
||||||
|
"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": "Как часто мир обновляет карты. Меньше — плавнее, но больше нагрузка на процессор."
|
||||||
|
},
|
||||||
|
"MinWorldUpdateTime": {
|
||||||
|
"t": "Минимальное время обновления мира",
|
||||||
|
"d": "Наименьшее время между обновлениями мира. Увеличьте, чтобы снизить нагрузку на процессор."
|
||||||
|
},
|
||||||
|
"ThreadPool": {
|
||||||
|
"t": "Рабочие потоки",
|
||||||
|
"d": "Число фоновых рабочих потоков. Больше помогает при большом числе игроков."
|
||||||
|
},
|
||||||
|
"Network.Threads": {
|
||||||
|
"t": "Сетевые потоки",
|
||||||
|
"d": "Потоки, обрабатывающие подключения игроков. Для небольших серверов хватает одного."
|
||||||
|
},
|
||||||
|
"Ra.Enable": {
|
||||||
|
"t": "Удалённая консоль",
|
||||||
|
"d": "Позволяет менеджеру и скриптам отправлять серверу команды. Она слушает только этот компьютер; оставьте так."
|
||||||
|
},
|
||||||
|
"Ra.IP": {
|
||||||
|
"t": "Адрес удалённой консоли",
|
||||||
|
"d": "Адрес, на котором слушает удалённая консоль. Оставьте 127.0.0.1, чтобы она не была доступна из интернета."
|
||||||
|
},
|
||||||
|
"Updates.EnableDatabases": {
|
||||||
|
"t": "Автоматические обновления баз данных",
|
||||||
|
"d": "Позволяет серверу самому менять свои базы данных при запуске. Оставьте 0: менеджер безопасно применяет и учитывает обновления баз данных."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"GameType.0": "Обычный",
|
||||||
|
"GameType.1": "PvP",
|
||||||
|
"GameType.6": "Ролевой",
|
||||||
|
"GameType.8": "Ролевой + 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": "Все настройки возвращаются к значениям по умолчанию."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { Loader2 } from "lucide-react";
|
|||||||
import { api, asUiError, type CompanionSizes, type Population, type UiError } from "@/lib/api";
|
import { api, asUiError, type CompanionSizes, type Population, type UiError } from "@/lib/api";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { useHuman, useT } from "@/i18n";
|
import { hasKey, useHuman, useT, type Key } from "@/i18n";
|
||||||
|
|
||||||
export function CompanionsCard({ serverId }: { serverId: string }) {
|
export function CompanionsCard({ serverId }: { serverId: string }) {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
@@ -35,8 +35,15 @@ export function CompanionsCard({ serverId }: { serverId: string }) {
|
|||||||
};
|
};
|
||||||
}, [serverId]);
|
}, [serverId]);
|
||||||
|
|
||||||
|
// The backend describes a size's warning in English; show the translated text for the two known kinds.
|
||||||
|
const warningFor = (size?: { bots: number; warning: string | null }) => {
|
||||||
|
if (!size?.warning) return null;
|
||||||
|
return size.warning.startsWith(`${size.bots} companions`)
|
||||||
|
? t("comp.warnHardware", { n: size.bots, cores: sizes?.hardware.cores ?? "?", ram: sizes ? sizes.hardware.ram_gb.toFixed(0) : "?" })
|
||||||
|
: t("comp.warnMemory");
|
||||||
|
};
|
||||||
const count = choice === "custom" ? Number(custom) : (sizes?.sizes.find((s) => s.id === choice)?.bots ?? 0);
|
const count = choice === "custom" ? Number(custom) : (sizes?.sizes.find((s) => s.id === choice)?.bots ?? 0);
|
||||||
const warning = choice === "custom" ? (count > 500 ? t("comp.largeWarning") : null) : (sizes?.sizes.find((s) => s.id === choice)?.warning ?? null);
|
const warning = choice === "custom" ? (count > 500 ? t("comp.largeWarning") : null) : (warningFor(sizes?.sizes.find((s) => s.id === choice)));
|
||||||
const valid = Number.isInteger(count) && count >= 1 && count <= 2000;
|
const valid = Number.isInteger(count) && count >= 1 && count <= 2000;
|
||||||
|
|
||||||
async function add() {
|
async function add() {
|
||||||
@@ -70,7 +77,7 @@ export function CompanionsCard({ serverId }: { serverId: string }) {
|
|||||||
{sizes?.sizes.map((s) => (
|
{sizes?.sizes.map((s) => (
|
||||||
<label key={s.id} className={`cursor-pointer rounded-md border px-3 py-2 text-sm ${choice === s.id ? "border-gold bg-gold/10" : "border-line hover:bg-white/5"}`}>
|
<label key={s.id} className={`cursor-pointer rounded-md border px-3 py-2 text-sm ${choice === s.id ? "border-gold bg-gold/10" : "border-line hover:bg-white/5"}`}>
|
||||||
<input type="radio" name="size" className="sr-only" checked={choice === s.id} onChange={() => setChoice(s.id)} />
|
<input type="radio" name="size" className="sr-only" checked={choice === s.id} onChange={() => setChoice(s.id)} />
|
||||||
{s.title} <span className="text-muted">· {s.bots}</span>
|
{hasKey(`comp.size.${s.id}`) ? t(`comp.size.${s.id}` as Key) : s.title} <span className="text-muted">· {s.bots}</span>
|
||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
<label className={`cursor-pointer rounded-md border px-3 py-2 text-sm ${choice === "custom" ? "border-gold bg-gold/10" : "border-line hover:bg-white/5"}`}>
|
<label className={`cursor-pointer rounded-md border px-3 py-2 text-sm ${choice === "custom" ? "border-gold bg-gold/10" : "border-line hover:bg-white/5"}`}>
|
||||||
|
|||||||
@@ -3,12 +3,45 @@ import { Check, Loader2, TriangleAlert, X } from "lucide-react";
|
|||||||
import { api, asUiError, type DiagCheck, type UiError } from "@/lib/api";
|
import { api, asUiError, type DiagCheck, type UiError } from "@/lib/api";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { useHuman, useI18n } from "@/i18n";
|
import { hasKey, useHuman, useI18n, type Key } from "@/i18n";
|
||||||
|
|
||||||
const ICON = { ok: Check, warn: TriangleAlert, fail: X } as const;
|
const ICON = { ok: Check, warn: TriangleAlert, fail: X } as const;
|
||||||
const TONE = { ok: "text-ok", warn: "text-warn", fail: "text-bad" } as const;
|
const TONE = { ok: "text-ok", warn: "text-warn", fail: "text-bad" } as const;
|
||||||
const WORD = { ok: "diag.word.ok", warn: "diag.word.warn", fail: "diag.word.fail" } as const;
|
const WORD = { ok: "diag.word.ok", warn: "diag.word.warn", fail: "diag.word.fail" } as const;
|
||||||
|
|
||||||
|
type T = (k: Key, v?: Record<string, string | number>) => string;
|
||||||
|
|
||||||
|
/** The backend writes each check in English; recognise the known ones and show them in the current language. */
|
||||||
|
function checkText(t: T, c: DiagCheck): { title: string; detail: string } {
|
||||||
|
const title = hasKey(`dg.title.${c.id}`) ? t(`dg.title.${c.id}` as Key) : c.title;
|
||||||
|
const d = c.detail;
|
||||||
|
const rules: [RegExp, (m: RegExpMatchArray) => string][] = [
|
||||||
|
[/^All expected server parts were found\.$/, () => t("dg.files.ok")],
|
||||||
|
[/^Some server parts are missing\.$/, () => t("dg.files.partial")],
|
||||||
|
[/^This is a custom server build; some features are limited\.$/, () => t("dg.files.custom")],
|
||||||
|
[/^This folder does not look like a CoA server\.$/, () => t("dg.files.bad")],
|
||||||
|
[/^Running$/, () => t("dg.svc.running")],
|
||||||
|
[/^Port (\d+) is used by another program \(process (\d+)\)\.$/, (m) => t("dg.svc.port", { port: m[1], pid: m[2] })],
|
||||||
|
[/^Starting, not answering yet\.$/, () => t("dg.svc.starting")],
|
||||||
|
[/^Not running\.$/, () => t("dg.svc.stopped")],
|
||||||
|
[/^Configuration files can be read\.$/, () => t("dg.configs.ok")],
|
||||||
|
[/^Cannot read: (.*)$/, (m) => t("dg.configs.bad", { files: m[1] })],
|
||||||
|
[/^Unusable values for: (.*)$/, (m) => t("dg.values.bad", { keys: m[1] })],
|
||||||
|
[/^(\d+) GB free$/, (m) => t("dg.disk.ok", { gb: m[1] })],
|
||||||
|
[/^Only (\d+) GB free; backups and updates need room\.$/, (m) => t("dg.disk.low", { gb: m[1] })],
|
||||||
|
[/^The server folder is writable\.$/, () => t("dg.perm.ok")],
|
||||||
|
[/^The Manager cannot write to the server folder/, () => t("dg.perm.bad")],
|
||||||
|
[/^The saved game folder was not found; choose it again in Settings\.$/, () => t("dg.client.missing")],
|
||||||
|
[/^Database and server console are not reachable from the network\.$/, () => t("dg.exposure.ok")],
|
||||||
|
[/^Reachable from the network: (.*)\.$/, (m) => t("dg.exposure.bad", { what: m[1] })],
|
||||||
|
];
|
||||||
|
for (const [re, f] of rules) {
|
||||||
|
const m = d.match(re);
|
||||||
|
if (m) return { title, detail: f(m) };
|
||||||
|
}
|
||||||
|
return { title, detail: d };
|
||||||
|
}
|
||||||
|
|
||||||
export function DiagnosticsCard({ serverId }: { serverId: string }) {
|
export function DiagnosticsCard({ serverId }: { serverId: string }) {
|
||||||
const { t, tn } = useI18n();
|
const { t, tn } = useI18n();
|
||||||
const human = useHuman();
|
const human = useHuman();
|
||||||
@@ -60,9 +93,9 @@ export function DiagnosticsCard({ serverId }: { serverId: string }) {
|
|||||||
<li key={c.id + c.title} className="flex items-start gap-3 py-2">
|
<li key={c.id + c.title} className="flex items-start gap-3 py-2">
|
||||||
<Icon className={`mt-0.5 h-4 w-4 shrink-0 ${TONE[c.level]}`} aria-hidden />
|
<Icon className={`mt-0.5 h-4 w-4 shrink-0 ${TONE[c.level]}`} aria-hidden />
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium">{c.title}</span>
|
<span className="font-medium">{checkText(t, c).title}</span>
|
||||||
<span className="sr-only"> — {t(WORD[c.level])}</span>
|
<span className="sr-only"> — {t(WORD[c.level])}</span>
|
||||||
<p className="text-muted">{c.detail}</p>
|
<p className="text-muted">{checkText(t, c).detail}</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export function FriendsPage({ serverId }: { serverId: string }) {
|
|||||||
run(`enable-${mode}`, async () => {
|
run(`enable-${mode}`, async () => {
|
||||||
const r = await api.friendsEnable(serverId, mode, net?.public_ip ?? undefined, mode === "direct" && !!net?.router_found);
|
const r = await api.friendsEnable(serverId, mode, net?.public_ip ?? undefined, mode === "direct" && !!net?.router_found);
|
||||||
setNeedsRestart(r.restart_required);
|
setNeedsRestart(r.restart_required);
|
||||||
return [r.restart_required ? t("fr.restartToApply") : null, r.note].filter(Boolean).join(" ") || t("fr.ready");
|
return [r.restart_required ? t("fr.restartToApply") : null, r.note ? (r.note.startsWith("Your router was asked") ? t("fr.note.forwarded") : r.note.startsWith("Your router does not support") ? t("fr.note.manual") : r.note) : null].filter(Boolean).join(" ") || t("fr.ready");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!st) return <p className="text-muted">{error ? human(error.human).message : t("fr.looking")}</p>;
|
if (!st) return <p className="text-muted">{error ? human(error.human).message : t("fr.looking")}</p>;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { AlertTriangle, Check, Minus } from "lucide-react";
|
|||||||
import { api, asUiError, type Classification, type ScanReport, type ServerSummary, type UiError } from "@/lib/api";
|
import { api, asUiError, type Classification, type ScanReport, type ServerSummary, type UiError } from "@/lib/api";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { useHuman, useT, type Key } from "@/i18n";
|
import { hasKey, useHuman, useT, type Key } from "@/i18n";
|
||||||
|
|
||||||
const HEADLINE: Record<Classification, { title: Key; tone: string; text: Key }> = {
|
const HEADLINE: Record<Classification, { title: Key; tone: string; text: Key }> = {
|
||||||
healthy: { title: "import.healthy.title", tone: "text-ok", text: "import.healthy.text" },
|
healthy: { title: "import.healthy.title", tone: "text-ok", text: "import.healthy.text" },
|
||||||
@@ -101,7 +101,7 @@ export function ImportServer(props: {
|
|||||||
<ul className="mt-4 divide-y divide-line text-sm">
|
<ul className="mt-4 divide-y divide-line text-sm">
|
||||||
{report.items.map((it) => (
|
{report.items.map((it) => (
|
||||||
<li key={it.key} className="flex items-center justify-between py-2">
|
<li key={it.key} className="flex items-center justify-between py-2">
|
||||||
<span>{it.label}</span>
|
<span>{hasKey(`scan.label.${it.key}`) ? t(`scan.label.${it.key}` as Key) : it.label}</span>
|
||||||
<span className="flex items-center gap-2 text-muted">
|
<span className="flex items-center gap-2 text-muted">
|
||||||
{it.detail && <span className="text-xs">{it.detail}</span>}
|
{it.detail && <span className="text-xs">{it.detail}</span>}
|
||||||
{it.status === "found" ? (
|
{it.status === "found" ? (
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import { useT } from "@/i18n";
|
||||||
|
|
||||||
export function Placeholder({ title, question }: { title: string; question: string }) {
|
export function Placeholder({ title, question }: { title: string; question: string }) {
|
||||||
|
const t = useT();
|
||||||
return (
|
return (
|
||||||
<div className="max-w-xl">
|
<div className="max-w-xl">
|
||||||
<h1 className="text-2xl font-semibold">{title}</h1>
|
<h1 className="text-2xl font-semibold">{title}</h1>
|
||||||
<p className="mt-1 text-muted">{question}</p>
|
<p className="mt-1 text-muted">{question}</p>
|
||||||
<p className="mt-8 rounded-card border border-line bg-card/70 p-5 text-sm text-muted">
|
<p className="mt-8 rounded-card border border-line bg-card/70 p-5 text-sm text-muted">
|
||||||
This section is being built in a later release.
|
{t("placeholder.soon")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Card } from "@/components/ui/card";
|
|||||||
import { ClientCard } from "@/screens/ClientCard";
|
import { ClientCard } from "@/screens/ClientCard";
|
||||||
import { DiagnosticsCard } from "@/screens/DiagnosticsCard";
|
import { DiagnosticsCard } from "@/screens/DiagnosticsCard";
|
||||||
import { AboutCard } from "@/screens/AboutCard";
|
import { AboutCard } from "@/screens/AboutCard";
|
||||||
import { useHuman, useI18n, type Key } from "@/i18n";
|
import { hasKey, useHuman, useI18n, type Key } from "@/i18n";
|
||||||
import { LanguagePicker } from "@/components/LanguagePicker";
|
import { LanguagePicker } from "@/components/LanguagePicker";
|
||||||
|
|
||||||
function mb(bytes: number) {
|
function mb(bytes: number) {
|
||||||
@@ -192,7 +192,7 @@ export function SettingsHome({ serverId }: { serverId: string }) {
|
|||||||
{busy === "update" && progress && (
|
{busy === "update" && progress && (
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<div className="flex justify-between text-sm">
|
<div className="flex justify-between text-sm">
|
||||||
<span role="status">{progress.step}</span>
|
<span role="status">{hasKey(`ustep.${progress.step}`) ? t(`ustep.${progress.step}` as Key) : progress.step}</span>
|
||||||
<span className="text-muted">{progress.percent}%</span>
|
<span className="text-muted">{progress.percent}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 h-2 overflow-hidden rounded-full bg-white/10" role="progressbar" aria-valuenow={progress.percent} aria-valuemin={0} aria-valuemax={100}>
|
<div className="mt-2 h-2 overflow-hidden rounded-full bg-white/10" role="progressbar" aria-valuenow={progress.percent} aria-valuemin={0} aria-valuemax={100}>
|
||||||
|
|||||||
@@ -17,16 +17,21 @@ import { cn } from "@/lib/utils";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { CompanionsCard } from "@/screens/CompanionsCard";
|
import { CompanionsCard } from "@/screens/CompanionsCard";
|
||||||
import { useHuman, useI18n, useT, type Key } from "@/i18n";
|
import { useHuman, useI18n, useSchemaText, useT, type Key } from "@/i18n";
|
||||||
|
|
||||||
type T = (k: Key, v?: Record<string, string | number>) => string;
|
type T = (k: Key, v?: Record<string, string | number>) => string;
|
||||||
|
|
||||||
const RESTART_LABEL = { runtime: "set.restart.runtime", world: "set.restart.world", full: "set.restart.full" } as const;
|
const RESTART_LABEL = { runtime: "set.restart.runtime", world: "set.restart.world", full: "set.restart.full" } as const;
|
||||||
|
|
||||||
function fmt(t: T, v: JsonValue, s: { type: string; unit?: string | null; options: { value: JsonValue; label: string }[] }): string {
|
type SX = ReturnType<typeof useSchemaText>;
|
||||||
|
|
||||||
|
function fmt(t: T, sx: SX, v: JsonValue, s: { key: string; type: string; unit?: string | null; options: { value: JsonValue; label: string }[] }): string {
|
||||||
if (typeof v === "boolean") return v ? t("set.on") : t("set.off");
|
if (typeof v === "boolean") return v ? t("set.on") : t("set.off");
|
||||||
if (s.type === "enum") return s.options.find((o) => o.value === v)?.label ?? String(v);
|
if (s.type === "enum") {
|
||||||
return s.unit ? `${v} ${s.unit}` : String(v);
|
const o = s.options.find((x) => x.value === v);
|
||||||
|
return o ? sx.option(s.key, o) : String(v);
|
||||||
|
}
|
||||||
|
return s.unit ? `${v} ${sx.unit(s.unit)}` : String(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clientCheck(t: T, s: SettingView, v: JsonValue): string | null {
|
function clientCheck(t: T, s: SettingView, v: JsonValue): string | null {
|
||||||
@@ -42,6 +47,7 @@ function clientCheck(t: T, s: SettingView, v: JsonValue): string | null {
|
|||||||
function Field(props: { s: SettingView; value: JsonValue; error: string | null; onChange: (v: JsonValue) => void }) {
|
function Field(props: { s: SettingView; value: JsonValue; error: string | null; onChange: (v: JsonValue) => void }) {
|
||||||
const { s, value, error, onChange } = props;
|
const { s, value, error, onChange } = props;
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const sx = useSchemaText();
|
||||||
const id = `f-${s.key}`;
|
const id = `f-${s.key}`;
|
||||||
const base = "rounded-md border bg-bg px-3 py-2 text-sm outline-none focus:border-gold";
|
const base = "rounded-md border bg-bg px-3 py-2 text-sm outline-none focus:border-gold";
|
||||||
if (s.type === "bool") {
|
if (s.type === "bool") {
|
||||||
@@ -68,7 +74,7 @@ function Field(props: { s: SettingView; value: JsonValue; error: string | null;
|
|||||||
>
|
>
|
||||||
{s.options.map((o) => (
|
{s.options.map((o) => (
|
||||||
<option key={String(o.value)} value={String(o.value)}>
|
<option key={String(o.value)} value={String(o.value)}>
|
||||||
{o.label}
|
{sx.option(s.key, o)}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@@ -88,7 +94,7 @@ function Field(props: { s: SettingView; value: JsonValue; error: string | null;
|
|||||||
onChange(numeric ? (raw.trim() === "" || Number.isNaN(Number(raw)) ? (raw as unknown as number) : Number(raw)) : raw);
|
onChange(numeric ? (raw.trim() === "" || Number.isNaN(Number(raw)) ? (raw as unknown as number) : Number(raw)) : raw);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{s.unit && <span className="text-xs text-muted">{s.unit}</span>}
|
{s.unit && <span className="text-xs text-muted">{sx.unit(s.unit)}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -96,12 +102,13 @@ function Field(props: { s: SettingView; value: JsonValue; error: string | null;
|
|||||||
function Row(props: { s: SettingView; value: JsonValue; error: string | null; onChange: (v: JsonValue) => void; onReset: () => void }) {
|
function Row(props: { s: SettingView; value: JsonValue; error: string | null; onChange: (v: JsonValue) => void; onReset: () => void }) {
|
||||||
const { s, value, error } = props;
|
const { s, value, error } = props;
|
||||||
const t = useT();
|
const t = useT();
|
||||||
|
const sx = useSchemaText();
|
||||||
const changed = value !== s.value;
|
const changed = value !== s.value;
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-[1fr_auto] items-start gap-x-6 gap-y-1 py-3.5">
|
<div className="grid grid-cols-[1fr_auto] items-start gap-x-6 gap-y-1 py-3.5">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor={`f-${s.key}`} className="flex flex-wrap items-center gap-2 font-medium">
|
<label htmlFor={`f-${s.key}`} className="flex flex-wrap items-center gap-2 font-medium">
|
||||||
{s.title}
|
{sx.title(s)}
|
||||||
{s.dangerous && (
|
{s.dangerous && (
|
||||||
<span className="inline-flex items-center gap-1 rounded bg-warn/15 px-1.5 py-0.5 text-[11px] font-normal text-warn">
|
<span className="inline-flex items-center gap-1 rounded bg-warn/15 px-1.5 py-0.5 text-[11px] font-normal text-warn">
|
||||||
<AlertTriangle className="h-3 w-3" aria-hidden /> {t("set.careful")}
|
<AlertTriangle className="h-3 w-3" aria-hidden /> {t("set.careful")}
|
||||||
@@ -109,9 +116,9 @@ function Row(props: { s: SettingView; value: JsonValue; error: string | null; on
|
|||||||
)}
|
)}
|
||||||
{changed && <span className="rounded bg-gold/15 px-1.5 py-0.5 text-[11px] font-normal text-gold">{t("set.changed")}</span>}
|
{changed && <span className="rounded bg-gold/15 px-1.5 py-0.5 text-[11px] font-normal text-gold">{t("set.changed")}</span>}
|
||||||
</label>
|
</label>
|
||||||
<p className="mt-0.5 max-w-xl text-sm text-muted">{s.description}</p>
|
<p className="mt-0.5 max-w-xl text-sm text-muted">{sx.description(s)}</p>
|
||||||
<p className="mt-1 text-xs text-muted/80">
|
<p className="mt-1 text-xs text-muted/80">
|
||||||
{t("set.default", { v: fmt(t, s.default, s) })}
|
{t("set.default", { v: fmt(t, sx, s.default, s) })}
|
||||||
{s.min !== undefined && s.max !== undefined && s.type !== "bool" ? ` · ${t("set.range", { min: s.min, max: s.max })}` : ""} · {t(RESTART_LABEL[s.restartRequired])}
|
{s.min !== undefined && s.max !== undefined && s.type !== "bool" ? ` · ${t("set.range", { min: s.min, max: s.max })}` : ""} · {t(RESTART_LABEL[s.restartRequired])}
|
||||||
</p>
|
</p>
|
||||||
{s.problem && <p className="mt-1 text-xs text-warn">{t("set.badValue", { problem: s.problem })}</p>}
|
{s.problem && <p className="mt-1 text-xs text-warn">{t("set.badValue", { problem: s.problem })}</p>}
|
||||||
@@ -126,7 +133,7 @@ function Row(props: { s: SettingView; value: JsonValue; error: string | null; on
|
|||||||
<Field s={s} value={value} error={error} onChange={props.onChange} />
|
<Field s={s} value={value} error={error} onChange={props.onChange} />
|
||||||
<button
|
<button
|
||||||
title={t("set.reset")}
|
title={t("set.reset")}
|
||||||
aria-label={t("set.resetItem", { name: s.title })}
|
aria-label={t("set.resetItem", { name: sx.title(s) })}
|
||||||
onClick={props.onReset}
|
onClick={props.onReset}
|
||||||
disabled={value === s.default}
|
disabled={value === s.default}
|
||||||
className="cursor-pointer rounded p-1.5 text-muted hover:bg-white/5 hover:text-ink disabled:opacity-25"
|
className="cursor-pointer rounded p-1.5 text-muted hover:bg-white/5 hover:text-ink disabled:opacity-25"
|
||||||
@@ -141,6 +148,7 @@ function Row(props: { s: SettingView; value: JsonValue; error: string | null; on
|
|||||||
export function SettingsPage(props: { serverId: string; scope: Scope; title: string; question: string }) {
|
export function SettingsPage(props: { serverId: string; scope: Scope; title: string; question: string }) {
|
||||||
const { serverId, scope } = props;
|
const { serverId, scope } = props;
|
||||||
const { t, tn } = useI18n();
|
const { t, tn } = useI18n();
|
||||||
|
const sx = useSchemaText();
|
||||||
const human = useHuman();
|
const human = useHuman();
|
||||||
const [view, setView] = useState<SettingsView | null>(null);
|
const [view, setView] = useState<SettingsView | null>(null);
|
||||||
const [draft, setDraft] = useState<Record<string, JsonValue>>({});
|
const [draft, setDraft] = useState<Record<string, JsonValue>>({});
|
||||||
@@ -266,8 +274,8 @@ export function SettingsPage(props: { serverId: string; scope: Scope; title: str
|
|||||||
<div className="mt-5 flex flex-wrap items-center gap-2">
|
<div className="mt-5 flex flex-wrap items-center gap-2">
|
||||||
<span className="text-sm text-muted">{t("set.presets")}</span>
|
<span className="text-sm text-muted">{t("set.presets")}</span>
|
||||||
{presets.map((p) => (
|
{presets.map((p) => (
|
||||||
<Button key={p.id} size="sm" title={p.description} onClick={() => void openPreset(p.id)}>
|
<Button key={p.id} size="sm" title={sx.preset(p).description} onClick={() => void openPreset(p.id)}>
|
||||||
{p.title}
|
{sx.preset(p).title}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
<Button size="sm" variant="ghost" onClick={() => void openPreset("defaults")}>
|
<Button size="sm" variant="ghost" onClick={() => void openPreset("defaults")}>
|
||||||
@@ -277,8 +285,8 @@ export function SettingsPage(props: { serverId: string; scope: Scope; title: str
|
|||||||
|
|
||||||
{preview && (
|
{preview && (
|
||||||
<Card className="mt-4 border-gold/40 p-5">
|
<Card className="mt-4 border-gold/40 p-5">
|
||||||
<p className="font-medium">{preview.title}</p>
|
<p className="font-medium">{sx.preset({ id: preview.id, title: preview.title, description: preview.description }).title}</p>
|
||||||
<p className="text-sm text-muted">{preview.description}</p>
|
<p className="text-sm text-muted">{sx.preset({ id: preview.id, title: preview.title, description: preview.description }).description}</p>
|
||||||
{preview.changes.length === 0 ? (
|
{preview.changes.length === 0 ? (
|
||||||
<p className="mt-3 text-sm">{t("set.matches")}</p>
|
<p className="mt-3 text-sm">{t("set.matches")}</p>
|
||||||
) : (
|
) : (
|
||||||
@@ -291,9 +299,9 @@ export function SettingsPage(props: { serverId: string; scope: Scope; title: str
|
|||||||
const s = view.settings.find((x) => x.key === c.key)!;
|
const s = view.settings.find((x) => x.key === c.key)!;
|
||||||
return (
|
return (
|
||||||
<li key={c.key} className="flex justify-between gap-4 py-1.5">
|
<li key={c.key} className="flex justify-between gap-4 py-1.5">
|
||||||
<span>{c.title}</span>
|
<span>{sx.title({ key: c.key, title: c.title })}</span>
|
||||||
<span className="text-muted">
|
<span className="text-muted">
|
||||||
{fmt(t, c.from, s)} → <span className="text-ink">{fmt(t, c.to, s)}</span>
|
{fmt(t, sx, c.from, s)} → <span className="text-ink">{fmt(t, sx, c.to, s)}</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@@ -367,7 +375,7 @@ export function SettingsPage(props: { serverId: string; scope: Scope; title: str
|
|||||||
category === c.id ? "border-gold text-ink" : "border-transparent text-muted hover:text-ink",
|
category === c.id ? "border-gold text-ink" : "border-transparent text-muted hover:text-ink",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{c.title}
|
{sx.category(scope, c)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -38,4 +38,21 @@ for (const loc of ["ru", "de", "fr", "es"]) {
|
|||||||
const pct = ((100 * (en.size - missing)) / en.size).toFixed(1);
|
const pct = ((100 * (en.size - missing)) / en.size).toFixed(1);
|
||||||
console.log(`${loc}: ${en.size - missing}/${en.size} translated (${pct}%), ${missing} fall back to English`);
|
console.log(`${loc}: ${en.size - missing}/${en.size} translated (${pct}%), ${missing} fall back to English`);
|
||||||
}
|
}
|
||||||
|
// 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"]) {
|
||||||
|
const o = JSON.parse(readFileSync(join(root, "src", "i18n", "schema", `${loc}.json`), "utf8"));
|
||||||
|
let miss = 0;
|
||||||
|
for (const { sc, d, p } of schemas) {
|
||||||
|
for (const c of d.categories) if (!o.categories[`${sc}.${c.id}`]) miss++;
|
||||||
|
for (const s of d.settings) {
|
||||||
|
if (!o.settings[s.key]) miss++;
|
||||||
|
for (const opt of s.options ?? []) if (!o.options[`${s.key}.${opt.value}`]) miss++;
|
||||||
|
}
|
||||||
|
for (const x of p) if (!o.presets[x.id]) miss++;
|
||||||
|
}
|
||||||
|
console.log(`${loc}: schema overlay ${miss === 0 ? "complete" : miss + " entries missing"}`);
|
||||||
|
if (miss) errors++;
|
||||||
|
}
|
||||||
process.exit(errors ? 1 : 0);
|
process.exit(errors ? 1 : 0);
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"types": [
|
"types": [
|
||||||
"node"
|
"node"
|
||||||
|
|||||||
Reference in new issue
Block a user