mirror of https://github.com/Aidaho12/haproxy-wi
parent
782544c85d
commit
6adba6cc37
|
@ -62,6 +62,19 @@ def subprocess_execute(cmd):
|
|||
return output, stderr
|
||||
|
||||
|
||||
def subprocess_execute_with_rc(cmd):
|
||||
import subprocess
|
||||
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True)
|
||||
stdout, stderr = p.communicate()
|
||||
output = stdout.splitlines()
|
||||
rc = p.returncode
|
||||
|
||||
return_out = {'output': output, 'error': stderr, 'rc': rc}
|
||||
|
||||
return return_out
|
||||
|
||||
|
||||
def is_file_exists(server_ip: str, file: str) -> bool:
|
||||
cmd = [f'[ -f {file} ] && echo yes || echo no']
|
||||
|
||||
|
@ -110,8 +123,8 @@ def get_system_info(server_ip: str) -> str:
|
|||
except Exception as e:
|
||||
raise e
|
||||
|
||||
if 'command not found' in sys_info_returned:
|
||||
raise Exception(f' You should install lshw on the server {server_ip}. Update System info after installation.')
|
||||
if 'not found' in sys_info_returned:
|
||||
raise Exception(f'You should install lshw on the server {server_ip}. Update System info after installation.')
|
||||
|
||||
try:
|
||||
os_info = ssh_command(server_ip, command1)
|
||||
|
|
|
@ -95,6 +95,10 @@ def upload_ssh_key(name: str, user_group: str, key: str) -> bool:
|
|||
print('error: nice try')
|
||||
return False
|
||||
|
||||
if name == '':
|
||||
print('error: please select credentials first')
|
||||
return False
|
||||
|
||||
try:
|
||||
key = paramiko.pkey.load_private_key(key)
|
||||
except Exception as e:
|
||||
|
|
|
@ -276,6 +276,7 @@ def get_stat_page(server_ip: str, service: str) -> None:
|
|||
|
||||
data = response.content
|
||||
if service == 'nginx':
|
||||
lang = roxywi_common.get_user_lang()
|
||||
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
|
||||
template = env.get_template('ajax/nginx_stats.html')
|
||||
|
||||
|
@ -287,7 +288,7 @@ def get_stat_page(server_ip: str, service: str) -> None:
|
|||
h = (out1,)
|
||||
servers_with_status.append(h)
|
||||
|
||||
template = template.render(out=servers_with_status)
|
||||
template = template.render(out=servers_with_status, lang=lang)
|
||||
print(template)
|
||||
else:
|
||||
print(data.decode('utf-8'))
|
||||
|
|
|
@ -10,21 +10,22 @@ from modules.server.ssh import return_ssh_keys_path
|
|||
form = common.form
|
||||
|
||||
|
||||
def show_installation_output(error: str, output: str, service: str) -> bool:
|
||||
def show_installation_output(error: str, output: str, service: str, rc=0) -> bool:
|
||||
if error and "WARNING" not in error:
|
||||
roxywi_common.logging('Roxy-WI server', error, roxywi=1)
|
||||
print('error: ' + error)
|
||||
return False
|
||||
else:
|
||||
for line in output:
|
||||
if any(s in line for s in ("Traceback", "FAILED", "error", "ERROR", "UNREACHABLE")):
|
||||
try:
|
||||
correct_out = line.split('=>')
|
||||
print(f'error: {correct_out[1]}')
|
||||
break
|
||||
except Exception:
|
||||
print(output)
|
||||
break
|
||||
if rc != 0:
|
||||
for line in output:
|
||||
if any(s in line for s in ("Traceback", "FAILED", "error", "ERROR", "UNREACHABLE")):
|
||||
try:
|
||||
correct_out = line.split('=>')
|
||||
print(f'error: {correct_out[1]}')
|
||||
break
|
||||
except Exception:
|
||||
print(output)
|
||||
break
|
||||
else:
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
|
||||
|
@ -70,13 +71,14 @@ def install_haproxy(server_ip: str, **kwargs):
|
|||
f"KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
if server_for_installing:
|
||||
service = server_for_installing + ' HAProxy'
|
||||
else:
|
||||
service = ' HAProxy'
|
||||
|
||||
if show_installation_output(error, output, service):
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
if show_installation_output(return_out['error'], return_out['output'], service, rc=return_out['rc']):
|
||||
sql.update_haproxy(server_ip)
|
||||
|
||||
if docker == '1':
|
||||
|
@ -107,9 +109,9 @@ def waf_install(server_ip: str):
|
|||
f"KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
if show_installation_output(error, output, service):
|
||||
if show_installation_output(return_out['error'], return_out['output'], service, rc=return_out['rc']):
|
||||
sql.insert_waf_metrics_enable(server_ip, "0")
|
||||
sql.insert_waf_rules(server_ip)
|
||||
|
||||
|
@ -134,9 +136,9 @@ def waf_nginx_install(server_ip: str):
|
|||
f"HOST={server_ip} USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
if show_installation_output(error, output, service):
|
||||
if show_installation_output(return_out['error'], return_out['output'], service, rc=return_out['rc']):
|
||||
sql.insert_nginx_waf_rules(server_ip)
|
||||
sql.insert_waf_nginx_server(server_ip)
|
||||
|
||||
|
@ -183,7 +185,7 @@ def install_service(server_ip: str, service: str, docker: str, **kwargs) -> None
|
|||
if server_for_installing:
|
||||
service_name = f'{server_for_installing} {service.title()}'
|
||||
else:
|
||||
service_name = service.title
|
||||
service_name = service.title()
|
||||
|
||||
if show_installation_output(error, output, service_name):
|
||||
if service == 'nginx':
|
||||
|
@ -226,10 +228,9 @@ def geoip_installation():
|
|||
f"PASS={ssh_settings['password']} KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
|
||||
show_installation_output(error, output, 'GeoLite2 Database')
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
show_installation_output(return_out['error'], return_out['output'], 'GeoLite2 Database', rc=return_out['rc'])
|
||||
os.remove(script)
|
||||
|
||||
|
||||
|
@ -296,9 +297,9 @@ def keepalived_master_install():
|
|||
f"USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
if show_installation_output(error, output, 'master Keepalived'):
|
||||
if show_installation_output(return_out['error'], return_out['output'], 'master Keepalived', rc=return_out['rc']):
|
||||
sql.update_keepalived(master)
|
||||
|
||||
if virt_server != '0':
|
||||
|
@ -340,10 +341,9 @@ def keepalived_slave_install():
|
|||
f"NGINX={nginx} HOST={slave} USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
|
||||
show_installation_output(error, output, 'slave Keepalived')
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
show_installation_output(return_out['error'], return_out['output'], 'slave Keepalived', rc=return_out['rc'])
|
||||
os.remove(script)
|
||||
sql.update_server_master(master, slave)
|
||||
sql.update_keepalived(slave)
|
||||
|
@ -375,9 +375,9 @@ def keepalived_masteradd():
|
|||
f"PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
|
||||
show_installation_output(error, output, 'master VRRP address')
|
||||
show_installation_output(return_out['error'], return_out['output'], 'master VRRP address', rc=return_out['rc'])
|
||||
os.remove(script)
|
||||
|
||||
|
||||
|
@ -405,8 +405,6 @@ def keepalived_slaveadd():
|
|||
f"router_id={router_id} USER={ssh_settings['user']} PASS='{ssh_settings['password']}' KEY={ssh_settings['key']}"
|
||||
]
|
||||
|
||||
output, error = server_mod.subprocess_execute(commands[0])
|
||||
|
||||
show_installation_output(error, output, 'slave VRRP address')
|
||||
|
||||
return_out = server_mod.subprocess_execute_with_rc(commands[0])
|
||||
show_installation_output(return_out['error'], return_out['output'], 'slave VRRP address', rc=return_out['rc'])
|
||||
os.remove(script)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
vrrp_instance VI_{{IP}} {
|
||||
state {{MASTER}}
|
||||
interface {% if MASTER == 'MASTER' %}{{ETH}} {% else %} {{ETH_SLAVE}} {% endif %}
|
||||
|
||||
virtual_router_id {{ router_id }}
|
||||
|
||||
priority {% if RETURN_TO_MASTER == 1 and MASTER == 'MASTER' %}152{% elif MASTER == 'MASTER' and RETURN_TO_MASTER == 0 %}102{% else %}101{%endif%}
|
||||
|
||||
track_script {
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
|
||||
- name: Gather currently installed keepalived_exporter version (if any)
|
||||
command: "{{ keepalived_exporter_binary_install_dir }}/keepalived_exporter --version"
|
||||
args:
|
||||
warn: false
|
||||
changed_when: false
|
||||
register: __keepalived_exporter_current_version_output
|
||||
check_mode: false
|
||||
|
|
|
@ -61,8 +61,6 @@
|
|||
|
||||
- name: Gather currently installed node_exporter version (if any)
|
||||
command: "{{ _node_exporter_binary_install_dir }}/node_exporter --version"
|
||||
args:
|
||||
warn: false
|
||||
changed_when: false
|
||||
register: __node_exporter_current_version_output
|
||||
check_mode: false
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
state: latest
|
||||
when:
|
||||
- ansible_facts['os_family'] == "RedHat" or ansible_facts['os_family'] == 'CentOS'
|
||||
- ansible_facts['distribution_major_version'] == '8'
|
||||
- ansible_facts['distribution_major_version'] == '9'
|
||||
environment:
|
||||
http_proxy: "{{PROXY}}"
|
||||
https_proxy: "{{PROXY}}"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{% import 'languages/'+lang|default('en')+'.html' as lang %}
|
||||
<style>
|
||||
body { font-family: arial, helvetica, sans-serif; font-size: 12px; font-weight: normal; color: black; background: white;}
|
||||
th,td { font-size: 10px; }
|
||||
|
@ -60,15 +61,15 @@ div.tips {
|
|||
u:hover div.tips {visibility:visible;}
|
||||
</style>
|
||||
{% for l in out %}
|
||||
<table class="tbl" width="100%">
|
||||
<table class="tbl">
|
||||
<tr class="titre">
|
||||
<th class="pxname" style="background-color: rgb(93, 156, 235); width: 100%; padding-top: 4px; padding-bottom: 4px; border-color: rgb(221, 221, 221);">
|
||||
<a name="status">
|
||||
<a class="px" href="#stats" style="color: rgb(255, 255, 255);">NGINX status</a>
|
||||
<a class="px" href="#stats" style="color: rgb(255, 255, 255);">NGINX {{lang.words.status}}</a>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="tbl" width="100%">
|
||||
<table class="tbl">
|
||||
<tr class="titre">
|
||||
<th style="background-color: rgb(245, 250, 244); padding-top: 4px; padding-bottom: 4px; border-color: rgb(221, 221, 221); width: 15%;">
|
||||
{{l.0.0}} {{l.0.1}}
|
||||
|
@ -116,7 +117,7 @@ u:hover div.tips {visibility:visible;}
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
|
||||
You can read the description about statuses <a href="https://roxy-wi.org/description.py?description=nginx_status" title="NGINX status page description" target="_blank">here</a>
|
||||
<div class="add-note addName alert-info" style="width: inherit; margin-left: 0;">
|
||||
{{lang.phrases.read_desc_statuses}} <a href="https://roxy-wi.org/description/nginx_status" title="NGINX status page description" class="link" target="_blank">{{lang.words.here}}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
title: "Dashboard #3",
|
||||
intro: "Roxy-WI services status",
|
||||
},
|
||||
{% if role == 1 %}
|
||||
{
|
||||
element: document.querySelector('#overview-users'),
|
||||
title: "Dashboard #4",
|
||||
|
@ -39,14 +40,30 @@
|
|||
intro: "Group list",
|
||||
},
|
||||
{
|
||||
element: document.querySelector('#overview-logs'),
|
||||
element: document.querySelector('#overview-roles'),
|
||||
title: "Dashboard #6",
|
||||
intro: "Roles description",
|
||||
},
|
||||
{% endif %}
|
||||
{% if role < 3 %}
|
||||
{% if role > 1 %}
|
||||
{% set board_id = 4 %}
|
||||
{% else %}
|
||||
{% set board_id = 7 %}
|
||||
{% endif %}
|
||||
{
|
||||
element: document.querySelector('#overview-logs'),
|
||||
title: "Dashboard #{{ board_id }}",
|
||||
intro: "Last log entries",
|
||||
},
|
||||
{% endif %}
|
||||
{% if role == 1 %}
|
||||
{
|
||||
element: document.querySelector('#overview-subs'),
|
||||
title: "Dashboard #8",
|
||||
intro: "Subscription info",
|
||||
},
|
||||
{% endif %}
|
||||
{
|
||||
element: document.querySelector('#version'),
|
||||
intro: "Your Roxy-WI version",
|
||||
|
|
|
@ -298,6 +298,8 @@
|
|||
"comparing_config": "Comparing config files",
|
||||
"select_older_config": "Select an older config",
|
||||
"select_newer_config": "Select a newer config",
|
||||
"not_checked": "Without check",
|
||||
"show_not_checked": "Show servers without checking",
|
||||
}
|
||||
%}
|
||||
{% set roles = {
|
||||
|
@ -400,7 +402,7 @@
|
|||
"before_install": "Before installing any exporters, first install",
|
||||
"been_installed": "servers have been installed",
|
||||
"there_are_no": "There are no Grafana and Prometheus servers",
|
||||
"country_codes": "country codes",
|
||||
"country_codes": "Country codes",
|
||||
"smon_desc": "SMON stands for <b>S</b>imple <b>MON</b>itoring",
|
||||
"checker_desc": "Checker is designed for monitoring HAProxy, Nginx, Apache and Keepalived services as well as HAProxy backends and maxconn",
|
||||
"auto_start_desc": "The Auto Start service allows to restart the HAProxy, NGINX, Apache and Keepalived services if they are down",
|
||||
|
@ -440,6 +442,7 @@
|
|||
"BODY_FAILURE": "BODY FAILURE",
|
||||
"UNKNOWN": "UNKNOWN",
|
||||
"PORT_DOWN": "PORT DOWN",
|
||||
"DISABLED": "DISABLED",
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
@ -550,7 +553,7 @@
|
|||
"role": "role",
|
||||
"roles": "roles",
|
||||
"subs": "subscription",
|
||||
"show_all": "show all",
|
||||
"show_all": "Show all",
|
||||
"plan": "plan",
|
||||
"pay_method": "pay method",
|
||||
"active": "active",
|
||||
|
@ -828,5 +831,7 @@
|
|||
"additions": "additions",
|
||||
"deletions": "deletions",
|
||||
"recent": "recent",
|
||||
"already": "already",
|
||||
"disable": "disable",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -298,6 +298,8 @@
|
|||
"comparing_config": "Comparer les fichiers de configuration",
|
||||
"select_older_config": "Sélectionnez une ancienne configuration",
|
||||
"select_newer_config": "Sélectionnez une configuration plus récente",
|
||||
"not_checked": "Sans chèque",
|
||||
"show_not_checked": "Afficher les serveurs sans vérifier",
|
||||
}
|
||||
%}
|
||||
{% set roles = {
|
||||
|
@ -400,7 +402,7 @@
|
|||
"before_install": "Avant d\'installer l\'Exporter, installez le d\'abord",
|
||||
"been_installed": "les serveurs ont été installés",
|
||||
"there_are_no": "Il n\'y a pas de serveurs Grafana ni Prometheus.",
|
||||
"country_codes": "codes des pays",
|
||||
"country_codes": "Сodes des pays",
|
||||
"smon_desc": "SMON stands for <b>S</b>imple <b>MON</b>itoring",
|
||||
"checker_desc": "Checker est conçu pour surveiller les services HAProxy, Nginx, Apache et Keepalived ainsi que les backends HAProxy et maxconn.",
|
||||
"auto_start_desc": "Le service Auto Start permet de redémarrer les services HAProxy, NGINX, Apache et Keepalived s\'ils sont hors service.",
|
||||
|
@ -440,6 +442,7 @@
|
|||
"BODY_FAILURE": " DÉFAILLANCE DU CORPS",
|
||||
"UNKNOWN": "INCONNU",
|
||||
"PORT_DOWN": "PORT DOWN",
|
||||
"DISABLED": "DÉSACTIVÉ",
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
@ -550,7 +553,7 @@
|
|||
"role": "rôle",
|
||||
"roles": "rôles",
|
||||
"subs": "abonnement",
|
||||
"show_all": "tout afficher",
|
||||
"show_all": "Tout afficher",
|
||||
"plan": "plan",
|
||||
"pay_method": "méthode de paiement",
|
||||
"active": "actif",
|
||||
|
@ -828,5 +831,7 @@
|
|||
"additions": "ajouts",
|
||||
"deletions": "suppressions",
|
||||
"recent": "récent",
|
||||
"already": "déjà",
|
||||
"disable": "désactiver",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -298,6 +298,8 @@
|
|||
"comparing_config": "Comparando arquivos de configuração",
|
||||
"select_older_config": "Selecione uma configuração mais antiga",
|
||||
"select_newer_config": "Selecione uma configuração mais nova",
|
||||
"not_checked": "Sem cheque",
|
||||
"show_not_checked": "Mostrar servidores sem verificar",
|
||||
}
|
||||
%}
|
||||
{% set roles = {
|
||||
|
@ -400,7 +402,7 @@
|
|||
"before_install": "Antes de instalar exportadores, primeiro instale",
|
||||
"been_installed": "servidores instalados",
|
||||
"there_are_no": "Não há servidores Grafana e Prometheus",
|
||||
"country_codes": "códigos de país",
|
||||
"country_codes": "Códigos de país",
|
||||
"smon_desc": "SMON significa <b>S</b>imple <b>MON</b>itoring",
|
||||
"checker_desc": "O Checker foi projetado para monitorar serviços HAProxy, Nginx, Apache e Keepalived, bem como backends HAProxy e maxconn",
|
||||
"auto_start_desc": "O serviços Auto Start permite reiniciar os serviços HAProxy, NGINX, Apache e Keepalived se estiverem inoperantes",
|
||||
|
@ -440,6 +442,7 @@
|
|||
"BODY_FAILURE": "BODY FAILURE",
|
||||
"UNKNOWN": "UNKNOWN",
|
||||
"PORT_DOWN": "PORT DOWN",
|
||||
"DISABLED": "DESABIL.",
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
@ -550,7 +553,7 @@
|
|||
"role": "função",
|
||||
"roles": "funções",
|
||||
"subs": "inscrição",
|
||||
"show_all": "mostrar tudo",
|
||||
"show_all": "Mostrar tudo",
|
||||
"plan": "plan",
|
||||
"pay_method": "método de pagamento.",
|
||||
"active": "ativo",
|
||||
|
@ -827,6 +830,8 @@
|
|||
"send": "enviar",
|
||||
"additions": "adicionados",
|
||||
"deletions": "apagados",
|
||||
"recent": "recente"
|
||||
"recent": "recente",
|
||||
"already": "já",
|
||||
"disable": "desabilitar",
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -298,6 +298,8 @@
|
|||
"comparing_config": "Сравнение файлов конфигурации",
|
||||
"select_older_config": "Выберите более старую конфигурацию",
|
||||
"select_newer_config": "Выберите более новую конфигурацию",
|
||||
"not_checked": "Без проверки",
|
||||
"show_not_checked": "Показать сервера без проверки",
|
||||
}
|
||||
%}
|
||||
{% set roles = {
|
||||
|
@ -400,7 +402,7 @@
|
|||
"before_install": "Прежде чем устанавливать какие-либо экспортеры, сначала установите",
|
||||
"been_installed": "сервера были установлены",
|
||||
"there_are_no": "Нет серверов Grafana и Prometheus",
|
||||
"country_codes": "коды стран",
|
||||
"country_codes": "Коды стран",
|
||||
"smon_desc": "SMON означает <b>S</b>простой <b>MON</b>иторинг.",
|
||||
"checker_desc": "Checker предназначен для мониторинга сервисов HAProxy, Nginx, Apache и Keepalived, а также бэкендов HAProxy и maxconn.",
|
||||
"auto_start_desc": "Служба автозапуска позволяет перезапустить службы HAProxy, NGINX, Apache и Keepalived, если они не работают.",
|
||||
|
@ -422,7 +424,7 @@
|
|||
"smon_is_not_run": "SMON сервис не запущен.",
|
||||
"run_smon": "Запустить сервис SMON",
|
||||
"not_installed": "Вы еще не установили сервис SMON",
|
||||
"not_added": "Вы еще не добавили сервера в SMON",
|
||||
"not_added": "Вы еще не добавили серверы в SMON",
|
||||
"create_server": "Создайте Ваш первый сервер",
|
||||
"see_check": "чтобы посмотреть проверки, которые были добавлены",
|
||||
"do_not_sort": "Не сортировать",
|
||||
|
@ -440,6 +442,7 @@
|
|||
"BODY_FAILURE": "ОШИБКА ТЕЛА",
|
||||
"UNKNOWN": "НЕИЗВЕСТНО",
|
||||
"PORT_DOWN": "ПОРТ НЕ ДОСТ.",
|
||||
"DISABLED": "ОТКЛ.",
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
@ -506,7 +509,7 @@
|
|||
"users": "пользователи",
|
||||
"users2": "пользователями",
|
||||
"username": "пользователь",
|
||||
"servers": "сервера",
|
||||
"servers": "серверы",
|
||||
"servers2": "серверами",
|
||||
"creds": "учетные данные",
|
||||
"creds2": "учетными данными",
|
||||
|
@ -550,7 +553,7 @@
|
|||
"role": "роль",
|
||||
"roles": "роли",
|
||||
"subs": "подписка",
|
||||
"show_all": "показать все",
|
||||
"show_all": "Показать все",
|
||||
"plan": "план",
|
||||
"pay_method": "платежный метод",
|
||||
"active": "активный",
|
||||
|
@ -654,7 +657,7 @@
|
|||
"every": "каждых",
|
||||
"every2": "каждую",
|
||||
"every3": "каждый",
|
||||
"hide": "убрать",
|
||||
"hide": "скрыть",
|
||||
"average": "Среднее количество",
|
||||
"peak": "пиковые",
|
||||
"connect": "подключиться",
|
||||
|
@ -828,5 +831,7 @@
|
|||
"additions": "дополнения",
|
||||
"deletions": "удаления",
|
||||
"recent": "недавние",
|
||||
"already": "уже",
|
||||
"disable": "отключить",
|
||||
}
|
||||
%}
|
||||
|
|
Loading…
Reference in New Issue