Merge branch 'dev' into 'master'

4.0.7

Closes #106

See merge request crafty-controller/crafty-4!409
This commit is contained in:
Iain Powrie 2022-07-18 23:20:32 +00:00
commit b479652383
39 changed files with 1108 additions and 322 deletions

View File

@ -27,4 +27,3 @@ This checklist encourages us to confirm any changes have been analyzed to reduce
* [ ] Have you resolved any lint issues?
* [ ] Have you assigned a reviewer?
* [ ] Have you applied correct labels?
* [ ] Have you updated CHANGELOG.md?

View File

@ -1,8 +1,27 @@
# Changelog
## --- [4.0.6] - 2022/07/06
## --- [4.0.7] - 2022/07/18
### New features
None
- Task toggle ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/398))
- Basic API for modifying tasks ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/398))
- Toggle Visible servers on status page ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/399))
### Bug fixes
- Fixes stats recording for Oracle hosts ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/397))
- Improve use of object oriented architecture ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/400))
- Fix issue with API Server Instance is not serializable ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/401))
- Fix issue where the motd was not displayed properly on small screens ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/402))
- Fix log file path issues caused by using relative paths ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/406))
- Fix servers order on creation page ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/407))
### Tweaks
- Remove server.props requirement ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/403))
- Add platform & crafty version info to support logs ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/405))
### Lang
- Updated `fi_FI, fr_FR, he_IL, lv_LV, nl_BE, zh_CN, id_ID, lol_EN` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/408))
- Added `pt_BR` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/408))
- Sorted/Corrected `en_EN` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/408))
<br><br>
## --- [4.0.6] - 2022/07/06
### Bug fixes
- Remove redundant path check on backup restore ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/390))
- Fix issue with stats pinging on slow starting servers ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/391))

View File

@ -2,11 +2,11 @@
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Supported Python Versions](https://shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20-blue)](https://www.python.org)
[![Version(temp-hardcoded)](https://img.shields.io/badge/release-v4.0.6--beta-orange)](https://gitlab.com/crafty-controller/crafty-4/-/releases)
[![Version(temp-hardcoded)](https://img.shields.io/badge/release-v4.0.7--beta-orange)](https://gitlab.com/crafty-controller/crafty-4/-/releases)
[![Code Quality(temp-hardcoded)](https://img.shields.io/badge/code%20quality-10-brightgreen)](https://gitlab.com/crafty-controller/crafty-4)
[![Build Status](https://gitlab.com/crafty-controller/crafty-4/badges/master/pipeline.svg)](https://gitlab.com/crafty-controller/crafty-4/-/commits/master)
# Crafty Controller 4.0.6-beta
# Crafty Controller 4.0.7-beta
> Python based Control Panel for your Minecraft Server
## What is Crafty Controller?

View File

@ -2,6 +2,7 @@ import os
import logging
import time
import json
import pathlib
import typing as t
from app.classes.controllers.roles_controller import RolesController
@ -13,7 +14,6 @@ from app.classes.shared.console import Console
from app.classes.shared.helpers import Helpers
from app.classes.shared.main_models import DatabaseShortcuts
from app.classes.minecraft.server_props import ServerProps
from app.classes.minecraft.stats import Stats
from app.classes.models.servers import HelperServers
@ -171,18 +171,6 @@ class ServersController(metaclass=Singleton):
)
continue
settings_file = os.path.join(
Helpers.get_os_understandable_path(server["path"]), "server.properties"
)
# if the properties file isn't there, let's warn
if not Helpers.check_file_exists(settings_file):
logger.error(f"Unable to find {settings_file}. Skipping this server.")
Console.error(f"Unable to find {settings_file}. Skipping this server.")
continue
settings = ServerProps(settings_file)
temp_server_dict = {
"server_id": server.get("server_id"),
"server_data_obj": server,
@ -193,7 +181,6 @@ class ServersController(metaclass=Singleton):
self.stats,
self.file_helper,
),
"server_settings": settings.props,
}
# setup the server, do the auto start and all that jazz
@ -350,14 +337,6 @@ class ServersController(metaclass=Singleton):
def get_server_friendly_name(server_id):
return HelperServers.get_server_friendly_name(server_id)
def get_server_settings(self, server_id):
for server in self.servers_list:
if int(server["server_id"]) == int(server_id):
return server["server_settings"]
logger.warning(f"Unable to find server object for server id {server_id}")
return False
def crash_detection(self, server_obj):
svr = self.get_server_instance_by_id(server_obj.server_id)
# start or stop crash detection depending upon user preference
@ -538,7 +517,14 @@ class ServersController(metaclass=Singleton):
continue
log_files = list(
filter(lambda val: val != latest_log_file, os.listdir(logs_path))
filter(
lambda val: val != latest_log_file,
os.listdir(
pathlib.Path(
server["path"], os.path.split(server["log_path"])[0]
)
),
)
)
for log_file in log_files:
log_file_path = os.path.join(logs_path, log_file)

View File

@ -1,66 +0,0 @@
import pprint
import os
class ServerProps:
def __init__(self, filepath):
self.filepath = filepath
self.props = self._parse()
def _parse(self):
# Loads and parses the file specified in self.filepath
with open(self.filepath, encoding="utf-8") as full_path:
line = full_path.readline()
dictionary = {}
if os.path.exists(".header"):
os.remove(".header")
while line:
if "#" != line[0]:
string = line
string1 = string[: string.find("=")]
if "\n" in string:
string2 = string[string.find("=") + 1 : string.find("\n")]
else:
string2 = string[string.find("=") + 1 :]
dictionary[string1] = string2
else:
with open(".header", "a+", encoding="utf-8") as header:
header.write(line)
line = full_path.readline()
return dictionary
def print(self):
# Prints the properties dictionary (using pprint)
pprint.pprint(self.props)
def get(self):
# Returns the properties dictionary
return self.props
def update(self, key, val):
# Updates property in the properties dictionary [ update("pvp", "true") ]
# and returns boolean condition
if key in self.props.keys():
self.props[key] = val
return True
return False
def save(self):
# Writes to the new file
with open(self.filepath, "a+", encoding="utf-8") as f:
f.truncate(0)
with open(".header", encoding="utf-8") as header:
line = header.readline()
while line:
f.write(line)
line = header.readline()
header.close()
for key, value in self.props.items():
f.write(key + "=" + value + "\n")
if os.path.exists(".header"):
os.remove(".header")
@staticmethod
def cleanup():
if os.path.exists(".header"):
os.remove(".header")

View File

@ -6,10 +6,10 @@ import datetime
import base64
import typing as t
from app.classes.shared.null_writer import NullWriter
from app.classes.minecraft.mc_ping import ping
from app.classes.models.management import HostStats
from app.classes.models.servers import HelperServers
from app.classes.shared.null_writer import NullWriter
from app.classes.shared.helpers import Helpers
with redirect_stderr(NullWriter()):
@ -87,7 +87,9 @@ class Stats:
try:
cpu_freq = psutil.cpu_freq()
except NotImplementedError:
cpu_freq = psutil._common.scpufreq(current=0, min=0, max=0)
cpu_freq = None
if cpu_freq is None:
cpu_freq = psutil._common.scpufreq(current=-1, min=-1, max=-1)
memory = psutil.virtual_memory()
try:
node_stats: NodeStatsDict = {
@ -224,11 +226,6 @@ class Stats:
logger.info(f"Getting players for server {server}")
# get our settings and data dictionaries
# server_settings = server.get('server_settings', {})
# server_data = server.get('server_data_obj', {})
# TODO: search server properties file for possible override of 127.0.0.1
internal_ip = server["server_ip"]
server_port = server["server_port"]

View File

@ -37,6 +37,7 @@ class Servers(BaseModel):
server_port = IntegerField(default=25565)
logs_delete_after = IntegerField(default=0)
type = CharField(default="minecraft-java")
show_status = BooleanField(default=1)
class Meta:
table_name = "servers"
@ -80,6 +81,7 @@ class HelperServers:
server_type: This is the type of server you're creating.
server_port: The port the server will be monitored on, defaults to 25565
server_host: The host the server will be monitored on, defaults to 127.0.0.1
show_status: Should Crafty show this server on the public status page
Returns:
int: The new server's id

View File

@ -1,6 +1,7 @@
import os
import pathlib
from pathlib import Path
import platform
import shutil
import time
import logging
@ -159,7 +160,10 @@ class Controller:
final_path += "_" + server["server_uuid"]
os.mkdir(final_path)
try:
FileHelpers.copy_file(server["log_path"], final_path)
FileHelpers.copy_file(
pathlib.Path(server["path"], server["log_path"]),
final_path,
)
except Exception as e:
logger.warning(f"Failed to copy file with error: {e}")
# Copy crafty logs to archive dir
@ -172,6 +176,19 @@ class Controller:
id="logs_" + str(exec_user["user_id"]),
args=[temp_dir, temp_zip_storage + ".zip", exec_user],
)
# Make version file .txt when we download it for support
# Most people have a default editor for .txt also more mobile friendly...
FileHelpers.copy_file(
os.path.join(self.project_root, "app", "config", "version.json"),
os.path.join(temp_dir, "crafty_sys_info.txt"),
)
with open(
os.path.join(temp_dir, "crafty_sys_info.txt"), "a", encoding="utf-8"
) as f:
f.write("\n")
f.write("OS Info:\n")
f.write("OS: " + str(platform.system()) + "\n")
f.write("Version: " + str(platform.release()))
FileHelpers.make_compressed_archive(temp_zip_storage, temp_dir)
if len(self.helper.websocket_helper.clients) > 0:
self.helper.websocket_helper.broadcast_user(

View File

@ -1244,7 +1244,6 @@ class ServerInstance:
# process stats
p_stats = Stats._try_get_process_stats(self.process, self.check_running())
# TODO: search server properties file for possible override of 127.0.0.1
internal_ip = server["server_ip"]
server_port = server["server_port"]
server_name = server.get("server_name", f"ID#{server_id}")
@ -1253,7 +1252,10 @@ class ServerInstance:
if HelperServers.get_server_type_by_id(server_id) == "minecraft-bedrock":
int_mc_ping = ping_bedrock(internal_ip, int(server_port))
else:
int_mc_ping = ping(internal_ip, int(server_port))
try:
int_mc_ping = ping(internal_ip, int(server_port))
except:
int_mc_ping = False
int_data = False
ping_data = {}
@ -1315,11 +1317,6 @@ class ServerInstance:
logger.info(f"Getting players for server {server}")
# get our settings and data dictionaries
# server_settings = server.get('server_settings', {})
# server_data = server.get('server_data_obj', {})
# TODO: search server properties file for possible override of 127.0.0.1
internal_ip = server["server_ip"]
server_port = server["server_port"]
@ -1377,9 +1374,6 @@ class ServerInstance:
# process stats
p_stats = Stats._try_get_process_stats(self.process, self.check_running())
# TODO: search server properties file for possible override of 127.0.0.1
# internal_ip = server['server_ip']
# server_port = server['server_port']
internal_ip = server_dt["server_ip"]
server_port = server_dt["server_port"]

View File

@ -288,11 +288,13 @@ class TasksManager:
job_data["parent"],
job_data["delay"],
)
# Checks to make sure some doofus didn't actually make the newly
# created task a child of itself.
if str(job_data["parent"]) == str(sch_id):
HelpersManagement.update_scheduled_task(sch_id, {"parent": None})
# Check to see if it's enabled and is not a chain reaction.
# Check to see if it's enabled and is not a chain reaction.
if job_data["enabled"] and job_data["interval_type"] != "reaction":
if job_data["cron_string"] != "":
try:
@ -389,11 +391,21 @@ class TasksManager:
)
def update_job(self, sch_id, job_data):
HelpersManagement.update_scheduled_task(sch_id, job_data)
# Checks to make sure some doofus didn't actually make the newly
# created task a child of itself.
if str(job_data["parent"]) == str(sch_id):
HelpersManagement.update_scheduled_task(sch_id, {"parent": None})
if str(job_data.get("parent")) == str(sch_id):
job_data["parent"] = None
HelpersManagement.update_scheduled_task(sch_id, job_data)
if not (
"interval" in job_data
and "enabled" in job_data
and "cron_string" in job_data
and "interval_type" in job_data
):
return
try:
if job_data["interval"] != "reaction":
self.scheduler.remove_job(str(sch_id))
@ -403,71 +415,70 @@ class TasksManager:
"Assuming it was previously disabled. Starting new job."
)
if job_data["enabled"]:
if job_data["interval"] != "reaction":
if job_data["cron_string"] != "":
try:
self.scheduler.add_job(
HelpersManagement.add_command,
CronTrigger.from_crontab(
job_data["cron_string"], timezone=str(self.tz)
),
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
except Exception as e:
Console.error(f"Failed to schedule task with error: {e}.")
Console.info("Removing failed task from DB.")
self.controller.management_helper.delete_scheduled_task(sch_id)
else:
if job_data["interval_type"] == "hours":
self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute=0,
hour="*/" + str(job_data["interval"]),
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
elif job_data["interval_type"] == "minutes":
self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute="*/" + str(job_data["interval"]),
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
elif job_data["interval_type"] == "days":
curr_time = job_data["start_time"].split(":")
self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
day="*/" + str(job_data["interval"]),
hour=curr_time[0],
minute=curr_time[1],
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
if job_data["enabled"] and job_data["interval"] != "reaction":
if job_data["cron_string"] != "":
try:
self.scheduler.add_job(
HelpersManagement.add_command,
CronTrigger.from_crontab(
job_data["cron_string"], timezone=str(self.tz)
),
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
except Exception as e:
Console.error(f"Failed to schedule task with error: {e}.")
Console.info("Removing failed task from DB.")
self.controller.management_helper.delete_scheduled_task(sch_id)
else:
if job_data["interval_type"] == "hours":
self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute=0,
hour="*/" + str(job_data["interval"]),
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
elif job_data["interval_type"] == "minutes":
self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
minute="*/" + str(job_data["interval"]),
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
elif job_data["interval_type"] == "days":
curr_time = job_data["start_time"].split(":")
self.scheduler.add_job(
HelpersManagement.add_command,
"cron",
day="*/" + str(job_data["interval"]),
hour=curr_time[0],
minute=curr_time[1],
id=str(sch_id),
args=[
job_data["server_id"],
self.users_controller.get_id_by_name("system"),
"127.0.0.1",
job_data["command"],
],
)
else:
try:
self.scheduler.get_job(str(sch_id))

View File

@ -10,6 +10,7 @@ from app.classes.models.users import ApiKeys
from app.classes.shared.helpers import Helpers
from app.classes.shared.main_controller import Controller
from app.classes.shared.translation import Translation
from app.classes.models.management import DatabaseShortcuts
logger = logging.getLogger(__name__)
@ -204,6 +205,10 @@ class BaseHandler(tornado.web.RequestHandler):
authorized_servers = self.controller.servers.get_authorized_servers(
user["user_id"] # TODO: API key authorized servers?
)
authorized_servers = [
DatabaseShortcuts.get_data_obj(x.server_object)
for x in authorized_servers
]
logger.debug("Checking results")
if user:

View File

@ -36,8 +36,6 @@ class PanelHandler(BaseHandler):
user_roles = {}
for user_id in self.controller.users.get_all_user_ids():
user_roles_list = self.controller.users.get_user_roles_names(user_id)
# user_servers =
# self.controller.servers.get_authorized_servers(user.user_id)
user_roles[user_id] = user_roles_list
return user_roles
@ -192,9 +190,9 @@ class PanelHandler(BaseHandler):
total_players = 0
for server in page_data["servers"]:
total_players += len(
self.controller.servers.stats.get_server_players(
self.controller.servers.get_server_instance_by_id(
server["server_data"]["server_id"]
)
).get_server_players()
)
page_data["num_players"] = total_players
@ -531,6 +529,7 @@ class PanelHandler(BaseHandler):
page_data["downloading"] = self.controller.servers.get_download_status(
server_id
)
page_data["server_id"] = server_id
try:
page_data["waiting_start"] = self.controller.servers.get_waiting_start(
server_id
@ -538,9 +537,7 @@ class PanelHandler(BaseHandler):
except Exception as e:
logger.error(f"Failed to get server waiting to start: {e}")
page_data["waiting_start"] = False
page_data[
"get_players"
] = lambda: self.controller.servers.stats.get_server_players(server_id)
page_data["get_players"] = server.get_server_players()
page_data["active_link"] = subpage
page_data["permissions"] = {
"Commands": EnumPermissionsServer.COMMANDS,
@ -876,9 +873,6 @@ class PanelHandler(BaseHandler):
page_data["schedules"] = HelpersManagement.get_schedules_by_server(
server_id
)
page_data[
"get_players"
] = lambda: self.controller.servers.stats.get_server_players(server_id)
page_data["active_link"] = "schedules"
page_data["permissions"] = {
"Commands": EnumPermissionsServer.COMMANDS,
@ -944,9 +938,6 @@ class PanelHandler(BaseHandler):
self.redirect("/panel/error?error=Invalid Schedule ID")
return
schedule = self.controller.management.get_scheduled_task_model(sch_id)
page_data[
"get_players"
] = lambda: self.controller.servers.stats.get_server_players(server_id)
page_data["active_link"] = "schedules"
page_data["permissions"] = {
"Commands": EnumPermissionsServer.COMMANDS,
@ -1383,6 +1374,7 @@ class PanelHandler(BaseHandler):
server_ip = self.get_argument("server_ip", None)
server_port = self.get_argument("server_port", None)
executable_update_url = self.get_argument("executable_update_url", None)
show_status = int(float(self.get_argument("show_status", "0")))
else:
execution_command = server_obj.execution_command
executable = server_obj.executable
@ -1460,6 +1452,7 @@ class PanelHandler(BaseHandler):
server_obj.server_ip = server_ip
server_obj.server_port = server_port
server_obj.executable_update_url = executable_update_url
server_obj.show_status = show_status
else:
server_obj.path = server_obj.path
server_obj.log_path = server_obj.log_path

View File

@ -23,6 +23,15 @@ from app.classes.web.routes.api.servers.server.public import (
)
from app.classes.web.routes.api.servers.server.stats import ApiServersServerStatsHandler
from app.classes.web.routes.api.servers.server.stdin import ApiServersServerStdinHandler
from app.classes.web.routes.api.servers.server.tasks.index import (
ApiServersServerTasksIndexHandler,
)
from app.classes.web.routes.api.servers.server.tasks.task.children import (
ApiServersServerTasksTaskChildrenHandler,
)
from app.classes.web.routes.api.servers.server.tasks.task.index import (
ApiServersServerTasksTaskIndexHandler,
)
from app.classes.web.routes.api.servers.server.users import ApiServersServerUsersHandler
from app.classes.web.routes.api.users.index import ApiUsersIndexHandler
from app.classes.web.routes.api.users.user.index import ApiUsersUserIndexHandler
@ -103,6 +112,21 @@ def api_handlers(handler_args):
ApiServersServerIndexHandler,
handler_args,
),
(
r"/api/v2/servers/([0-9]+)/tasks/?",
ApiServersServerTasksIndexHandler,
handler_args,
),
(
r"/api/v2/servers/([0-9]+)/tasks/([0-9]+)/?",
ApiServersServerTasksTaskIndexHandler,
handler_args,
),
(
r"/api/v2/servers/([0-9]+)/tasks/([0-9]+)/children/?",
ApiServersServerTasksTaskChildrenHandler,
handler_args,
),
(
r"/api/v2/servers/([0-9]+)/stats/?",
ApiServersServerStatsHandler,

View File

@ -5,6 +5,7 @@ from app.classes.web.routes.api.roles.role.index import modify_role_schema
from app.classes.web.routes.api.roles.index import create_role_schema
from app.classes.web.routes.api.servers.server.index import server_patch_schema
from app.classes.web.routes.api.servers.index import new_server_schema
from app.classes.web.routes.api.servers.server.tasks.task.index import task_patch_schema
SCHEMA_LIST: t.Final = [
"login",
@ -14,6 +15,7 @@ SCHEMA_LIST: t.Final = [
"new_server",
"user_patch",
"new_user",
"task_patch",
]
@ -59,22 +61,8 @@ class ApiJsonSchemaHandler(BaseApiHandler):
"properties": {
**self.controller.users.user_jsonschema_props,
},
"anyOf": [
# Require at least one property
{"required": [name]}
for name in [
"username",
"password",
"email",
"enabled",
"lang",
"superuser",
"permissions",
"roles",
"hints",
]
],
"additionalProperties": False,
"minProperties": 1,
},
},
)
@ -93,6 +81,11 @@ class ApiJsonSchemaHandler(BaseApiHandler):
},
},
)
elif schema_name == "task_patch":
self.finish_json(
200,
{"status": "ok", "data": task_patch_schema},
)
else:
self.finish_json(
404,

View File

@ -28,11 +28,8 @@ modify_role_schema = {
},
},
},
"anyOf": [
{"required": ["name"]},
{"required": ["servers"]},
],
"additionalProperties": False,
"minProperties": 1,
}

View File

@ -28,28 +28,8 @@ server_patch_schema = {
"logs_delete_after": {"type": "integer"},
"type": {"type": "string", "minLength": 1},
},
"anyOf": [
# Require at least one property
{"required": [name]}
for name in [
"server_name",
"path",
"backup_path",
"executable",
"log_path",
"execution_command",
"auto_start",
"auto_start_delay",
"crash_detection",
"stop_command",
"executable_update_url",
"server_ip",
"server_port",
"logs_delete_after",
"type",
]
],
"additionalProperties": False,
"minProperties": 1,
}

View File

@ -0,0 +1,16 @@
# TODO: create and read
import logging
from app.classes.web.base_api_handler import BaseApiHandler
logger = logging.getLogger(__name__)
class ApiServersServerTasksIndexHandler(BaseApiHandler):
def get(self, server_id: str, task_id: str):
pass
def post(self, server_id: str, task_id: str):
pass

View File

@ -0,0 +1,13 @@
# TODO: read
import logging
from app.classes.web.base_api_handler import BaseApiHandler
logger = logging.getLogger(__name__)
class ApiServersServerTasksTaskChildrenHandler(BaseApiHandler):
def get(self, server_id: str, task_id: str):
pass

View File

@ -0,0 +1,110 @@
# TODO: read and delete
import json
import logging
from jsonschema import ValidationError, validate
from app.classes.models.management import HelpersManagement
from app.classes.models.server_permissions import EnumPermissionsServer
from app.classes.web.base_api_handler import BaseApiHandler
logger = logging.getLogger(__name__)
task_patch_schema = {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"default": True,
},
"action": {
"type": "string",
},
"interval": {"type": "integer"},
"interval_type": {
"type": "string",
"enum": [
# Basic tasks
"hours",
"minutes",
"days",
# Chain reaction tasks:
"reaction",
# CRON tasks:
"",
],
},
"start_time": {"type": "string", "pattern": r"\d{1,2}:\d{1,2}"},
"command": {"type": ["string", "null"]},
"one_time": {"type": "boolean", "default": False},
"cron_string": {"type": "string", "default": ""},
"parent": {"type": ["integer", "null"]},
"delay": {"type": "integer", "default": 0},
},
"additionalProperties": False,
"minProperties": 1,
}
class ApiServersServerTasksTaskIndexHandler(BaseApiHandler):
def get(self, server_id: str, task_id: str):
pass
def delete(self, server_id: str, task_id: str):
pass
def patch(self, server_id: str, task_id: str):
auth_data = self.authenticate_user()
if not auth_data:
return
try:
data = json.loads(self.request.body)
except json.decoder.JSONDecodeError as e:
return self.finish_json(
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
validate(data, task_patch_schema)
except ValidationError as e:
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
if server_id not in [str(x["server_id"]) for x in auth_data[0]]:
# if the user doesn't have access to the server, return an error
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
if (
EnumPermissionsServer.SCHEDULE
not in self.controller.server_perms.get_user_id_permissions_list(
auth_data[4]["user_id"], server_id
)
):
# if the user doesn't have Schedule permission, return an error
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
# Checks to make sure some doofus didn't actually make the newly
# created task a child of itself.
if str(data.get("parent")) == str(task_id) and data.get("parent") is not None:
data["parent"] = None
HelpersManagement.update_scheduled_task(task_id, data)
self.controller.management.add_to_audit_log(
auth_data[4]["user_id"],
f"Edited server {server_id}: updated schedule",
server_id,
self.get_remote_ip(),
)
self.tasks_manager.reload_schedule_from_db()
self.finish_json(200, {"status": "ok"})

View File

@ -112,22 +112,8 @@ class ApiUsersUserIndexHandler(BaseApiHandler):
"properties": {
**self.controller.users.user_jsonschema_props,
},
"anyOf": [
# Require at least one property
{"required": [name]}
for name in [
"username",
"password",
"email",
"enabled",
"lang",
"superuser",
"permissions",
"roles",
"hints",
]
],
"additionalProperties": False,
"minProperties": 1,
}
auth_data = self.authenticate_user()
if not auth_data:

View File

@ -62,12 +62,31 @@ class ServerHandler(BaseHandler):
exec_user_role.add(role["role_name"])
list_roles.append(self.controller.roles.get_role(role["role_id"]))
user_order = self.controller.users.get_user_by_id(exec_user["user_id"])
user_order = user_order["server_order"].split(",")
page_servers = []
server_ids = []
for server_id in user_order[:]:
for server in defined_servers[:]:
if str(server.server_id) == str(server_id):
page_servers.append(
DatabaseShortcuts.get_data_obj(server.server_object)
)
user_order.remove(server_id)
defined_servers.remove(server)
for server in defined_servers:
server_ids.append(str(server.server_id))
if server not in page_servers:
page_servers.append(
DatabaseShortcuts.get_data_obj(server.server_object)
)
for server_id in user_order[:]:
# remove IDs in list that user no longer has access to
if str(server_id) not in server_ids:
user_order.remove(server_id)
defined_servers = page_servers
template = "public/404.html"
@ -92,7 +111,7 @@ class ServerHandler(BaseHandler):
),
},
"hosts_data": self.controller.management.get_latest_hosts_stats(),
"menu_servers": defined_servers,
"menu_servers": page_servers,
"show_contribute": self.helper.get_setting("show_contribute_link", True),
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
"lang_page": Helpers.get_lang_page(

View File

@ -1,6 +1,6 @@
{
"major": 4,
"minor": 0,
"sub": 6,
"sub": 7,
"meta": "beta"
}

View File

@ -21,6 +21,18 @@
display: block;
}
.toggle-handle {
background-color: white !important;
}
.toggle-on {
color: black !important;
}
.toggle {
height: 0px !important;
}
.sidebar>.nav>.nav-item:not(.nav-profile)>.nav-link:before {
content: none;
position: absolute;

View File

@ -37,6 +37,11 @@
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<!-- End Alpine.js -->
<!-- Bootstrap Toggle -->
<link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
<script defer src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
<!-- End Bootstrap Toggle -->
</head>
<body class="dark-theme">

View File

@ -73,7 +73,7 @@
</style>
<h2>{{ translate('serverPlayerManagement', 'players', data['lang']) }}:</h2>
<ul style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
{% for player in data['get_players']() %}
{% for player in data['get_players'] %}
<li class="playerItem">
<h3>{{ player }}</h3>
<div class="buttons">

View File

@ -176,24 +176,35 @@
<div class="form-check-flat">
<label for="auto_start" class="form-check-label ml-4 mb-4">
{% if data['server_stats']['server_id']['auto_start'] %}
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" checked=""
value="1">{{ translate('serverConfig', 'serverAutoStart', data['lang']) }}
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" checked="" data-toggle="toggle"
value="1">&nbsp;&nbsp;{{ translate('serverConfig', 'serverAutoStart', data['lang']) }}
{% else %}
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" value="1">{{
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" value="1" data-toggle="toggle">&nbsp;&nbsp;{{
translate('serverConfig', 'serverAutoStart', data['lang']) }}
{% end %}
</label>
<label for="crash_detection" class="form-check-label ml-4 mb-4">
{% if data['server_stats']['server_id']['crash_detection'] %}
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection"
checked="" value="1">{{ translate('serverConfig', 'serverCrashDetection', data['lang']) }}
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection" data-toggle="toggle"
checked="" value="1">&nbsp;&nbsp;{{ translate('serverConfig', 'serverCrashDetection', data['lang']) }}
{% else %}
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection"
value="1">{{ translate('serverConfig', 'serverCrashDetection', data['lang']) }}
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection" data-toggle="toggle"
value="1">&nbsp;&nbsp;{{ translate('serverConfig', 'serverCrashDetection', data['lang']) }}
{% end %}
</label>
{% if data['super_user'] %}
<label for="show_status" class="form-check-label ml-4 mb-4">
{% if data['server_stats']['server_id']['show_status'] %}
<input type="checkbox" class="form-check-input" id="show_status" name="show_status" data-toggle="toggle"
checked="" value="1">&nbsp;&nbsp;{{ translate('serverConfig', 'showStatus', data['lang']) }}
{% else %}
<input type="checkbox" class="form-check-input" id="show_status" name="show_status" data-toggle="toggle"
value="1">&nbsp;&nbsp;{{ translate('serverConfig', 'showStatus', data['lang']) }}
{% end %}
</label>
{% end %}
</div>
<button type="submit" class="btn btn-success mr-2"><i class="fas fa-save"></i> {{
@ -243,13 +254,33 @@
</div>
<style>
.toggle-handle {
background-color: white !important;
}
.toggle-on {
color: black !important;
background-color: blueviolet !important;
}
.toggle {
height: 0px !important;
background-color: grey !important;
}
</style>
<!-- content-wrapper ends -->
{% end %}
{% block js %}
<script>
$(function() {
$('.form-check-input').bootstrapToggle({
on: '',
off: ''
});
})
const serverId = new URLSearchParams(document.location.search).get('id')

View File

@ -24,7 +24,7 @@
</div>
<!-- Page Title Header Ends-->
{% include "parts/details_stats.html %}
{% include "parts/details_stats.html" %}
<div class="row">
@ -33,10 +33,10 @@
<div class="card-body pt-0">
<span class="d-none d-sm-block">
{% include "parts/server_controls_list.html %}
{% include "parts/server_controls_list.html" %}
</span>
<span class="d-block d-sm-none">
{% include "parts/m_server_controls_list.html %}
{% include "parts/m_server_controls_list.html" %}
</span>
<div class="row">
@ -94,15 +94,7 @@
<p>{{schedule.start_time}}</p>
</td>
<td id="{{schedule.enabled}}" class="action">
{% if schedule.enabled %}
<span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
<input style="width: 10px !important;" type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
</td>
<td id="{{schedule.action}}" class="action">
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
@ -189,15 +181,8 @@
<p>{{schedule.start_time}}</p>
</li>
<li id="{{schedule.enabled}}" class="action" style="border-top: .1em solid gray; border-bottom: .1em solid gray">
{% if schedule.enabled %}
<h4>Enabled</h4> <span class="text-success">
<i class="fas fa-check-square"></i> Yes
</span>
{% else %}
<h4>Enabled</h4> <span class="text-danger">
<i class="far fa-times-square"></i> No
</span>
{% end %}
<h4>Enabled</h4>
<input type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
</li>
</ul>
</div>
@ -230,6 +215,15 @@
color: white !important;
;
}
.toggle-handle {
background-color: white !important;
}
.toggle-on {
color: black !important;
}
.toggle {
height: 0px !important;
}
</style>
@ -256,6 +250,39 @@
{% block js %}
<script>
function debounce(func, timeout = 300){
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => { func.apply(this, args); }, timeout);
};
}
$(() => {
$('.schedule-enabled-toggle').bootstrapToggle({
on: 'Yes',
off: 'No',
onstyle: 'success',
offstyle: 'danger',
})
$('.schedule-enabled-toggle').each(function() {
const enabled = JSON.parse(this.getAttribute('data-schedule-enabled'));
$(this).bootstrapToggle(enabled ? 'on' : 'off')
})
$('.schedule-enabled-toggle').change(function() {
const id = this.getAttribute('data-schedule-id');
const enabled = this.checked;
fetch(`/api/v2/servers/{{data['server_id']}}/tasks/${id}`, {
method: 'PATCH',
body: JSON.stringify({enabled}),
headers: {
'Content-Type': 'application/json',
},
})
});
})
const serverId = new URLSearchParams(document.location.search).get('id')
$(document).ready(function () {
@ -393,4 +420,4 @@
</script>
{% end %}
{% end %}

View File

@ -27,6 +27,7 @@
<span id="sync" style="margin-left: 5px;"><i class="fas fa-sync fa-spin"></i></span></h4>
{% end %}
{% for server in data['servers'] %}
{% if server['server_data']['show_status'] %}
<tr>
<td id="server_name_{{ server['stats']['server_id']['server_id'] }}">
<i class="fas fa-server"></i>
@ -71,6 +72,7 @@
</td>
</tr>
{% end %}
{% end %}
</tbody>
</table>
</div>
@ -125,7 +127,7 @@
<div class="media-body">
{% if server['stats']['desc'] != 'False' %}
<div id="m_server_motd_{{ server['stats']['server_id']['server_id'] }}">
<span id="input_motd_{{ server['stats']['server_id']['server_id'] }}" class="input_motd">{{
<span id="m_input_motd_{{ server['stats']['server_id']['server_id'] }}" class="input_motd">{{
server['stats']['desc'] }}</span> <br />
</div>
{% end %}
@ -143,6 +145,7 @@
<div id="m_server_motd_{{ server['stats']['server_id']['server_id'] }}">
<span class="text-warning"><i class="fas fa-exclamation-triangle"></i> Crafty can't get infos from this Server </span>
</div>
<div id="m_server_version_{{ server['stats']['server_id']['server_id'] }}"></div>
</div>
</div>
{% end %}
@ -200,7 +203,7 @@
}
motd = motd + `<span id="input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span> <br />`;
m_motd = m_motd + `<div class="media-body"><span id="input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span></div>`;
m_motd = m_motd + `<div class="media-body"><span id="m_input_motd_` + server.id + `" class="input_motd">` + server.desc + `</span></div>`;
server_motd.innerHTML = motd;
m_server_motd.innerHTML = m_motd;
}

View File

@ -0,0 +1,16 @@
# Generated by database migrator
import peewee
def migrate(migrator, database, **kwargs):
migrator.add_columns("servers", show_status=peewee.BooleanField(default=1))
"""
Write your migrations here.
"""
def rollback(migrator, database, **kwargs):
migrator.drop_columns("servers", ["show_status"])
"""
Write your rollback migrations here.
"""

View File

@ -40,12 +40,12 @@
"pageDescription": "Without these people, you wouldn't have Crafty",
"pageTitle": "Credits",
"patreonDesc": "to our Patreon / Ko-fi supporters!",
"subscriptionLevel": "Level",
"subscriberName": "Name",
"patreonOther": "Other",
"patreonSupporter": "Patreon / Ko-fi Supporters",
"patreonUpdate": "Last Update:",
"retiredStaff": "Retired Staff",
"subscriberName": "Name",
"subscriptionLevel": "Level",
"supportTeam": "Support and Documentation Team",
"thankYou": "THANK YOU",
"translationDesc": "to our community who translate!",
@ -170,6 +170,7 @@
"eulaAgree": "Do you agree?",
"eulaMsg": "You must agree to the EULA. A copy of the Mojang EULA is linked under this message.",
"eulaTitle": "Agree To EULA",
"fileTooLarge": "Upload failed. File upload too large. Contact system administrator for assistance.",
"hereIsTheError": "Here is the error",
"internet": "We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.",
"no-file": "We can't seem to locate the requested file. Double check the path. Does Crafty have proper permissions?",
@ -177,8 +178,7 @@
"not-downloaded": "We can't seem to find your executable file. Has it finished downloading? Are the permissions set to executable?",
"portReminder": "We have detected this is the first time {} has been run. Make sure to forward port {} through your router/firewall to make this remotely accessible from the internet.",
"start-error": "Server {} failed to start with error code: {}",
"terribleFailure": "What a Terrible Failure!",
"fileTooLarge": "Upload failed. File upload too large. Contact system administrator for assistance."
"terribleFailure": "What a Terrible Failure!"
},
"footer": {
"allRightsReserved": "All rights reserved",
@ -210,6 +210,7 @@
"delete": "Delete",
"edit": "Edit",
"enabled": "Enabled",
"match": "Passwords must match",
"newRole": "Add New Role",
"newUser": "Add New User",
"pageTitle": "Panel Config",
@ -220,8 +221,7 @@
"superConfirm": "Proceed only if you want this user to have access to EVERYTHING (all user accounts, servers, panel settings, etc.). They can even revoke your superuser rights.",
"superConfirmTitle": "Enable superuser? Are you sure?",
"user": "User",
"users": "Users",
"match": "Passwords must match"
"users": "Users"
},
"rolesConfig": {
"config": "Role Config",
@ -271,10 +271,10 @@
"restore": "Restore",
"restoring": "Restoring Backup. This may take a while. Please be patient.",
"save": "Save",
"shutdown": "Shutdown server for duration of backup",
"size": "Size",
"storageLocation": "Storage Location",
"storageLocationDesc": "Where do you want to store backups?",
"shutdown": "Shutdown server for duration of backup"
"storageLocationDesc": "Where do you want to store backups?"
},
"serverConfig": {
"bePatientDelete": "Please be patient while we remove your server from the Crafty panel. This screen will close in a few moments.",
@ -290,6 +290,9 @@
"deleteServerQuestionMessage": "Are you sure you want to delete this server? After this there is no going back...",
"exeUpdateURL": "Server Executable Update URL",
"exeUpdateURLDesc": "Direct Download URL for updates.",
"javaNoChange": "Do Not Override",
"javaVersion": "Override current Java Version",
"javaVersionDesc": "If you're going to override Java, make sure your current Java path in 'execution command' is wrapped in quotes (default 'java' variable excluded)",
"noDelete": "No, go back",
"noDeleteFiles": "No, just remove from panel",
"removeOldLogsAfter": "Remove Old Logs After",
@ -303,9 +306,6 @@
"serverCrashDetection": "Server Crash Detection",
"serverExecutable": "Server Executable",
"serverExecutableDesc": "The server's executable file",
"javaVersion": "Override current Java Version",
"javaVersionDesc": "If you're going to override java. Make sure your current java path in 'execution command' is wrapped in quotes (default 'java' variable excluded)",
"javaNoChange": "Do Not Override",
"serverExecutionCommand": "Server Execution Command",
"serverExecutionCommandDesc": "What will be launched in a hidden terminal",
"serverIP": "Server IP",
@ -320,6 +320,7 @@
"serverPortDesc": "Port Crafty should connect to for stats",
"serverStopCommand": "Server Stop Command",
"serverStopCommandDesc": "Command to send the program to stop it",
"showStatus": "Show On Public Status Page",
"stopBeforeDeleting": "Please stop the server before deleting it",
"update": "Update Executable",
"yesDelete": "Yes, delete",
@ -374,8 +375,8 @@
"noscript": "The file manager does not work without JavaScript",
"rename": "Rename",
"renameItemQuestion": "What should the new name be?",
"size": "Toggle Editor Size",
"save": "Save",
"size": "Toggle Editor Size",
"stayHere": "DO NOT LEAVE THIS PAGE!",
"unsupportedLanguage": "Warning: This is not a supported file type",
"unzip": "Unzip",
@ -537,4 +538,4 @@
"userSettings": "User Settings",
"uses": "Number of uses allowed (-1==No Limit)"
}
}
}

View File

@ -40,12 +40,12 @@
"pageDescription": "Ilman näitä ihmisiä sinulla ei olisi Craftya",
"pageTitle": "Hyvitykset",
"patreonDesc": "Patreon / Ko-fi-tukijoillemme!",
"subscriptionLevel": "Taso",
"subscriberName": "Nimi",
"patreonOther": "Muu",
"patreonSupporter": "Patreon / Ko-fi-tukijat",
"patreonUpdate": "Viimeisin päivitys:",
"retiredStaff": "Entinen henkilökunta",
"subscriberName": "Nimi",
"subscriptionLevel": "Taso",
"supportTeam": "Tuki- ja dokumentointitiimi",
"thankYou": "KIITOS",
"translationDesc": "yhteisöllemme, jotka kääntävät!",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "Etkö näe kaikkea mobiililaitteella?",
"cannotSeeOnMobile2": "Yritä vierittää taulukkoa sivuttain.",
"clone": "Kloonaa",
"cloneConfirm": "Oletko varma, että haluat kloonata tämän palvelimen? Tämä prosessi voi kestää hetken.",
"cpuCores": "Suorittimen ytimet",
"cpuCurFreq": "Nykyinen kellotaajuus",
"cpuMaxFreq": "Maksimi kellotaajuus",
@ -193,6 +194,7 @@
"eulaAgree": "Oletko samaa mieltä?",
"eulaMsg": "Sinun on hyväksyttävä EULA. Kopio Mojang EULA:sta on linkitetty tämän viestin alla.",
"eulaTitle": "Hyväksy EULA",
"fileTooLarge": "Lataus epäonnistui. Tiedosto on liian suuri. Ota yhteyttä järjestelmänvalvojaan saadaksesi apua.",
"hereIsTheError": "Tässä on virhe",
"internet": "Olemme havainneet, että Crafty -koneella ei ole Internet -yhteyttä. Asiakasyhteydet palvelimelle voivat olla rajalliset.",
"no-file": "Emme löydä pyydettyä tiedostoa. Tarkista polku uudelleen. Onko Craftylla asianmukaiset käyttöoikeudet?",
@ -292,6 +294,7 @@
"restore": "Palauttaa",
"restoring": "Varmuuskopion palauttaminen. Tämä voi kestää hetken. Olkaa kärsivällisiä.",
"save": "Tallenna",
"shutdown": "Sammuta palvelin varmuuskopioinnin ajaksi",
"size": "Koko",
"storageLocation": "Varmuuskopiointisijainti",
"storageLocationDesc": "Mihin haluat tallentaa varmuuskopiot?"
@ -310,6 +313,9 @@
"deleteServerQuestionMessage": "Haluatko varmasti poistaa tämän palvelimen? Tätä ei voi peruuttaa...",
"exeUpdateURL": "Palvelimen suoritettavan päivityksen URL-osoite",
"exeUpdateURLDesc": "Direct Download URL for updates.",
"javaNoChange": "Älä korvaa",
"javaVersion": "Korvaa nykyinen Java-versio",
"javaVersionDesc": "Jos aiot korvata Javan version, varmista, että nykyinen Java-polkusi 'suorituskomennossa' on kääritty lainausmerkkeihin (oletus 'java' muuttuja ei sisällytetty)",
"noDelete": "Ei, mene takaisin",
"noDeleteFiles": "Ei, poista vain paneelista",
"removeOldLogsAfter": "Poista vanhat lokit N päivän jälkeen",
@ -392,6 +398,7 @@
"rename": "Nimeä uudelleen",
"renameItemQuestion": "Mikä uuden nimen pitäisi olla?",
"save": "Tallenna",
"size": "Muuta tiedostoeditorin kokoa",
"stayHere": "ÄLÄ POISTU SIVULTA!",
"unsupportedLanguage": "Varoitus: Tätä tiedostotyyppiä ei tueta",
"unzip": "Pura",

View File

@ -40,12 +40,12 @@
"pageDescription": "Sans ces personnes, vous n'auriez pas Crafty",
"pageTitle": "Crédits",
"patreonDesc": "à nos Soutiens Patreon / Ko-fi !",
"subscriptionLevel": "Niveau",
"subscriberName": "Nom",
"patreonOther": "Autre",
"patreonSupporter": "Soutiens Patreon / Ko-fi",
"patreonUpdate": "Dernière mise à Jour :",
"retiredStaff": "Retraités de Crafty",
"subscriberName": "Nom",
"subscriptionLevel": "Niveau",
"supportTeam": "Equipe de Support et de Documentation",
"thankYou": "MERCI",
"translationDesc": "à notre communauté qui traduit Crafty !",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "Impossible de tout voir sur mobile ?",
"cannotSeeOnMobile2": "Essaie de déplacer le tableau sur le côté.",
"clone": "Cloner",
"cloneConfirm": "Es-tu sûr de vouloir cloner ce serveur ? Ce processus peut prendre du temps.",
"cpuCores": "Coeurs CPU",
"cpuCurFreq": "Fréquence CPU actuelle",
"cpuMaxFreq": "Fréquence CPU Maximum",
@ -169,6 +170,7 @@
"eulaAgree": "Êtes-vous d'accord?",
"eulaMsg": "Vous devez accepter le EULA. Une copie du CLUF de Mojang est liée sous ce message.",
"eulaTitle": "Accepter le EULA",
"fileTooLarge": "Echec du chargement. Le fichier est trop gros. Demande de l'aide à l'administrateur système.",
"hereIsTheError": "Il y a une erreur",
"internet": "Nous avons détecté que la machine exécutant Crafty n'a pas de connexion à Internet. Les connexions client au serveur peuvent être limitées.",
"no-file": "Nous ne parvenons pas à localiser le fichier demandé. Vérifier le chemin du fichier. Les permissions authorisent elles Crafty ?",
@ -268,6 +270,7 @@
"restore": "Restaurer",
"restoring": "Restauration de la sauvegarde. Cela peut prendre un peu de temps. S'il vous plaît soyez patient.",
"save": "Sauvegarder",
"shutdown": "Extinction du serveur pendant la durée de la sauvegarde",
"size": "Taille",
"storageLocation": "Emplacement de Sauvegarde",
"storageLocationDesc": "Où veux-tu enregister tes sauvegardes ?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "Es-tu sur de vouloir supprimer ce Serveur ? Après ça, il n'y aura pas de retour en arrière ...",
"exeUpdateURL": "Lien URL de mise à jour de l'exécutable du Serveur",
"exeUpdateURLDesc": "Lien URL de Téléchargement Direct pour les mises à jour.",
"javaNoChange": "Ne Pas Remplacer",
"javaVersion": "Remplace la version actuelle de Java",
"javaVersionDesc": "Si tu veux remplacer la version de Java, assure toi que le chemin vers la version de Java dans 'execution command' est bien entre guillements (par défaut sans la variable 'java')",
"noDelete": "Non, revenir en arrière",
"noDeleteFiles": "Non, Supprimer uniquement du tabelau de bord",
"removeOldLogsAfter": "Supprimer les Anciens Logs après",
@ -368,6 +374,7 @@
"rename": "Renommer",
"renameItemQuestion": "Quel devrait être le nouveau nom ?",
"save": "Sauvegarder",
"size": "Changer la Taille de l'Editeur",
"stayHere": "NE FERME PAS CETTE PAGE!",
"unsupportedLanguage": "Attention : Ce n'est pas un type de fichier supporté",
"unzip": "Décompresser",

View File

@ -66,6 +66,7 @@
"cannotSeeOnMobile": "לא רואים הכל בנייד?",
"cannotSeeOnMobile2": "נסו לגלול את הטבלה הצידה.",
"clone": "העתק",
"cloneConfirm": "האם אתם בטוחים שברצונכם להעתיק את השרת הזה? התהתליך לוקח המון זמן.",
"cpuCores": "ליבות מעבד",
"cpuCurFreq": "שעון נוכחי של מעבד",
"cpuMaxFreq": "שעון מרבי של מעבד",
@ -111,16 +112,16 @@
"copy": "העתק",
"copyKeys": "ctrl או u2318 + C כדי להעתיק את נתוני הטבלה ללוח המערכת שלך.<br><br>escape-כדי לבטל, לחצו על הודעה זו או והקישו על.",
"copySuccess": {
"_": "הועתקו %d שורות ללוח",
"1": "הועתקה שורה אחת ללוח"
"1": "הועתקה שורה אחת ללוח",
"_": "הועתקו %d שורות ללוח"
},
"copyTitle": "העתקה ללוח",
"csv": "CSV",
"excel": "Excel",
"pageLength": {
"_": "הצג %d שורות",
"1": "הצגת שורה אחת",
"-1": "הצגת כל השורות",
"1": "הצגת שורה אחת"
"_": "הצג %d שורות"
},
"pdf": "PDF",
"print": "הדפסה"
@ -143,19 +144,19 @@
"search": "לחפש:",
"select": {
"cells": {
"_": "נבחרו %d תאים",
"0": "לחצו על תא כדי לבחור אותו",
"1": "תא %d נבחר"
"1": "תא %d נבחר",
"_": "נבחרו %d תאים"
},
"columns": {
"_": "נבחרו %d עמודות",
"0": "לחצו על עמודה כדי לבחור בה",
"1": "עמודה %d נבחרה"
"1": "עמודה %d נבחרה",
"_": "נבחרו %d עמודות"
},
"rows": {
"_": "נבחרו %d שורות",
"0": "לחצו על שורה כדי לבחור בה",
"1": "נבחרה שורה %d"
"1": "נבחרה שורה %d",
"_": "נבחרו %d שורות"
}
},
"thousands": ",",
@ -169,6 +170,7 @@
"eulaAgree": "אתם מסכימים?",
"eulaMsg": "עליכם להסכים להסכם הרישיון למשתמש הקצה. עותק של הסכם הרישיון למשתמש הקצה של מוג'אנג מקושר תחת הודעה זו.",
"eulaTitle": "להסכים להסכם רישיון משתמש קצה של מוג'אנג",
"fileTooLarge": "העלאה נכשלה. העלאת הקובץ גדולה מדי. פנה למנהל המערכת לקבלת סיוע.",
"hereIsTheError": "הנה השגיאה",
"internet": "גילינו שלמכונה(מחשב) שמריצה את קראפטי אין חיבור לאינטרנט. חיבורי לקוחות לשרת עשויים להיות מוגבלים.",
"no-file": "נראה שאיננו מצליחים לאתר את הקובץ המבוקש. בדוק שוב את הנתיב. האם ל-קראפטי יש הרשאות מתאימות?",
@ -268,6 +270,7 @@
"restore": "לשחזר",
"restoring": "שחזור גיבוי. זה עשוי לקחת זמן. אנא חכו בסבלנות.",
"save": "שמירה",
"shutdown": "כיבוי שרת למשך הגיבוי",
"size": "גודל",
"storageLocation": "מקום איחסון",
"storageLocationDesc": "איפו אתם רוצים לאחסן גיבויים?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "האם אתם בטוחים שברצונכם למחוק את השרת הזה? אחרי זה אין דרך חזרה...",
"exeUpdateURL": "כתובת ה-URL של עדכון השרת הניתן להפעלה",
"exeUpdateURLDesc": "כתובת אתר להורדה ישירה לקבלת עדכונים.",
"javaNoChange": "לא למחוק",
"javaVersion": "כן למחוק את גרסאת ה-Java המותקנת כרגע",
"javaVersionDesc": "אם אתה מתכוון לעקוף את Java, ודא שנתיב ה-Java הנוכחי שלך ב'פקודה לביצוע' עטוף במרכאות (משתנה ברירת המחדל 'java' לא נכלל)",
"noDelete": "לא, חזרה אחורה",
"noDeleteFiles": "לא, פשוט הסר מהפאנל",
"removeOldLogsAfter": "הסר יומנים ישנים לאחר",
@ -368,6 +374,7 @@
"rename": "שנה שם",
"renameItemQuestion": "מה צריך להיות השם החדש?",
"save": "שמור",
"size": "החלף את גודל העורך",
"stayHere": "אל תצאומדף הזה!!",
"unsupportedLanguage": "אזהרה: סוג קובץ נתמך",
"unzip": "פתיחת קובץ מכווץ",

View File

@ -40,12 +40,12 @@
"pageDescription": "Tanpa orang-orang ini, Anda tidak akan memiliki Crafty",
"pageTitle": "Kredit",
"patreonDesc": "untuk pendukung Patreon / Ko-fi kami!",
"subscriptionLevel": "Level",
"subscriberName": "Nama",
"patreonOther": "Lainnya",
"patreonSupporter": "Suporter Patreon / Ko-fi",
"patreonUpdate": "Pembaharuan Terakhir:",
"retiredStaff": "Pensiunan Staf",
"subscriberName": "Nama",
"subscriptionLevel": "Level",
"supportTeam": "Tim Dukungan dan Dokumentasi",
"thankYou": "TERIMA KASIH",
"translationDesc": "untuk komunitas kami yang menerjemahkan!",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "Tidak Melihat Apa-Apa Di Mobile?",
"cannotSeeOnMobile2": "Coba gulir tabel ke samping.",
"clone": "Ganda",
"cloneConfirm": "Apakah kamu yakin untuk menggandakan server ini?. pekerjaan ini akan memerlukan beberapa waktu.",
"cpuCores": "CPU Cores",
"cpuCurFreq": "Jam Arus CPU",
"cpuMaxFreq": "Jam Maksimum CPU",
@ -169,6 +170,7 @@
"eulaAgree": "Apakah anda setuju?",
"eulaMsg": "Anda harus menyetujui EULA. Salinan Mojang EULA ditautkan di bawah pesan ini.",
"eulaTitle": "Setuju Ke EULA",
"fileTooLarge": "Gagal menggungah. File yang ingin di unggah terlalu besar. Kontak administrator system untuk pengawasan",
"hereIsTheError": "Disini Error nya",
"internet": "Kami telah mendeteksi mesin yang menjalankan Crafty tidak memiliki koneksi ke internet. Koneksi klien ke server mungkin terbatas.",
"no-file": "Kami tidak dapat menemukan file yang diminta. Periksa kembali jalurnya. Apakah Crafty memiliki izin yang tepat?",
@ -268,6 +270,7 @@
"restore": "Mengembalikan",
"restoring": "Memulihkan Pencadangan. Ini mungkin memakan waktu cukup lama. Harap bersabar.",
"save": "Simpan",
"shutdown": "Mematikan server untuk durasi pencadangan",
"size": "Ukuran",
"storageLocation": "Lokasi Penyimpanan",
"storageLocationDesc": "Di mana Anda ingin menyimpan cadangan?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "Apakah Anda yakin ingin menghapus server ini? Setelah ini tidak ada jalan kembali...",
"exeUpdateURL": "URL Update Eksekusi Server",
"exeUpdateURLDesc": "URL Unduhan Langsung untuk pembaruan.",
"javaNoChange": "Jangan Mengesampikan",
"javaVersion": "Mengesampikan Java Versi terkini",
"javaVersionDesc": "Jika Anda akan mengganti Java, pastikan jalur Java Anda saat ini di 'perintah eksekusi' dibungkus dengan tanda kutip (variabel 'java' default dikecualikan)",
"noDelete": "Tidak, Kembali",
"noDeleteFiles": "Tidak, Hanya delete dari panel",
"removeOldLogsAfter": "Hapus Log Lama Setelah",
@ -368,6 +374,7 @@
"rename": "Rename",
"renameItemQuestion": "Apa nama baru itu?",
"save": "Simpan",
"size": "Aktifkan Mode Mengedit Ukuran",
"stayHere": "JANGAN PERGI DARI HALAMAN INI!",
"unsupportedLanguage": "Peringatan: Ini bukan jenis file yang didukung",
"unzip": "Unzip",

View File

@ -40,12 +40,12 @@
"pageDescription": "WITHOUT THEES PEEPS, U WOULDNT HAS CWAFTY",
"pageTitle": "GUD HOOMANZ",
"patreonDesc": "2 DA PATREUN UN KOFEE SUPPORTERS!",
"subscriptionLevel": "LVLZ",
"subscriberName": "NAMEZ",
"patreonOther": "OTHERZ",
"patreonSupporter": "PATREUN UN KOFEE SUPPORTERS",
"patreonUpdate": "LAST UPDATE:",
"retiredStaff": "DISTANT PPLZ, NEVR FORGOTTEN",
"subscriberName": "NAMEZ",
"subscriptionLevel": "LVLZ",
"supportTeam": "THEES PEEOPLE FED AN CARE 4 ME, THEY VRY VRY GUD PPL",
"thankYou": "THANK U",
"translationDesc": "2 R COMMUNITY HOO TRANZLATE!",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "U HAVIN PROBLERMZ SEEUN TINY SCRIENZ?",
"cannotSeeOnMobile2": "TRY SCROLLIN TEH TABLEZ SIDEWAYZ",
"clone": "COPYZ",
"cloneConfirm": "R U SURE U WANTZ ME TO COPYZ DIS SERVR? I WIAL BEH GON AH WHILE...",
"cpuCores": "NUMBR OV HAMSTUR WHEELZ",
"cpuCurFreq": "HAMSTUR(CPU) SPEEDZ RIGHT NAOW",
"cpuMaxFreq": "HAMSTUR(CPU) OMGLIMITED SPEED",
@ -169,6 +170,7 @@
"eulaAgree": "DOZ HOOMAN AGWEE",
"eulaMsg": "U MUST SAY YESH. COPY OV TEH MOJANG EULA IZ LINKD UNDR DIS MESAGE.",
"eulaTitle": "SAYZ YESH TWOO TEH LEGAL-WEEGALS",
"fileTooLarge": "SOZ, FISH TOO BIGZ.",
"hereIsTheError": "HER IZ TEH OOF",
"internet": "WE HAS DETECTD TEH BIG BOX RUNNIN CRAFTY HAS NO CONNECSHUN 2 TEH INTERNET. HOOMAN CONNECSHUNS 2 TEH SERVR CUD BE LIMITD.",
"no-file": "I HUNT BUT CANT SEEM 2 LOCATE TEH REQUESTD FISH, DOUBLE CHECK TEH SCENT. DOEZ I HAS PROPR PERMISHUNS?",
@ -253,7 +255,7 @@
"compress": "MAK BAKUP SMOL",
"confirm": "YIS",
"confirmDelete": "R U SURE U WANTZ ME TO EATZ DIS BAKUP? WIAL BEH LOZT FOREVR (LONGIR THAN KITTEHZ NAPZ)",
"confirmRestore": "R U SURE U WANTS 2 RESTORE FRUM DIS BAKUP. ALL CURRENT SERVR FISHZ WILL BE EATZ AN WILL BE UNRECOVERABLE.",
"confirmRestore": "R U SURE U WANTZ 2 RESTORE FRUM DIS BAKUP. ALL CURRENT SERVR FISHZ WILL BE EATZ AN WILL BE UNRECOVERABLE.",
"currentBackups": "CURRENT STASH OV BAKUPS",
"delete": "MAK GONE",
"destroyBackup": "EAT BAKUP \" + file_to_del + \"?",
@ -268,6 +270,7 @@
"restore": "RESTOR",
"restoring": "RESTORIN BAKUP. DIS CUD TAEK WHILE. PLZ BE PATIENT.",
"save": "DUN",
"shutdown": "SLEEPY SERVR WEN MAK BAKAUPZ?",
"size": "HOW BIGZ",
"storageLocation": "SHINY STASH OV HINGZ",
"storageLocationDesc": "WER DO U WANTS 2 STASH BAKUPS?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "R U SURE U WANTS ME 2 EAT DIS SERVR? AFTER I EATS TEHRE IZ NO GO BAK...",
"exeUpdateURL": "SERVER EGGS-CUTA-BLE UPDATE DIRECT URL",
"exeUpdateURLDesc": "FAST URL TO GET NEW FISH TO UPDATZ SERVR (MANY CAT GO DIS PETH, VERY DIRCT).",
"javaNoChange": "I WILL NO REPLACE JAFAR",
"javaVersion": "USE DIFFERENTZ JAFAR VERSHUN",
"javaVersionDesc": "PLZ MAK SHOOR, YOUR JAFAR PETH IN 'EGGS-CUTE-ABLE CMD' ISH COVERD INZ QUOTEZ (default 'java' variable excluded)",
"noDelete": "NO NO NO, PLS GO BAK",
"noDeleteFiles": "NO, JST EAT TEH PANELZ",
"removeOldLogsAfter": "BURRY OLD LOGZ AFTER",
@ -368,6 +374,7 @@
"rename": "NAYM FISH",
"renameItemQuestion": "WHAT SHOULD TEH NEW NAYM BE?",
"save": "DUN",
"size": "MAK EDITOR UUGE!",
"stayHere": "U MUST STAY HERE, PLZ DNT GO!",
"unsupportedLanguage": "WARNING: DIS NO BE SUMTIN I CAN READZ (FILE TYP BADZ)",
"unzip": "MAK UNSMOL",

View File

@ -40,12 +40,12 @@
"pageDescription": "Bez šiem cilvēkiem, jums nebūtu Crafty",
"pageTitle": "Pateicības",
"patreonDesc": "mūsu Patreon / Ko-fi atbalstītājiem!",
"subscriptionLevel": "Līmenis",
"subscriberName": "Vārds",
"patreonOther": "Cits",
"patreonSupporter": "Patreon / Ko-fi Atbalstītāji",
"patreonUpdate": "Pēdējais Atjaunojums:",
"retiredStaff": "Atvaļinātie Komandas Biedri",
"subscriberName": "Vārds",
"subscriptionLevel": "Līmenis",
"supportTeam": "Atbalsta un Dokumentācijas Komanda",
"thankYou": "PALDIES",
"translationDesc": "mūsu kopienai, kas tulkoja!",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "Neredzi visu uz mobīlā?",
"cannotSeeOnMobile2": "Pamēģini pavilkt tabulu uz sānu.",
"clone": "Klonēt",
"cloneConfirm": "Vai tiešām vēlaties klonēt šo serveri? Šis process var aizņemt kādu laiku.",
"cpuCores": "CPU Kodoli",
"cpuCurFreq": "CPU Pašreizējā Frekvence",
"cpuMaxFreq": "CPU Maksimālā Frekvence",
@ -169,6 +170,7 @@
"eulaAgree": "Vai jūs piekrītat?",
"eulaMsg": "Jums ir jāpiekrīt EULA. Kopija no Mojang EULA ir saitēta zem šī ziņojuma.",
"eulaTitle": "Piekrist EULA",
"fileTooLarge": "Augšupielāde neizdevās. Faila augšupielāde ir pārāk liela. Sazinies ar sistēmas administratoru priekš palīdzības.",
"hereIsTheError": "Rekur ir kļūda",
"internet": "Mēs esam noteikuši ka šai ierīcei, uz kuras iet Crafty nav internet. Client connections to the server may be limited.",
"no-file": "Mēs nevaram atrast pieprasīto failu. Pārbaudiet faila ceļu. Vai Crafty ir vajadzīgās piekļuves?",
@ -268,6 +270,7 @@
"restore": "Atjaunot",
"restoring": "Atjauno dublējumu. Tas var aizņemt kādi laiku. Esiet pacietīgs.",
"save": "Saglabāt",
"shutdown": "Apturēt serveri dublējumkopijas laikā",
"size": "Lielums",
"storageLocation": "Krātuves Vieta",
"storageLocationDesc": "Kur jūs vēlaties saglabāt dublējumus?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "Vai tiešām vēlies izdzēst šo serveri? Pēc šī vairs nevar atgriezties...",
"exeUpdateURL": "Servera Izpildāmā Faila Atjaunošanas URL",
"exeUpdateURLDesc": "Tiešās Lejupielādes URL priekš atjauninājumiem.",
"javaNoChange": "Nepārrakstīt",
"javaVersion": "Pārrakstīt esošo Java Versiju",
"javaVersionDesc": "Ja grasies pārrakstīt Javu, Pārliecienies ka tavs esošais Java ceļš iekš 'izpildes komanda' atrodas pēdiņās (atskaitot noklusēto 'java' mainīgo)",
"noDelete": "Nē, iet atpakaļ",
"noDeleteFiles": "Nē, tikai noņemt no paneļa",
"removeOldLogsAfter": "Noņemt Vecos Log Failus Pēc",
@ -368,6 +374,7 @@
"rename": "Pārsaukt",
"renameItemQuestion": "Kādam būtu jābūt jaunajam nosaukumam?",
"save": "Saglabāt",
"size": "Mainīt Redaktora Lielumu",
"stayHere": "NEATSTĀJIET ŠO LAPU!",
"unsupportedLanguage": "Uzmanību: Šis nav atbalstīts faila veids",
"unzip": "Izvilkt",

View File

@ -40,12 +40,12 @@
"pageDescription": "Zonder deze mensen, zou je Crafty niet hebben",
"pageTitle": "Credits",
"patreonDesc": "aan onze Patreon / Ko-fi supporters!",
"subscriptionLevel": "Niveau",
"subscriberName": "Naam",
"patreonOther": "Andere",
"patreonSupporter": "Patreon / Ko-fi supporters",
"patreonUpdate": "Laatste Update:",
"retiredStaff": "Gepensioneerd personeel",
"subscriberName": "Naam",
"subscriptionLevel": "Niveau",
"supportTeam": "Ondersteunings- en documentatieteam",
"thankYou": "DANK JE WEL",
"translationDesc": "aan onze gemeenschap die vertaalt!",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "Zie je niet alles op je GSM?",
"cannotSeeOnMobile2": "Probeer de tabel zijwaarts te scrollen.",
"clone": "Kloon",
"cloneConfirm": "Weet u zeker dat u deze server wilt klonen? Dit proces kan even duren.",
"cpuCores": "CPU Cores",
"cpuCurFreq": "CPU huidige kloksnelheid",
"cpuMaxFreq": "CPU maximale kloksnelheid",
@ -169,6 +170,7 @@
"eulaAgree": "Bent u het eens?",
"eulaMsg": "U moet akkoord gaan met de EULA. Een kopie van de Mojang EULA is gelinkt onder dit bericht.",
"eulaTitle": "Akkoord gaan met EULA",
"fileTooLarge": "Uploaden mislukt. Bestand uploaden te groot. Neem contact op met de systeembeheerder voor assistentie",
"hereIsTheError": "Hier is de fout",
"internet": "We hebben gedetecteerd dat de machine waarop Crafty draait geen verbinding met internet heeft. Clientverbindingen met de server kunnen beperkt zijn.",
"no-file": "We kunnen het gevraagde bestand niet vinden. Controleer het pad. Heeft Crafty de juiste permissies?",
@ -268,6 +270,7 @@
"restore": "Herstellen",
"restoring": "Back-up herstellen. Dit kan een tijdje duren. Even geduld alstublieft.",
"save": "Opslaan",
"shutdown": "Sluit de server af voor de duur van de backup",
"size": "Grootte",
"storageLocation": "Opslaglocatie",
"storageLocationDesc": "Waar wil je back-ups opslaan?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "Weet u zeker dat u deze server wilt verwijderen? Deze actie is onomkeerbaar...",
"exeUpdateURL": "Uitvoerbare server-update-URL",
"exeUpdateURLDesc": "Directe download-URL voor updates.",
"javaNoChange": "Niet overschrijven",
"javaVersion": "Huidige Java versie overschrijven",
"javaVersionDesc": "Als je Java gaat overschrijven. Zorg ervoor dat uw huidige Java pad in 'execution command' tussen aanhalingstekens staat (standaard 'java' variabele uitgesloten)",
"noDelete": "Nee, ga terug",
"noDeleteFiles": "Nee, gewoon uit het paneel verwijderen",
"removeOldLogsAfter": "Oude logboeken verwijderen na",
@ -368,6 +374,7 @@
"rename": "Hernoemen",
"renameItemQuestion": "Wat moet de nieuwe naam worden?",
"save": "Opslaan",
"size": "Verander Editor Grootte",
"stayHere": "VERLAAT DEZE PAGINA NIET!",
"unsupportedLanguage": "Waarschuwing: dit is geen ondersteund bestandstype",
"unzip": "Uitpakken",

540
app/translations/pt_BR.json Normal file
View File

@ -0,0 +1,540 @@
{
"404": {
"contact": "Contate o suporte do Crafty Control através do Discord",
"notFound": "Página não encontrada",
"unableToFind": "Fomos incapazes de encontrar a página que você está procurando. Por favor, tente novamente ou volte e atualize."
},
"accessDenied": {
"accessDenied": "Acesso Negado",
"contact": "Contate o suporte do Crafty Control através do Discord",
"contactAdmin": "Contate o Administrador do seu servidor para acessar este recurso. Ou se você acha que deveria ter acesso a este recurso, contate o suporte.",
"noAccess": "Você não tem acesso a este recurso"
},
"apiKeys": {
"apiKeys": "Chaves de API",
"auth": "Autorizado?",
"buttons": "Botões",
"config": "Config",
"crafty": "Crafty: ",
"created": "Criado",
"createNew": "Criar novo Token de API",
"deleteKeyConfirmation": "Deseja deletar esta Chave de API?. Esta ação não pode ser desfeita.",
"deleteKeyConfirmationTitle": "Remover Chave de API ${keyId}?",
"getToken": "Pegar um Token",
"name": "Nome",
"nameDesc": "Como você gostaria de chamar este Token de API?",
"no": "Não",
"pageTitle": "Editar Chaves de API do usuário",
"permName": "Nome da Permissão",
"perms": "Permissões",
"server": "Servidor: ",
"superUser": "Super Usuário",
"yes": "Sim"
},
"base": {
"doesNotWorkWithoutJavascript": "<strong>Aviso: </strong>Crafty não funciona propriamente quando JavaScript não está habilitado!"
},
"credits": {
"developmentTeam": "Equipe de Desenvolvimento",
"hugeDesc": "Um grande",
"pageDescription": "Sem estas pessoas, não teríamos o Crafty",
"pageTitle": "Creditos",
"patreonDesc": "aos nossos apoiadores do Patreon e Ko-fi!",
"patreonOther": "Outro",
"patreonSupporter": "Apoiadores do Patreon e Ko-fi",
"patreonUpdate": "Última Atualização:",
"retiredStaff": "Staff Aposentada",
"subscriberName": "Nome",
"subscriptionLevel": "Nível",
"supportTeam": "Equipe de Documentação e Suporte",
"thankYou": "OBRIGADO",
"translationDesc": "à nossa comunidade que traduz!",
"translationName": "Nome",
"translationTitle": "Tradução de Idioma",
"translator": "Tradutores"
},
"dashboard": {
"actions": "Ações",
"allServers": "Todos os Servidores",
"avg": "Média",
"backups": "Backups",
"bePatientClone": "Por favor aguarde enquanto clonamos seu servidor.<br /> Esta tela atualizará em alguns instantes",
"bePatientRestart": "Por favor aguarde enquanto reiniciamos seu servidor.<br /> Esta tela atualizará em alguns instantes",
"bePatientStart": "Por favor aguarde enquanto iniciamos seu servidor.<br /> Esta tela atualizará em alguns instantes",
"bePatientStop": "Por favor aguarde enquanto paramos seu servidor.<br /> Esta tela atualizará em alguns instantes",
"cannotSee": "Não está vendo tudo?",
"cannotSeeOnMobile": "Não está vendo tudo no dispositivo móvel?",
"cannotSeeOnMobile2": "Tente rolar a tela para o lado.",
"clone": "Clonar",
"cloneConfirm": "Tem certeza de que deseja clonar este servidor? Esse processo pode demorar um tempo.",
"cpuCores": "Núcleos do Processador",
"cpuCurFreq": "Clock Atual do Processador",
"cpuMaxFreq": "Clock Máximo do Processador",
"cpuUsage": "Uso do Processador",
"crashed": "Crashou",
"dashboard": "Painel de Controle",
"delay-explained": "O serviço/agente iniciou recentemente e está atrasando o início da instância do servidor de minecraft",
"host": "Host",
"kill": "Matar Processo",
"killing": "Matando processo...",
"lastBackup": "Último:",
"max": "Max",
"memUsage": "Uso de Memória",
"motd": "Mensagem do Dia",
"newServer": "Criar Novo Servidor",
"nextBackup": "Próximo:",
"no-servers": "Não há servidores no momento. Para começar, clique",
"offline": "Offline",
"online": "Online",
"players": "Jogadores",
"restart": "Reiniciar",
"sendingCommand": "Enviando seu comando",
"server": "Servidor",
"servers": "Servidores",
"size": "Tamanho do Diretório do Servidor",
"start": "Iniciar",
"starting": "Início-Atrasado",
"status": "Status",
"stop": "Parar",
"version": "Versão",
"welcome": "Bem-vindo ao Crafty Controller"
},
"datatables": {
"i18n": {
"aria": {
"sortAscending": ": ative para ordenar a coluna de forma ascendente",
"sortDescending": ": ative para ordenar coluna de forma descendente"
},
"buttons": {
"collection": "Coleção <span class='ui-button-icon-primary ui-icon ui-icon-triangle-1-s'/>",
"colvis": "Visibilidade da Coluna",
"colvisRestore": "Restaurar Visibilidade",
"copy": "Copiar",
"copyKeys": "Pressione ctrl ou u2318 + C para copiar os dados da tabela para a área de transferência do seu sistema.<br><br>Para cancelar, clique na mensagem ou clique esc.",
"copySuccess": {
"1": "Copiou 1 linha para a área de transferência",
"_": "Copiou %d linhas para a área de transferência"
},
"copyTitle": "Copiado para a área de transferência",
"csv": "CSV",
"excel": "Excel",
"pageLength": {
"1": "Exibir 1 linha",
"-1": "Exibir todas as linhas",
"_": "Exibir %d linhas"
},
"pdf": "PDF",
"print": "Imprimir"
},
"decimal": "",
"emptyTable": "Nenhum dado disponível na tabela",
"info": "Exibindo de _START_ a _END_ de _TOTAL_ entradas",
"infoEmpty": "Exibindo de 0 a 0 de 0 entradas",
"infoFiltered": "(filtrado de _MAX_ entradas totais)",
"infoPostFix": "",
"lengthMenu": "Exibir _MENU_ entradas",
"loadingRecords": "Carregando...",
"paginate": {
"first": "Primeira",
"last": "Última",
"next": "Próxima",
"previous": "Anterior"
},
"processing": "Processando...",
"search": "Pesquisar:",
"select": {
"cells": {
"0": "Clique em uma célula para selecioná-la",
"1": "%d célula selecionada",
"_": "%d células selecionadas"
},
"columns": {
"0": "Click on a column to select it",
"1": "%d column selected",
"_": "%d columns selected"
},
"rows": {
"0": "Clique em uma linha para selecioná-la",
"1": "%d linha selecionada",
"_": "%d linhas selecionadas"
}
},
"thousands": ",",
"zeroRecords": "Nenhum registro encontrado"
}
},
"error": {
"contact": "Contate o suporte do Crafty Control através do Discord",
"embarassing": "Oh. Bem, isso é constrangedor",
"error": "Erro!",
"eulaAgree": "Você concorda?",
"eulaMsg": "Você deve concordar com os Termos de Licença. Uma cópia dos Termos de Licença da Mojang está linkado abaixo desta mensagem.",
"eulaTitle": "Concordar com os Termos de Licença",
"fileTooLarge": "Upload falhou. Arquivo muito grande. Contato o administrador do sistema para assistência.",
"hereIsTheError": "Aqui está o erro",
"internet": "Detectamos que a máquina rodando Crafty não possui conexão com a internet. Conexões de clientes ao serviço podem ser limitadas.",
"no-file": "Não conseguimos encontrar o arquivo solicitado. Verifique o caminho do arquivo. O Crafty tem as permissões necessárias?",
"noJava": "Servidor {} falhou ao iniciar com código de erro: Detectamos que o Java não está instalado. Por favor, instale o Java e então inicie o servidor.",
"not-downloaded": "Não conseguimos encontrar seu arquivo executável. O download foi concluído? As permissões estão definidas para executável?",
"portReminder": "Detectamos que esta é a primeira vez que {} está rodando. Certifique-se de encaminhar a porta {} através do seu roteador/firewall para torná-lo acessível remotamente da internet.",
"start-error": "Servidor {} falhou ao iniciar com código de erro: {}",
"terribleFailure": "Que Falha terrível!"
},
"footer": {
"allRightsReserved": "Todos os direitos reservados",
"copyright": "Copyright",
"version": "Versão"
},
"login": {
"forgotPassword": "Esqueci a Senha",
"login": "Logar",
"password": "Senha",
"username": "Usuário"
},
"notify": {
"activityLog": "Logs de Atividade",
"backupComplete": "Backup concluído com sucesso para o servidor {}",
"backupStarted": "Backup iniciado para o servidor {}",
"downloadLogs": "Baixar Logs de Suporte?",
"finishedPreparing": "Terminamos de preparar seus logs de suporte. Por favor, clique em baixar para baixar",
"logout": "Deslogar",
"preparingLogs": " Por favor aguarde enquanto preparamos seus logs... Enviaremos uma notificação quando eles estiverem prontos. Esta ação pode demorar um tempo para grandes implementações.",
"supportLogs": "Logs de Suporte"
},
"panelConfig": {
"adminControls": "Controles de Admin",
"allowedServers": "Servidores Permitidos",
"assignedRoles": "Cargos Atribuídos",
"cancel": "Cancelar",
"clearComms": "Limpar comandos não executados",
"delete": "Deletar",
"edit": "Editar",
"enabled": "Habilitado",
"match": "Senhas devem coincidir",
"newRole": "Adicionar Novo Cargo",
"newUser": "Adicionar Novo Usuário",
"pageTitle": "Configuração do Painel",
"role": "Cargo",
"roles": "Cargos",
"roleUsers": "Usuários com o Cargo",
"save": "Salvar",
"superConfirm": "Proceda apenas se desejar que este usuário tenha acesso a TUDO (todas as contas de usuário, servidores, configurações do painel, etc.). Eles podem até mesmo revogar seus direitos de Super Usuário.",
"superConfirmTitle": "Habilitar Super Usuário? Tem certeza?",
"user": "Usuário",
"users": "Usuários"
},
"rolesConfig": {
"config": "Configurações de Cargo",
"configDesc": "Aqui você pode mudar a configuração do seu cargo",
"configUpdate": "Última vez atualizado: ",
"created": "Criado: ",
"delRole": "Deletar Cargo",
"doesNotExist": "Você não pode deletar algo que ainda não existe",
"pageTitle": "Editar Cargo",
"pageTitleNew": "Novo Cargo",
"permAccess": "Acesso?",
"permName": "Nome da Permissão",
"permsServer": "Permissões que este cargo tem para estes servidores especificados",
"roleConfigArea": "Área de Configuração do Cargo",
"roleDesc": "Como você gostaria de chamar este cargo?",
"roleName": "Nome do Cargo: ",
"rolePerms": "Permissões do Cargo",
"roleServers": "Servidores Permitidos",
"roleTitle": "Configurações dos Cargos",
"roleUserName": "Nome de Usuário",
"roleUsers": "Usuários com o Cargo: ",
"serverAccess": "Acesso?",
"serverName": "Nome do Servidor",
"serversDesc": "Servidores que este cargo tem permissão para acessar"
},
"serverBackups": {
"backupAtMidnight": "Backup automático à meia-noite?",
"backupNow": "Fazer backup agora!",
"backupTask": "Uma tarefa de backup foi iniciada.",
"cancel": "Cancelar",
"clickExclude": "Clique para selecionar Exclusões",
"compress": "Comprimir Backup",
"confirm": "Confirmar",
"confirmDelete": "Deseja deletar este backup? Esta ação não pode ser desfeita.",
"confirmRestore": "Tem certeza de que deseja restaurar a partir deste backup. Todos os arquivos atuais do servidor serão mudados para o estado de backup e serão irrecuperáveis.",
"currentBackups": "Backups atuais",
"delete": "Deletar",
"destroyBackup": "Destruir backup \" + file_to_del + \"?",
"download": "Baixar",
"excludedBackups": "Caminhos Excluídos: ",
"excludedChoose": "Escolha os caminhos que você deseja excluir dos seus backups",
"exclusionsTitle": "Exclusões de Backup",
"maxBackups": "Número máximo de backups",
"maxBackupsDesc": "Crafty não armazenará mais backups que o especificado, deletando o mais antigo (insira 0 para manter todos)",
"options": "Opções",
"path": "Caminho",
"restore": "Restaurar",
"restoring": "Restaurando Backup. Isso pode demorar um tempo. Por favor aguarde.",
"save": "Salvar",
"shutdown": "Desligar o servidor durante o backup",
"size": "Tamanho",
"storageLocation": "Local de Armazenamento",
"storageLocationDesc": "Onde você deseja armazenar backups?"
},
"serverConfig": {
"bePatientDelete": "Por favor aguarde enquanto removemos seu servidor do painel Crafty. Esta tela fechará em alguns instantes.",
"bePatientDeleteFiles": "Por favor aguarde enquanto removemos seu servidor do painel Crafty e deletamos seus arquivos. Esta tela fechará em alguns instantes.",
"bePatientUpdate": "Por favor aguarde enquanto atualizamos o servidor. O tempo de download pode variar dependendo da velocidade da sua internet.<br /> Esta tela atualizará em alguns instantes.",
"cancel": "Cancelar",
"crashTime": "Tempo Limite de Crash",
"crashTimeDesc": "Quanto tempo devemos esperar antes de considerar que seu servidor crashou?",
"deleteFilesQuestion": "Deletar arquivos do servidor da máquina?",
"deleteFilesQuestionMessage": "Deseja que Crafty delete todos os arquivos da máquina host? <br><br><strong>Isso inclui backups de servidor.</strong>",
"deleteServer": "Deletar Servidor",
"deleteServerQuestion": "Deletar Servidor?",
"deleteServerQuestionMessage": "Tem certeza de que deseja deletar esta servidor? Esta ação não pode ser desfeita.",
"exeUpdateURL": "URL de Atualização do Executável do Servidor",
"exeUpdateURLDesc": "URL de Download Direto para atualizações.",
"javaNoChange": "Não sobrepor",
"javaVersion": "Sobrepor versão atual do Java",
"javaVersionDesc": "Se for sobrepor o Java, certifique-se de que seu Java atual em 'Comando de Execução do Servidor' está envolto em aspas simples(' ') (variável 'java' padrão excluída)",
"noDelete": "Não! Volta.",
"noDeleteFiles": "Não, só remova do painel",
"removeOldLogsAfter": "Remova logs antigos depois",
"removeOldLogsAfterDesc": "Quantos dias um arquivo de logs precisa ter para ser considerado antigo? (0 para desabilitar)",
"save": "Salvar",
"sendingDelete": "Deletando Servidor",
"sendingRequest": "Enviando sua requisição...",
"serverAutoStart": "Início Automático do Servidor",
"serverAutostartDelay": "Atraso de Início Automático de Servidor",
"serverAutostartDelayDesc": "Atraso antes do início automático (Se habilitado abaixo)",
"serverCrashDetection": "Detecção de Crash do Servidor",
"serverExecutable": "Executável do Servidor",
"serverExecutableDesc": "O arquivo executável do servidor",
"serverExecutionCommand": "Comando de Execução do Servidor",
"serverExecutionCommandDesc": "O que será lançado em um terminal oculto",
"serverIP": "IP do Servidor",
"serverIPDesc": "IP de acesso ao seu servidor em jogo (Try a real ip instead of 127.0.0.1 if you have issues)",
"serverLogLocation": "Local do Log do Servidor",
"serverLogLocationDesc": "Caminho para o arquivo de log",
"serverName": "Nome do Servidor",
"serverNameDesc": "Como deseja chamar este servidor?",
"serverPath": "Diretório principal do servidor",
"serverPathDesc": "Caminho completo (não incluindo o executável)",
"serverPort": "Porta do Servidor",
"serverPortDesc": "Porta de acesso do seu servidor em jogo",
"serverStopCommand": "Comando de Parada do Servidor",
"serverStopCommandDesc": "Comando enviado ao programa para pará-lo",
"stopBeforeDeleting": "Por favor pare o servidor antes de deletá-lo",
"update": "Atualizar Executável",
"yesDelete": "Sim, delete.",
"yesDeleteFiles": "Sim, delete os arquivos."
},
"serverConfigHelp": {
"desc": "Aqui você pode mudar a configuração do seu servidor",
"perms": [
"Recomenda-se que <code>NÃO</code> mude os caminhos de um servidor gerenciado pelo Crafty.",
"Mudar caminhos <code>PODE</code> quebrar coisas, especialmente em sistemos similares ao Linux onde permissões de arquivos são mais restritas.",
"<br /><br/>",
"Se sentir que precisa mudar o local de um servidor, você pode, contanto que dê ao \"crafty\" as permissões de usuário para ler e escrever no caminho do servidor.",
"<br />",
"<br />",
"No Linux é melhor fazer isso executando o seguinte:<br />",
"<code>",
" sudo chown crafty:crafty /caminho/para/o/servidor -R<br />",
" sudo chmod 2775 /caminho/para/o/servidor -R<br />",
"</code>"
],
"title": "Área de Configuração do Servidor"
},
"serverDetails": {
"backup": "Backup",
"config": "Config",
"files": "Arquivos",
"logs": "Logs",
"playerControls": "Gerenciar Jogadores",
"schedule": "Agendar",
"serverDetails": "Detalhes do Servidor",
"terminal": "Terminal"
},
"serverFiles": {
"clickUpload": "Clique aqui para selecionar seus arquivos",
"close": "Fechar",
"createDir": "Criar diretório",
"createDirQuestion": "Qual nome deseja dar ao diretório?",
"createFile": "Criar arquivos",
"createFileQuestion": "Qual nome deseja dar ao arquivo?",
"default": "Padrão",
"delete": "Deletar",
"deleteItemQuestion": "Tem certeza de que deseja deletar \" + name + \"?",
"deleteItemQuestionMessage": "Você está deletando \\\"\" + path + \"\\\"!<br/><br/>Esta ação será irreversível e o arquivo será perdido para sempre!",
"download": "Baixar",
"editingFile": "Editando arquivo",
"error": "Erro ao conseguir arquivos",
"fileReadError": "Erro de leitura de arquivo",
"files": "Arquivos",
"keybindings": "Teclas",
"loadingRecords": "Carregando Arquivos...",
"noDelete": "Não",
"noscript": "O gerenciador de arquivos não funciona sem JavaScript",
"rename": "Renomear",
"renameItemQuestion": "Qual será o novo nome?",
"save": "Salvar",
"size": "Mudar tamanho do editor",
"stayHere": "NÃO DEIXE ESTA PÁGINA!",
"unsupportedLanguage": "Warning: This is not a supported file type",
"unzip": "Extrair",
"upload": "Enviar Arquivo",
"uploadTitle": "Enviar Arquivos para: ",
"waitUpload": "Por favor aguarde enquanto enviamos seus arquivos... Esta ação pode demorar um tempo.",
"yesDelete": "Sim, eu entendo as consequências"
},
"serverPlayerManagement": {
"bannedPlayers": "Jogadores Banidos",
"loadingBannedPlayers": "Carregando Jogadores Banidos",
"players": "Jogadores"
},
"serverScheduleConfig": {
"backup": "Backup do Servidor",
"basic": "Básico",
"children": "Tarefas Filhas Anexadas: ",
"command": "Comando",
"command-explain": "Qual comando deseja que seja executado? Não inclua a '/'",
"cron": "Cronometrada",
"cron-explain": "Insira sua string cron -- NOTA: 0 = Segunda na última opção.",
"custom": "Comando Personalizado",
"days": "Dias",
"enabled": "Habilitado",
"hours": "Horas",
"interval": "Intervalo",
"interval-explain": "Com que frequência deseja que este agendamento seja executado?",
"minutes": "Minutos",
"offset": "Deslocamento de Atraso",
"offset-explain": "Quanto tempo deve ser esperado para executar isto após executar a primeira tarefa? (Seconds)",
"one-time": "Deletar após execução",
"parent": "Selecionar um agendamento pai",
"parent-explain": "Qual agendamento deve provocar este?",
"reaction": "Reação",
"restart": "Reiniciar Servidor",
"start": "Iniciar Servidor",
"stop": "Desligar Servidor",
"time": "Horário",
"time-explain": "Em que horário deseja que o agendamento seja executado?"
},
"serverSchedules": {
"areYouSure": "Deletar Tarefa Agendada?",
"cancel": "Cancelar",
"cannotSee": "Não está vendo tudo?",
"cannotSeeOnMobile": "Tente clicar em uma tarefa agendada para detalhes completos.",
"confirm": "Confirmar",
"confirmDelete": "Deseja deletar esta tarefa agendada? Esta ação não pode ser desfeita."
},
"serverStats": {
"cpuUsage": "Uso do Processador",
"description": "Descrição",
"errorCalculatingUptime": "Erro ao Calcular Tempo de Atividade",
"memUsage": "Uso da Memória",
"offline": "Offline",
"online": "Online",
"players": "Jogadores",
"serverStarted": "Servidor Iniciado",
"serverStatus": "Status do Servidor",
"serverTime": "Horário UTC",
"serverTimeZone": "Fusorário do Servidor",
"serverUptime": "Tempo de Atividade do Servidor",
"starting": "Início-Atrasado",
"unableToConnect": "Incapaz de Conectar",
"version": "Versão"
},
"serverTerm": {
"commandInput": "Insira seu comando",
"delay-explained": "O serviço/agente iniciou recentemente e está atrasando o início da instância do servidor de minecraft",
"downloading": "Baixando...",
"restart": "Reiniciar",
"sendCommand": "Enviar comando",
"start": "Iniciar",
"starting": "Início-Atrasado",
"stop": "Parar",
"stopScroll": "Parar Rolagem Automática",
"updating": "Atualizando..."
},
"serverWizard": {
"absoluteServerPath": "Caminho absoluto para o servidor",
"absoluteZipPath": "Caminho absoluto para o servidor",
"addRole": "Adicionar servidor a cargo(s) existente(s)",
"autoCreate": "Se nenhum estiver selecionado Crafty fará um!",
"bePatient": "Por favor aguarde nós ' + (importing ? 'importamos' : 'download') + ' the server",
"buildServer": "Construir Servidor!",
"clickRoot": "Clique aqui para selecionar diretório raiz",
"close": "Fechar",
"defaultPort": "25565 = padrão",
"downloading": "Baixando Servidor...",
"explainRoot": "Por favor clique no botão abaixo para selecionar o diretório raiz do seu servidor dentro do arquivo",
"importing": "Importando Servidor...",
"importServer": "Importar um servidor existente",
"importServerButton": "Importar Servidor!",
"importZip": "Importar de um Arquivo Zip",
"maxMem": "Memória Máxima",
"minMem": "Memória Mínima",
"myNewServer": "Meu Novo Servidor",
"newServer": "Criar Novo Servidor",
"quickSettings": "Configurações Rápidas",
"quickSettingsDescription": "Não se preocupe. Você pode alterar isso depois.",
"resetForm": "Redefinir Formulário",
"save": "Salvar",
"selectRole": "Selecionar Cargo(s)",
"selectRoot": "Selecionar Diretório Raiz de Arquivo",
"selectType": "Selecione um Tipo",
"selectVersion": "Selecione um Versão",
"selectZipDir": "Selecione o diretório no arquivo de onde deseja extrair os arquivos",
"serverJar": "Arquivo Executável do Servidor",
"serverName": "Nome do Servidor",
"serverPath": "Arquivo do Servidor",
"serverPort": "Porta do Servidor",
"serverType": "Tipo de Servidor",
"serverVersion": "Versão do Servidor",
"sizeInGB": "Tamanho em GB",
"zipPath": "Caminho do Servidor"
},
"sidebar": {
"contribute": "Contribuir",
"credits": "Créditos",
"dashboard": "Painel de Controle",
"documentation": "Documentação",
"navigation": "Navegação",
"newServer": "Criar Novo Servidor",
"servers": "Servidores"
},
"userConfig": {
"apiKey": "Chaves de API",
"auth": "Autorizado? ",
"config": "Config",
"configArea": "Área de Configuração do Usuário",
"configAreaDesc": "Aqui você pode mudar todas as configurações do seu usuário",
"confirmDelete": "Tem certeza de que deseja deletar este usuário? Esta ação é irreversível.",
"craftyPermDesc": "Permissões do Crafty que este usuário tem ",
"craftyPerms": "Permissões do Crafty: ",
"created": "Criado: ",
"deleteUser": "Deletar Usuário: ",
"deleteUserB": "Deletar Usuário",
"delSuper": "Você não pode deletar um Super Usuário",
"enabled": "Habilitado",
"gravDesc": "Este e-mail é para uso exclusivo com Gravatar™. Crafty não irá, sob quaisquer circunstâncias, fazer uso deste e-mail para qualquer coisa além de seu Gravatar™",
"gravEmail": "E-mail Gravatar™",
"lastIP": "Último IP: ",
"lastLogin": "Último Login: ",
"lastUpdate": "Última Atualização: ",
"leaveBlank": "Para editar o usuário sem alterar a senha, deixe em branco.",
"member": "Membro?",
"notExist": "Você não pode deletar algo que não existe!",
"pageTitle": "Editar Usuário",
"pageTitleNew": "Criar Usuário",
"password": "Nova Senha",
"permName": "Nome da Permissão",
"repeat": "Repetir a Senha",
"roleName": "Nome do Cargo",
"super": "Super Usuário",
"userLang": "Idioma do Usuário",
"userName": "Nome do Usuário",
"userNameDesc": "Como deseja chamar este usuário?",
"userRoles": "Cargos do Usuário",
"userRolesDesc": "Cargos que este usuário possui.",
"userSettings": "Configurações do Usuário",
"uses": "Número de Usos Permitidos (-1==Sem Limite)"
}
}

View File

@ -40,12 +40,12 @@
"pageDescription": "没有这些人,就没有 Crafty",
"pageTitle": "鸣谢",
"patreonDesc": "我们的 Patreon / Ko-fi 支持者!",
"subscriptionLevel": "等级",
"subscriberName": "名称",
"patreonOther": "其他",
"patreonSupporter": "Patreon / Ko-fi 支持者",
"patreonUpdate": "上次更新:",
"retiredStaff": "退休员工",
"subscriberName": "名称",
"subscriptionLevel": "等级",
"supportTeam": "支持与文档团队",
"thankYou": "感谢",
"translationDesc": "帮助我们翻译的社区!",
@ -66,6 +66,7 @@
"cannotSeeOnMobile": "在移动设备上什么都看不到?",
"cannotSeeOnMobile2": "尝试横向滚动表格。",
"clone": "克隆",
"cloneConfirm": "您确定要克隆该服务器吗?此过程将需要一点时间。",
"cpuCores": "CPU 核心",
"cpuCurFreq": "当前 CPU 时钟",
"cpuMaxFreq": "最大 CPU 时钟",
@ -169,6 +170,7 @@
"eulaAgree": "你同意吗?",
"eulaMsg": "你必须同意最终用户许可协议EULA。一份 Mojang EULA 副本的链接在此消息下方。",
"eulaTitle": "同意最终用户许可协议EULA",
"fileTooLarge": "上传失败。上传的文件过大。联系系统管理员以获取协助。",
"hereIsTheError": "错误如下",
"internet": "我们检测到运行 Crafty 的设备没有网络连接。客户端到服务器的连接可能受限。",
"no-file": "我们似乎找不到请求的文件。请再次检查路径。Crafty 是否拥有了正确的权限?",
@ -268,6 +270,7 @@
"restore": "恢复",
"restoring": "正在恢复备份。这需要一点时间。请耐心等待。",
"save": "保存",
"shutdown": "在备份期间停止服务器",
"size": "大小",
"storageLocation": "存储位置",
"storageLocationDesc": "您想要在哪里存储备份?"
@ -286,6 +289,9 @@
"deleteServerQuestionMessage": "您确定要删除此服务器吗?在此之后将无法撤销……",
"exeUpdateURL": "服务器可执行文件更新地址",
"exeUpdateURLDesc": "用于下载更新的直接链接。",
"javaNoChange": "不覆盖",
"javaVersion": "覆盖当前的 Java 版本",
"javaVersionDesc": "如果你要覆盖 Java请确保你当前“运行命令”中的 Java 路径括在了引号中不包括默认的“java”变量",
"noDelete": "否,返回",
"noDeleteFiles": "否,只从面板中移除",
"removeOldLogsAfter": "此时间后删除旧日志",
@ -368,6 +374,7 @@
"rename": "重命名",
"renameItemQuestion": "新名称应该是什么?",
"save": "保存",
"size": "调整编辑器大小",
"stayHere": "请不要离开此页面!",
"unsupportedLanguage": "警告:这不是一个受支持的文件类型",
"unzip": "解压",