Merge branch 'master' into CURA-4253_psp

This commit is contained in:
ChrisTerBeke 2017-10-16 17:16:00 +02:00
commit 205ac7c50c
18 changed files with 434 additions and 90 deletions

1
.gitignore vendored
View File

@ -42,6 +42,7 @@ plugins/FlatProfileExporter
plugins/ProfileFlattener plugins/ProfileFlattener
plugins/cura-god-mode-plugin plugins/cura-god-mode-plugin
plugins/cura-big-flame-graph plugins/cura-big-flame-graph
plugins/cura-siemensnx-plugin
#Build stuff #Build stuff
CMakeCache.txt CMakeCache.txt

View File

@ -1,18 +1,27 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import sys import sys
import platform import platform
import traceback import traceback
import webbrowser
import faulthandler import faulthandler
import tempfile import tempfile
import os import os
import urllib import os.path
import time
import json
import ssl
import urllib.request
import urllib.error
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, Qt, QCoreApplication from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QCoreApplication
from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QVBoxLayout, QLabel, QTextEdit, QGroupBox, QPushButton
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QHBoxLayout, QVBoxLayout, QLabel, QTextEdit
from UM.Logger import Logger from UM.Logger import Logger
from UM.View.GL.OpenGL import OpenGL
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Platform import Platform
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
MYPY = False MYPY = False
@ -35,83 +44,238 @@ fatal_exception_types = [
SystemError, SystemError,
] ]
def show(exception_type, value, tb): class CrashHandler:
Logger.log("c", "An uncaught exception has occurred!") crash_url = "https://stats.ultimaker.com/api/cura"
for line in traceback.format_exception(exception_type, value, tb):
for part in line.rstrip("\n").split("\n"):
Logger.log("c", part)
if not CuraDebugMode and exception_type not in fatal_exception_types: def __init__(self, exception_type, value, tb):
return
application = QCoreApplication.instance() self.exception_type = exception_type
if not application: self.value = value
sys.exit(1) self.traceback = tb
dialog = QDialog() # While we create the GUI, the information will be stored for sending afterwards
dialog.setMinimumWidth(640) self.data = dict()
dialog.setMinimumHeight(640) self.data["time_stamp"] = time.time()
dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
layout = QVBoxLayout(dialog) Logger.log("c", "An uncaught exception has occurred!")
for line in traceback.format_exception(exception_type, value, tb):
for part in line.rstrip("\n").split("\n"):
Logger.log("c", part)
#label = QLabel(dialog) if not CuraDebugMode and exception_type not in fatal_exception_types:
#pixmap = QPixmap() return
#try:
# data = urllib.request.urlopen("http://www.randomkittengenerator.com/cats/rotator.php").read()
# pixmap.loadFromData(data)
#except:
# try:
# from UM.Resources import Resources
# path = Resources.getPath(Resources.Images, "kitten.jpg")
# pixmap.load(path)
# except:
# pass
#pixmap = pixmap.scaled(150, 150)
#label.setPixmap(pixmap)
#label.setAlignment(Qt.AlignCenter)
#layout.addWidget(label)
label = QLabel(dialog) application = QCoreApplication.instance()
layout.addWidget(label) if not application:
sys.exit(1)
#label.setScaledContents(True) self._createDialog()
label.setText(catalog.i18nc("@label", """<p>A fatal exception has occurred that we could not recover from!</p>
<p>Please use the information below to post a bug report at <a href=\"http://github.com/Ultimaker/Cura/issues\">http://github.com/Ultimaker/Cura/issues</a></p>
"""))
textarea = QTextEdit(dialog) ## Creates a modal dialog.
layout.addWidget(textarea) def _createDialog(self):
try: self.dialog = QDialog()
from UM.Application import Application self.dialog.setMinimumWidth(640)
version = Application.getInstance().getVersion() self.dialog.setMinimumHeight(640)
except: self.dialog.setWindowTitle(catalog.i18nc("@title:window", "Crash Report"))
version = "Unknown"
trace = "".join(traceback.format_exception(exception_type, value, tb)) layout = QVBoxLayout(self.dialog)
crash_info = "Version: {0}\nPlatform: {1}\nQt: {2}\nPyQt: {3}\n\nException:\n{4}" layout.addWidget(self._messageWidget())
crash_info = crash_info.format(version, platform.platform(), QT_VERSION_STR, PYQT_VERSION_STR, trace) layout.addWidget(self._informationWidget())
layout.addWidget(self._exceptionInfoWidget())
layout.addWidget(self._logInfoWidget())
layout.addWidget(self._userDescriptionWidget())
layout.addWidget(self._buttonsWidget())
tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True) def _messageWidget(self):
os.close(tmp_file_fd) label = QLabel()
with open(tmp_file_path, "w") as f: label.setText(catalog.i18nc("@label crash message", """<p><b>A fatal exception has occurred. Please send us this Crash Report to fix the problem</p></b>
faulthandler.dump_traceback(f, all_threads=True) <p>Please use the "Send report" button to post a bug report automatically to our servers</p>
with open(tmp_file_path, "r") as f: """))
data = f.read()
msg = "-------------------------\n" return label
msg += data
crash_info += "\n\n" + msg
textarea.setText(crash_info) def _informationWidget(self):
group = QGroupBox()
group.setTitle(catalog.i18nc("@title:groupbox", "System information"))
layout = QVBoxLayout()
label = QLabel()
buttons = QDialogButtonBox(QDialogButtonBox.Close, dialog) try:
layout.addWidget(buttons) from UM.Application import Application
buttons.addButton(catalog.i18nc("@action:button", "Open Web Page"), QDialogButtonBox.HelpRole) self.cura_version = Application.getInstance().getVersion()
buttons.rejected.connect(dialog.close) except:
buttons.helpRequested.connect(lambda: webbrowser.open("http://github.com/Ultimaker/Cura/issues")) self.cura_version = catalog.i18nc("@label unknown version of Cura", "Unknown")
dialog.exec_() crash_info = catalog.i18nc("@label Cura version", "<b>Cura version:</b> {version}<br/>").format(version = self.cura_version)
sys.exit(1) crash_info += catalog.i18nc("@label Platform", "<b>Platform:</b> {platform}<br/>").format(platform = platform.platform())
crash_info += catalog.i18nc("@label Qt version", "<b>Qt version:</b> {qt}<br/>").format(qt = QT_VERSION_STR)
crash_info += catalog.i18nc("@label PyQt version", "<b>PyQt version:</b> {pyqt}<br/>").format(pyqt = PYQT_VERSION_STR)
crash_info += catalog.i18nc("@label OpenGL", "<b>OpenGL:</b> {opengl}<br/>").format(opengl = self._getOpenGLInfo())
label.setText(crash_info)
layout.addWidget(label)
group.setLayout(layout)
self.data["cura_version"] = self.cura_version
self.data["os"] = {"type": platform.system(), "version": platform.version()}
self.data["qt_version"] = QT_VERSION_STR
self.data["pyqt_version"] = PYQT_VERSION_STR
return group
def _getOpenGLInfo(self):
info = "<ul>"
info += catalog.i18nc("@label OpenGL version", "<li>OpenGL Version: {version}</li>").format(version = OpenGL.getInstance().getOpenGLVersion())
info += catalog.i18nc("@label OpenGL vendor", "<li>OpenGL Vendor: {vendor}</li>").format(vendor = OpenGL.getInstance().getGPUVendorName())
info += catalog.i18nc("@label OpenGL renderer", "<li>OpenGL Renderer: {renderer}</li>").format(renderer = OpenGL.getInstance().getGPUType())
info += "</ul>"
self.data["opengl"] = {"version": OpenGL.getInstance().getOpenGLVersion(), "vendor": OpenGL.getInstance().getGPUVendorName(), "type": OpenGL.getInstance().getGPUType()}
return info
def _exceptionInfoWidget(self):
group = QGroupBox()
group.setTitle(catalog.i18nc("@title:groupbox", "Exception traceback"))
layout = QVBoxLayout()
text_area = QTextEdit()
trace_dict = traceback.format_exception(self.exception_type, self.value, self.traceback)
trace = "".join(trace_dict)
text_area.setText(trace)
text_area.setReadOnly(True)
layout.addWidget(text_area)
group.setLayout(layout)
# Parsing all the information to fill the dictionary
summary = trace_dict[len(trace_dict)-1].rstrip("\n")
module = trace_dict[len(trace_dict)-2].rstrip("\n").split("\n")
module_split = module[0].split(", ")
filepath = module_split[0].split("\"")[1]
directory, filename = os.path.split(filepath)
line = int(module_split[1].lstrip("line "))
function = module_split[2].lstrip("in ")
code = module[1].lstrip(" ")
# Using this workaround for a cross-platform path splitting
split_path = []
folder_name = ""
# Split until reach folder "cura"
while folder_name != "cura":
directory, folder_name = os.path.split(directory)
if not folder_name:
break
split_path.append(folder_name)
# Look for plugins. If it's not a plugin, the current cura version is set
isPlugin = False
module_version = self.cura_version
module_name = "Cura"
if split_path.__contains__("plugins"):
isPlugin = True
# Look backwards until plugin.json is found
directory, name = os.path.split(filepath)
while not os.listdir(directory).__contains__("plugin.json"):
directory, name = os.path.split(directory)
json_metadata_file = os.path.join(directory, "plugin.json")
try:
with open(json_metadata_file, "r") as f:
try:
metadata = json.loads(f.read())
module_version = metadata["version"]
module_name = metadata["name"]
except json.decoder.JSONDecodeError:
# Not throw new exceptions
Logger.logException("e", "Failed to parse plugin.json for plugin %s", name)
except:
# Not throw new exceptions
pass
exception_dict = dict()
exception_dict["traceback"] = {"summary": summary, "full_trace": trace}
exception_dict["location"] = {"path": filepath, "file": filename, "function": function, "code": code, "line": line,
"module_name": module_name, "version": module_version, "is_plugin": isPlugin}
self.data["exception"] = exception_dict
return group
def _logInfoWidget(self):
group = QGroupBox()
group.setTitle(catalog.i18nc("@title:groupbox", "Logs"))
layout = QVBoxLayout()
text_area = QTextEdit()
tmp_file_fd, tmp_file_path = tempfile.mkstemp(prefix = "cura-crash", text = True)
os.close(tmp_file_fd)
with open(tmp_file_path, "w") as f:
faulthandler.dump_traceback(f, all_threads=True)
with open(tmp_file_path, "r") as f:
logdata = f.read()
text_area.setText(logdata)
text_area.setReadOnly(True)
layout.addWidget(text_area)
group.setLayout(layout)
self.data["log"] = logdata
return group
def _userDescriptionWidget(self):
group = QGroupBox()
group.setTitle(catalog.i18nc("@title:groupbox", "User description"))
layout = QVBoxLayout()
# When sending the report, the user comments will be collected
self.user_description_text_area = QTextEdit()
self.user_description_text_area.setFocus(True)
layout.addWidget(self.user_description_text_area)
group.setLayout(layout)
return group
def _buttonsWidget(self):
buttons = QDialogButtonBox()
buttons.addButton(QDialogButtonBox.Close)
buttons.addButton(catalog.i18nc("@action:button", "Send report"), QDialogButtonBox.AcceptRole)
buttons.rejected.connect(self.dialog.close)
buttons.accepted.connect(self._sendCrashReport)
return buttons
def _sendCrashReport(self):
# Before sending data, the user comments are stored
self.data["user_info"] = self.user_description_text_area.toPlainText()
# Convert data to bytes
binary_data = json.dumps(self.data).encode("utf-8")
# Submit data
kwoptions = {"data": binary_data, "timeout": 5}
if Platform.isOSX():
kwoptions["context"] = ssl._create_unverified_context()
Logger.log("i", "Sending crash report info to [%s]...", self.crash_url)
try:
f = urllib.request.urlopen(self.crash_url, **kwoptions)
Logger.log("i", "Sent crash report info.")
f.close()
except urllib.error.HTTPError:
Logger.logException("e", "An HTTP error occurred while trying to send crash report")
except Exception: # We don't want any exception to cause problems
Logger.logException("e", "An exception occurred while trying to send crash report")
os._exit(1)
def show(self):
self.dialog.exec_()
os._exit(1)

View File

@ -10,7 +10,6 @@ from UM.Application import Application
import UM.FlameProfiler import UM.FlameProfiler
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders. from cura.Settings.ExtruderStack import ExtruderStack #To listen to changes on the extruders.
from cura.Settings.MachineManager import MachineManager #To listen to changes on the extruders of the currently active machine.
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")

View File

@ -41,8 +41,9 @@ if "PYTHONPATH" in os.environ.keys(): # If PYTHONPATH is u
sys.path.insert(1, PATH_real) # Insert it at 1 after os.curdir, which is 0. sys.path.insert(1, PATH_real) # Insert it at 1 after os.curdir, which is 0.
def exceptHook(hook_type, value, traceback): def exceptHook(hook_type, value, traceback):
import cura.CrashHandler from cura.CrashHandler import CrashHandler
cura.CrashHandler.show(hook_type, value, traceback) _crash_handler = CrashHandler(hook_type, value, traceback)
_crash_handler.show()
sys.excepthook = exceptHook sys.excepthook = exceptHook

View File

@ -79,7 +79,7 @@ class MachineSettingsAction(MachineAction):
@pyqtSlot() @pyqtSlot()
def onFinishAction(self): def onFinishAction(self):
# Restore autoslicing when the machineaction is dismissed # Restore autoslicing when the machineaction is dismissed
if self._backend.determineAutoSlicing(): if self._backend and self._backend.determineAutoSlicing():
self._backend.tickle() self._backend.tickle()
def _onActiveExtruderStackChanged(self): def _onActiveExtruderStackChanged(self):

View File

@ -118,24 +118,23 @@ class VersionUpgrade27to30(VersionUpgrade):
if not parser.has_section("general"): if not parser.has_section("general"):
parser.add_section("general") parser.add_section("general")
# Need to exclude the following names: # The ultimaker 2 family
# - ultimaker2_plus ultimaker2_prefix_list = ["ultimaker2_extended_",
# - ultimaker2_go "ultimaker2_go_",
# - ultimaker2_extended "ultimaker2_"]
# - ultimaker2_extended_plus # ultimaker 2+ is a different family, so don't do anything with those
exclude_prefix_list = ["ultimaker2_plus_", exclude_prefix_list = ["ultimaker2_extended_plus_",
"ultimaker2_go_", "ultimaker2_plus_"]
"ultimaker2_extended_",
"ultimaker2_extended_plus_"] # set machine definition to "ultimaker2" for the custom quality profiles that can be for the ultimaker 2 family
file_base_name = os.path.basename(filename) file_base_name = os.path.basename(filename)
if file_base_name.startswith("ultimaker2_"): is_ultimaker2_family = False
skip_this = False if not any(file_base_name.startswith(ep) for ep in exclude_prefix_list):
for exclude_prefix in exclude_prefix_list: is_ultimaker2_family = any(file_base_name.startswith(ep) for ep in ultimaker2_prefix_list)
if file_base_name.startswith(exclude_prefix):
skip_this = True # ultimaker2 family quality profiles used to set as "fdmprinter" profiles
break if is_ultimaker2_family and parser["general"]["definition"] == "fdmprinter":
if not skip_this: parser["general"]["definition"] = "ultimaker2"
parser["general"]["definition"] = "ultimaker2"
# Update version numbers # Update version numbers
parser["general"]["version"] = "2" parser["general"]["version"] = "2"

View File

@ -63,6 +63,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "" msgstr ""
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr ""
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr ""
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr ""
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Druck vollendet" msgstr "Druck vollendet"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Plugins"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Plugins durchsuchen..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Installierte plugins..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Impresión terminada" msgstr "Impresión terminada"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Complementos"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Examinar complementos..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Complementos instalados..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Tulosta valmis" msgstr "Tulosta valmis"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Lisäosat"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Selaa lisäosia..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Asennetut lisäoset..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Impression terminée" msgstr "Impression terminée"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Plug-ins"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Parcourir les plug-ins..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Plug-ins installés..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Stampa finita" msgstr "Stampa finita"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Plugin"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Sfoglia plugin..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Plugin installati..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Print klaar" msgstr "Print klaar"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Plugins"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Door invoegtoepassingen bladeren..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Geïnstalleerde plugins..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -63,6 +63,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Drukowanie zakończone" msgstr "Drukowanie zakończone"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "W&tyczki"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Przeglądaj wtyczki..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Zainstalowane wtyczki..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -62,6 +62,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Impressão Concluída" msgstr "Impressão Concluída"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Complementos"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Navegar complementos..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Complementos instalados..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -63,6 +63,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Печать завершена" msgstr "Печать завершена"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "Плагины"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Просмотр плагинов..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Установленные плагины..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -61,6 +61,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "Baskı tamamlandı" msgstr "Baskı tamamlandı"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "&Eklentiler"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "Eklentilere göz at..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "Yüklü eklentiler..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"

View File

@ -63,6 +63,21 @@ msgctxt "@info:status"
msgid "Print finished" msgid "Print finished"
msgstr "打印完成" msgstr "打印完成"
#: Manually added for resources/Cura/Cura.qml
msgctxt "@title:menu menubar:toplevel"
msgid "P&lugins"
msgstr "插件"
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Browse plugins..."
msgstr "浏览插件..."
#: Manually added for resources/Cura/Actions.qml
msgctxt "@action:menu"
msgid "Installed plugins..."
msgstr "已安装插件..."
#: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29 #: /home/ruben/Projects/Cura/plugins/MachineSettingsAction/MachineSettingsAction.py:29
msgctxt "@action" msgctxt "@action"
msgid "Machine Settings" msgid "Machine Settings"