diff --git a/computes/templates/computes/instances.html b/computes/templates/computes/instances.html
index e56c32af..15f6b3e5 100644
--- a/computes/templates/computes/instances.html
+++ b/computes/templates/computes/instances.html
@@ -27,7 +27,7 @@
{% if compute.status is not True %}
- {% trans 'Problem occurred with host' %} {{ compute.name }}: {{ compute.connection_error }}
+ {% blocktrans with name=compute.name error=compute.connection_error %}Problem occurred with host {{ name }}: {{ error }}{% endblocktrans %}
{% endif %}
{% if not instances %}
diff --git a/console/refusals.py b/console/refusals.py
new file mode 100644
index 00000000..52c3e593
--- /dev/null
+++ b/console/refusals.py
@@ -0,0 +1,9 @@
+"""socketiod's refusals, which its page shows in the user's language. Here,
+as makemessages reads only .py files and socketiod has no extension."""
+
+from django.utils.translation import gettext_noop
+
+TURNED_OFF = gettext_noop("The serial console is turned off on this server")
+NOT_ALLOWED = gettext_noop("The console link has expired, or you may no longer open this console: reload the page")
+OPEN_ELSEWHERE = gettext_noop("The console of this VM is open in another window")
+TOO_MANY = gettext_noop("Too many consoles are open on this server: try again later")
diff --git a/console/socketiod b/console/socketiod
index cb02db20..3f7df5ae 100755
--- a/console/socketiod
+++ b/console/socketiod
@@ -30,7 +30,11 @@ import socketio # noqa: E402
from gunicorn.app.base import BaseApplication # noqa: E402
from django import db # noqa: E402
from django.conf import settings # noqa: E402
+from django.http import HttpRequest # noqa: E402
+from django.http.cookie import parse_cookie # noqa: E402
+from django.utils import translation # noqa: E402
+from console import refusals # noqa: E402
from console.tokens import authorize, session_user_id # noqa: E402
CONSOLECALLBACK = os.path.join(ROOT_PATH, "conf", "daemon", "consolecallback")
@@ -49,30 +53,34 @@ sessions = {}
sessions_lock = threading.Lock()
-def refused(reason):
- """The refusal the page shows; it is logged too."""
+def refused(environ, reason):
+ """The refusal the page shows, in its language (LocaleMiddleware's choice:
+ the language cookie, else the browser's); it is logged too, in English."""
logger.info("serial console refused: %s", reason)
- return socketio.exceptions.ConnectionRefusedError(reason)
+ request = HttpRequest()
+ request.COOKIES, request.META = parse_cookie(environ.get("HTTP_COOKIE", "")), environ
+ with translation.override(translation.get_language_from_request(request)):
+ return socketio.exceptions.ConnectionRefusedError(translation.gettext(reason))
@sio.event
def connect(sid, environ, auth):
# the page shows the reason
if not settings.SERIAL_CONSOLE_ENABLED:
- raise refused("The serial console is turned off on this server")
+ raise refused(environ, refusals.TURNED_OFF)
try:
instance, user = authorize((auth or {}).get("token"), "pty")
except PermissionError:
- raise refused("The console link has expired, or you may no longer open this console: reload the page")
+ raise refused(environ, refusals.NOT_ALLOWED)
finally:
db.close_old_connections()
taken = None
with sessions_lock:
open_sid = next((s for s, session in sessions.items() if session["vm"] == instance.pk), None)
if open_sid is not None and not user.is_superuser:
- raise refused("The console of this VM is open in another window")
+ raise refused(environ, refusals.OPEN_ELSEWHERE)
if open_sid is None and len(sessions) >= MAX_SESSIONS:
- raise refused("Too many consoles are open on this server: try again later")
+ raise refused(environ, refusals.TOO_MANY)
if open_sid is not None: # a superuser takes over a console left open
taken = open_sid, sessions.pop(open_sid)
# the page tells its user who took the console; first, as its
diff --git a/console/tests/test_socketiod.py b/console/tests/test_socketiod.py
index 183426f8..6f5e9b83 100644
--- a/console/tests/test_socketiod.py
+++ b/console/tests/test_socketiod.py
@@ -116,6 +116,18 @@ class SocketiodTestCase(Base):
self.assertIn("Too many", self.refused("over", {"token": self.token(vm=other)}))
self.assertEqual(list(self.d.sessions), ["first"])
+ @override_settings(SERIAL_CONSOLE_ENABLED=False)
+ def test_a_refusal_is_in_the_page_s_language_and_logged_in_english(self):
+ # as LocaleMiddleware: the language cookie first, then the browser's
+ for environ, shown in (({"HTTP_COOKIE": "django_language=tr", "HTTP_ACCEPT_LANGUAGE": "zh-hans"}, "Seri konsol bu sunucuda kapalı"),
+ ({"HTTP_ACCEPT_LANGUAGE": "zh-CN,zh;q=0.9"}, "此服务器已关闭串行控制台"),
+ ({}, "The serial console is turned off on this server")):
+ with self.subTest(shown), self.assertRaises(self.d.socketio.exceptions.ConnectionRefusedError) as refusal, \
+ self.assertLogs("socketiod", level="INFO") as log:
+ self.d.connect("sid", environ, {"token": self.token()})
+ self.assertEqual(refusal.exception.error_args["message"], shown)
+ self.assertIn("refused: The serial console is turned off on this server", log.output[0])
+
@override_settings(SERIAL_CONSOLE_ENABLED=True)
def test_input_and_resize_go_to_the_session_and_are_checked(self):
self.d.connect("sid-1", {}, {"token": self.token()})
diff --git a/instances/api/viewsets.py b/instances/api/viewsets.py
index 1022d0c3..e56845e3 100644
--- a/instances/api/viewsets.py
+++ b/instances/api/viewsets.py
@@ -5,6 +5,7 @@ from django.contrib.messages import get_messages
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.urls import reverse
+from django.utils.translation import gettext as _
from instances.jobs import MIGRATE_OPTIONS
from instances.models import Flavor, Instance
from instances.views import (
@@ -144,7 +145,7 @@ class InstanceViewSet(viewsets.ViewSet):
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
raise Http404()
if queryset.is_template:
- return Response({"status": "Templates cannot be started"}, status=status.HTTP_409_CONFLICT)
+ return Response({"status": _("Templates cannot be started.")}, status=status.HTTP_409_CONFLICT)
return instance_action_response(poweron, request, pk, "poweron command send")
@extend_schema(request=None, responses=ActionStatusSerializer)
@@ -162,7 +163,7 @@ class InstanceViewSet(viewsets.ViewSet):
if compute_pk is not None and str(queryset.compute_id) != str(compute_pk):
raise Http404()
if queryset.is_template:
- return Response({"status": "Templates cannot be started"}, status=status.HTTP_409_CONFLICT)
+ return Response({"status": _("Templates cannot be started.")}, status=status.HTTP_409_CONFLICT)
return instance_action_response(powercycle, request, pk, "powercycle command send")
@extend_schema(request=None, responses=ActionStatusSerializer)
diff --git a/instances/views.py b/instances/views.py
index cb21f25a..3e3ccc58 100755
--- a/instances/views.py
+++ b/instances/views.py
@@ -640,7 +640,7 @@ def _busy(request, pk, busy):
def _moved(request, pk):
if hasattr(request, "accepted_renderer") or from_script(request):
- return JsonResponse({"detail": "The VM was moved meanwhile; try again."}, status=409)
+ return JsonResponse({"detail": _("The VM was moved meanwhile; try again.")}, status=409)
messages.error(request, _("The VM was moved meanwhile; try again."))
return get_safe_redirect(request, default=reverse("instances:instance", args=[pk]))
diff --git a/locale/tr/LC_MESSAGES/django.mo b/locale/tr/LC_MESSAGES/django.mo
index 459b4e79..cf2d984f 100644
Binary files a/locale/tr/LC_MESSAGES/django.mo and b/locale/tr/LC_MESSAGES/django.mo differ
diff --git a/locale/tr/LC_MESSAGES/django.po b/locale/tr/LC_MESSAGES/django.po
index 4bdf1e10..c6391990 100644
--- a/locale/tr/LC_MESSAGES/django.po
+++ b/locale/tr/LC_MESSAGES/django.po
@@ -2119,8 +2119,10 @@ msgid "New Instance"
msgstr "Yeni sanal makine"
#: computes/templates/computes/instances.html:30
-msgid "Problem occurred with host"
-msgstr "Sunucu ile ilgili bir problem meydana geldi"
+#, python-format
+#| msgid "Problem occurred with host"
+msgid "Problem occurred with host %(name)s: %(error)s"
+msgstr "%(name)s sunucusuyla ilgili bir sorun oluştu: %(error)s"
#: computes/templates/computes/instances.html:36
#: computes/templates/computes/list.html:16
@@ -2379,7 +2381,7 @@ msgstr ""
"Sunucudaki /etc/default/webvirt-gstfsd içindeki GSTFSD_KEY değerinin 64 "
"onaltılık karakterini girin"
-#: computes/views.py:202
+#: computes/views.py:205
#, python-format
msgid ""
"Its VMs keep running on the host and leave the panel; their owners are kept "
@@ -2390,6 +2392,28 @@ msgstr ""
"Kaldırılan Sanal Makineler sayfasında %(days)s gün tutulur ve sunucu yeniden "
"eklenirse geri gelir."
+#: console/refusals.py:6
+#| msgid "The device is not on this host"
+msgid "The serial console is turned off on this server"
+msgstr "Seri konsol bu sunucuda kapalı"
+
+#: console/refusals.py:7
+msgid ""
+"The console link has expired, or you may no longer open this console: reload "
+"the page"
+msgstr ""
+"Konsol bağlantısının süresi doldu ya da bu konsolu artık açamazsınız: sayfayı"
+" yeniden yükleyin"
+
+#: console/refusals.py:8
+#| msgid "The console starts scaled to its window"
+msgid "The console of this VM is open in another window"
+msgstr "Bu sanal makinenin konsolu başka bir pencerede açık"
+
+#: console/refusals.py:9
+msgid "Too many consoles are open on this server: try again later"
+msgstr "Bu sunucuda çok fazla konsol açık: daha sonra yeniden deneyin"
+
#: console/templates/console-menu.html:6
msgid "Send key(s)"
msgstr "Anahtar(ları) gönder"
@@ -2634,6 +2658,11 @@ msgstr ""
"'%(type)s' konsol tipi desteklenmiyor. Lütfen sanal makinenin grafik tipini "
"VNC olarak değiştirin."
+#: instances/api/viewsets.py:148 instances/api/viewsets.py:166
+#: instances/views.py:792 instances/views.py:807
+msgid "Templates cannot be started."
+msgstr "Şablon makineler başlatılamaz."
+
#: instances/forms.py:13 instances/templates/create_instance_w2.html:69
#: instances/templates/instances/settings_tab.html:857
msgid "Memory (MiB)"
@@ -2999,7 +3028,6 @@ msgstr "Sanal makine tanımlanıyor"
#: instances/jobs.py:906
#, python-format
-#| msgid "The panel failed unexpectedly; its log has the details."
msgid ""
"The panel failed unexpectedly; its log has the details. Remove these volumes "
"by hand: %(volumes)s"
@@ -5924,7 +5952,7 @@ msgstr ""
"Sunucu aygıtları olan bir sanal makine taşınamaz: hedefte bu aygıtlar "
"olmayabilir. Önce onları kaldırın."
-#: instances/views.py:644
+#: instances/views.py:643 instances/views.py:644
msgid "The VM was moved meanwhile; try again."
msgstr "Sanal makine bu arada taşındı; yeniden deneyin."
@@ -5958,10 +5986,6 @@ msgstr ""
msgid "Invalid disk options: %(options)s"
msgstr "Geçersiz disk seçenekleri: %(options)s"
-#: instances/views.py:792 instances/views.py:807
-msgid "Templates cannot be started."
-msgstr "Şablon makineler başlatılamaz."
-
#: instances/views.py:999
#, python-format
msgid "Set the gstfsd key of %(compute)s first (Computes, edit the host)"
@@ -7628,6 +7652,12 @@ msgstr ""
msgid "%(phase)s (over its time limit)"
msgstr "%(phase)s (süre sınırını aştı)"
+#: operations/jobs.py:151
+#| msgid "The form has no valid submission key; reload the page"
+msgid "This form was already submitted for another request; reload the page"
+msgstr ""
+"Bu form başka bir istek için zaten gönderildi; sayfayı yeniden yükleyin"
+
#: operations/jobs.py:157
msgid "The form has no valid submission key; reload the page"
msgstr "Formun geçerli bir gönderim anahtarı yok; sayfayı yeniden yükleyin"
@@ -7907,10 +7937,14 @@ msgstr ""
"Kurtarma bir saat boyunca işin durumunu okuyamadı; sanal makineyi kontrol "
"edin, sonra bu işi çözün"
-#: operations/worker.py:474
+#: operations/worker.py:479
msgid "The worker stopped before the job changed anything"
msgstr "Worker, iş herhangi bir şeyi değiştirmeden önce durdu"
+#: storages/api/viewsets.py:203 storages/api/viewsets.py:224
+msgid "Pool is not active"
+msgstr "Havuz etkin değil"
+
#: storages/forms.py:30 storages/templates/storage.html:102
#: storages/templates/storages.html:43
msgid "Path"
@@ -8009,6 +8043,26 @@ msgstr "Kopya oluşturulmadı"
msgid "Upload ISO image"
msgstr "ISO imajı yükle"
+#: storages/jobs.py:118
+#| msgid "Invalid file size."
+msgid "Invalid file name"
+msgstr "Geçersiz dosya adı"
+
+#: storages/jobs.py:120
+#| msgid "Only .iso files can be uploaded."
+msgid "Only .iso files can be uploaded"
+msgstr "Yalnızca .iso dosyaları yüklenebilir"
+
+#: storages/jobs.py:122
+#| msgid "Invalid file size."
+msgid "Invalid file size"
+msgstr "Geçersiz dosya boyutu"
+
+#: storages/jobs.py:124
+#| msgid "Invalid chunk index or total chunks."
+msgid "Invalid chunk index or total chunks"
+msgstr "Geçersiz parça dizini veya toplam parça sayısı"
+
#: storages/templates/create_stg_block.html:7
msgid "New pool"
msgstr "Yeni havuz"
@@ -9834,6 +9888,11 @@ msgstr "XML geçerli değil: %(err)s"
msgid "The XML may not declare a DTD"
msgstr "XML bir DTD bildiremez"
+#: vrtManager/util.py:143
+#, python-format
+msgid "MAC address must be of the format AA:BB:CC:DD:EE:FF, was %(mac)s"
+msgstr "MAC adresi AA:BB:CC:DD:EE:FF biçiminde olmalı; girilen: %(mac)s"
+
#: vrtManager/virtsecrets.py:26
msgid "A Ceph key is base64 text, as `ceph auth get-key` prints it"
msgstr ""
diff --git a/locale/zh/LC_MESSAGES/django.mo b/locale/zh/LC_MESSAGES/django.mo
index 17aeed85..7de24a53 100644
Binary files a/locale/zh/LC_MESSAGES/django.mo and b/locale/zh/LC_MESSAGES/django.mo differ
diff --git a/locale/zh/LC_MESSAGES/django.po b/locale/zh/LC_MESSAGES/django.po
index 07d063bc..cd19c93e 100644
--- a/locale/zh/LC_MESSAGES/django.po
+++ b/locale/zh/LC_MESSAGES/django.po
@@ -2050,8 +2050,10 @@ msgid "New Instance"
msgstr "新建虚拟机"
#: computes/templates/computes/instances.html:30
-msgid "Problem occurred with host"
-msgstr "主机出现问题"
+#, python-format
+#| msgid "Problem occurred with host"
+msgid "Problem occurred with host %(name)s: %(error)s"
+msgstr "主机 %(name)s 出现问题:%(error)s"
#: computes/templates/computes/instances.html:36
#: computes/templates/computes/list.html:16
@@ -2302,7 +2304,7 @@ msgid ""
"/etc/default/webvirt-gstfsd"
msgstr "请输入主机 /etc/default/webvirt-gstfsd 中 GSTFSD_KEY 的 64 个十六进制字符"
-#: computes/views.py:202
+#: computes/views.py:205
#, python-format
msgid ""
"Its VMs keep running on the host and leave the panel; their owners are kept "
@@ -2310,6 +2312,26 @@ msgid ""
"again."
msgstr "其虚拟机继续在主机上运行并离开面板;其所有者在“已移除的虚拟机”页面保留 %(days)s 天,如果再次添加该主机则会恢复。"
+#: console/refusals.py:6
+#| msgid "The device is not on this host"
+msgid "The serial console is turned off on this server"
+msgstr "此服务器已关闭串行控制台"
+
+#: console/refusals.py:7
+msgid ""
+"The console link has expired, or you may no longer open this console: reload "
+"the page"
+msgstr "控制台链接已过期,或您已无权打开此控制台:请重新加载页面"
+
+#: console/refusals.py:8
+#| msgid "The console starts scaled to its window"
+msgid "The console of this VM is open in another window"
+msgstr "此虚拟机的控制台已在另一个窗口中打开"
+
+#: console/refusals.py:9
+msgid "Too many consoles are open on this server: try again later"
+msgstr "此服务器上打开的控制台过多:请稍后再试"
+
#: console/templates/console-menu.html:6
msgid "Send key(s)"
msgstr "发送按键"
@@ -2541,6 +2563,11 @@ msgid ""
"VNC."
msgstr "不支持控制台类型 '%(type)s'。请将虚拟机图形切换为 VNC。"
+#: instances/api/viewsets.py:148 instances/api/viewsets.py:166
+#: instances/views.py:792 instances/views.py:807
+msgid "Templates cannot be started."
+msgstr "模板无法启动。"
+
#: instances/forms.py:13 instances/templates/create_instance_w2.html:69
#: instances/templates/instances/settings_tab.html:857
msgid "Memory (MiB)"
@@ -2879,7 +2906,6 @@ msgstr "正在定义虚拟机"
#: instances/jobs.py:906
#, python-format
-#| msgid "The panel failed unexpectedly; its log has the details."
msgid ""
"The panel failed unexpectedly; its log has the details. Remove these volumes "
"by hand: %(volumes)s"
@@ -5623,7 +5649,7 @@ msgid ""
" Remove them first."
msgstr "有主机设备的虚拟机无法迁移:目标主机可能没有这些设备。请先移除它们。"
-#: instances/views.py:644
+#: instances/views.py:643 instances/views.py:644
msgid "The VM was moved meanwhile; try again."
msgstr "该虚拟机在此期间已被移动;请重试。"
@@ -5652,10 +5678,6 @@ msgstr ""
msgid "Invalid disk options: %(options)s"
msgstr "无效的磁盘选项:%(options)s"
-#: instances/views.py:792 instances/views.py:807
-msgid "Templates cannot be started."
-msgstr "模板无法启动。"
-
#: instances/views.py:999
#, python-format
msgid "Set the gstfsd key of %(compute)s first (Computes, edit the host)"
@@ -7226,6 +7248,11 @@ msgstr "字母、数字、点、短横线和下划线。副本包含该过滤器
msgid "%(phase)s (over its time limit)"
msgstr "%(phase)s(已超出时间限制)"
+#: operations/jobs.py:151
+#| msgid "The form has no valid submission key; reload the page"
+msgid "This form was already submitted for another request; reload the page"
+msgstr "此表单已为另一个请求提交过;请重新加载页面"
+
#: operations/jobs.py:157
msgid "The form has no valid submission key; reload the page"
msgstr "表单没有有效的提交密钥;请重新加载页面"
@@ -7490,10 +7517,14 @@ msgid ""
"resolve this job"
msgstr "恢复在一小时内无法读取任务状态;请检查虚拟机,然后处理此任务"
-#: operations/worker.py:474
+#: operations/worker.py:479
msgid "The worker stopped before the job changed anything"
msgstr "工作进程在任务做出任何更改之前停止"
+#: storages/api/viewsets.py:203 storages/api/viewsets.py:224
+msgid "Pool is not active"
+msgstr "存储池未激活"
+
#: storages/forms.py:30 storages/templates/storage.html:102
#: storages/templates/storages.html:43
msgid "Path"
@@ -7591,6 +7622,26 @@ msgstr "未创建副本"
msgid "Upload ISO image"
msgstr "上传 ISO 镜像"
+#: storages/jobs.py:118
+#| msgid "Invalid file size."
+msgid "Invalid file name"
+msgstr "文件名无效"
+
+#: storages/jobs.py:120
+#| msgid "Only .iso files can be uploaded."
+msgid "Only .iso files can be uploaded"
+msgstr "只能上传 .iso 文件"
+
+#: storages/jobs.py:122
+#| msgid "Invalid file size."
+msgid "Invalid file size"
+msgstr "文件大小无效"
+
+#: storages/jobs.py:124
+#| msgid "Invalid chunk index or total chunks."
+msgid "Invalid chunk index or total chunks"
+msgstr "分块索引或分块总数无效"
+
#: storages/templates/create_stg_block.html:7
msgid "New pool"
msgstr "新建存储池"
@@ -9274,6 +9325,11 @@ msgstr "XML 无效:%(err)s"
msgid "The XML may not declare a DTD"
msgstr "XML 不能声明 DTD"
+#: vrtManager/util.py:143
+#, python-format
+msgid "MAC address must be of the format AA:BB:CC:DD:EE:FF, was %(mac)s"
+msgstr "MAC 地址的格式必须为 AA:BB:CC:DD:EE:FF,实际为 %(mac)s"
+
#: vrtManager/virtsecrets.py:26
msgid "A Ceph key is base64 text, as `ceph auth get-key` prints it"
msgstr "Ceph 密钥是 base64 文本,即 `ceph auth get-key` 输出的内容"
diff --git a/operations/jobs.py b/operations/jobs.py
index 6bc056ce..bbe1dc9b 100644
--- a/operations/jobs.py
+++ b/operations/jobs.py
@@ -13,7 +13,7 @@ from django.db import transaction
from django.db.models import F, Value
from django.db.models.functions import Coalesce
from django.utils import timezone
-from django.utils.translation import gettext_noop
+from django.utils.translation import gettext, gettext_noop
from logs.audit import write
from vrtManager.util import OperationError
@@ -148,7 +148,7 @@ def _existing(user, key, kind_name, params):
Operation.objects.filter(pk=op.pk).update(submission_key=f"expired:{op.pk.hex}")
return None
if op.kind != kind_name or op.params != params:
- raise SubmissionConflict("This form was already submitted for another request; reload the page")
+ raise SubmissionConflict(gettext("This form was already submitted for another request; reload the page"))
return op
diff --git a/storages/api/viewsets.py b/storages/api/viewsets.py
index 7f5d3dbd..882abbba 100644
--- a/storages/api/viewsets.py
+++ b/storages/api/viewsets.py
@@ -5,6 +5,7 @@ from appsettings.settings import app_settings
from computes.models import Compute
from computes.utils import libvirt_compute_lock
from django.shortcuts import get_object_or_404
+from django.utils.translation import gettext as _
from drf_spectacular.utils import extend_schema, inline_serializer
from libvirt import libvirtError
from logs.audit import audit, failed
@@ -199,7 +200,7 @@ class VolumeViewSet(viewsets.ViewSet):
return Response({"status": "Volume: " + ret + " is created"})
else:
failed(request, compute, subject, action, "pool is not active")
- return Response({"status": "Pool is not active"}, status=status.HTTP_409_CONFLICT)
+ return Response({"status": _("Pool is not active")}, status=status.HTTP_409_CONFLICT)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@@ -220,4 +221,4 @@ class VolumeViewSet(viewsets.ViewSet):
return Response({"status": "Volume: " + pk + " is deleted"})
else:
failed(request, compute, subject, action, "pool is not active")
- return Response({"status": "Pool is not active"}, status=status.HTTP_409_CONFLICT)
+ return Response({"status": _("Pool is not active")}, status=status.HTTP_409_CONFLICT)
diff --git a/storages/jobs.py b/storages/jobs.py
index 6430ac9e..3b930f46 100644
--- a/storages/jobs.py
+++ b/storages/jobs.py
@@ -5,7 +5,7 @@ import logging
import os
from django.core.exceptions import PermissionDenied
-from django.utils.translation import gettext_noop
+from django.utils.translation import gettext, gettext_noop
from libvirt import libvirtError
from vrtManager import util
from vrtManager.storage import wvmStorage
@@ -115,13 +115,13 @@ class UploadVolume(Kind):
raise PermissionDenied
name = params["name"]
if not name or name in (".", "..") or "\x00" in name:
- raise ValueError("Invalid file name")
+ raise ValueError(gettext("Invalid file name"))
if len(name) <= 4 or not is_iso(name):
- raise ValueError("Only .iso files can be uploaded")
+ raise ValueError(gettext("Only .iso files can be uploaded"))
if params["size"] <= 0:
- raise ValueError("Invalid file size")
+ raise ValueError(gettext("Invalid file size"))
if params["chunks"] < 1:
- raise ValueError("Invalid chunk index or total chunks")
+ raise ValueError(gettext("Invalid chunk index or total chunks"))
def plan(self, user, params):
compute, stg = _storage(params)
diff --git a/vrtManager/util.py b/vrtManager/util.py
index acb26262..3d1b5679 100644
--- a/vrtManager/util.py
+++ b/vrtManager/util.py
@@ -140,7 +140,7 @@ def validate_macaddr(val):
form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val)
if form is None:
- raise ValueError("MAC address must be of the format AA:BB:CC:DD:EE:FF, was {}".format(val))
+ raise ValueError(gettext("MAC address must be of the format AA:BB:CC:DD:EE:FF, was %(mac)s") % {"mac": val})
def vol_dev_type(vol_bus):