mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 21:28:58 +08:00
Merge pull request #14891 from Ultimaker/CURA-10406_fix_project_loading
CURA-10406 Fix project loading
This commit is contained in:
commit
30b2d3b1ee
@ -43,7 +43,7 @@ from .WorkspaceDialog import WorkspaceDialog
|
|||||||
i18n_catalog = i18nCatalog("cura")
|
i18n_catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
_ignored_machine_network_metadata = {
|
_ignored_machine_network_metadata: Set[str] = {
|
||||||
"um_cloud_cluster_id",
|
"um_cloud_cluster_id",
|
||||||
"um_network_key",
|
"um_network_key",
|
||||||
"um_linked_to_account",
|
"um_linked_to_account",
|
||||||
@ -55,7 +55,7 @@ _ignored_machine_network_metadata = {
|
|||||||
"capabilities",
|
"capabilities",
|
||||||
"octoprint_api_key",
|
"octoprint_api_key",
|
||||||
"is_abstract_machine"
|
"is_abstract_machine"
|
||||||
} # type: Set[str]
|
}
|
||||||
|
|
||||||
|
|
||||||
class ContainerInfo:
|
class ContainerInfo:
|
||||||
@ -69,41 +69,41 @@ class ContainerInfo:
|
|||||||
|
|
||||||
class QualityChangesInfo:
|
class QualityChangesInfo:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.name = None
|
self.name: Optional[str] = None
|
||||||
self.global_info = None
|
self.global_info = None
|
||||||
self.extruder_info_dict = {} # type: Dict[str, ContainerInfo]
|
self.extruder_info_dict: Dict[str, ContainerInfo] = {}
|
||||||
|
|
||||||
|
|
||||||
class MachineInfo:
|
class MachineInfo:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.container_id = None
|
self.container_id: Optional[str] = None
|
||||||
self.name = None
|
self.name: Optional[str] = None
|
||||||
self.definition_id = None
|
self.definition_id: Optional[str] = None
|
||||||
|
|
||||||
self.metadata_dict = {} # type: Dict[str, str]
|
self.metadata_dict: Dict[str, str] = {}
|
||||||
|
|
||||||
self.quality_type = None
|
self.quality_type: Optional[str] = None
|
||||||
self.intent_category = None
|
self.intent_category: Optional[str] = None
|
||||||
self.custom_quality_name = None
|
self.custom_quality_name: Optional[str] = None
|
||||||
self.quality_changes_info = None
|
self.quality_changes_info: Optional[QualityChangesInfo] = None
|
||||||
self.variant_info = None
|
self.variant_info: Optional[ContainerInfo] = None
|
||||||
|
|
||||||
self.definition_changes_info = None
|
self.definition_changes_info: Optional[ContainerInfo] = None
|
||||||
self.user_changes_info = None
|
self.user_changes_info: Optional[ContainerInfo] = None
|
||||||
|
|
||||||
self.extruder_info_dict = {} # type: Dict[str, ExtruderInfo]
|
self.extruder_info_dict: Dict[str, str] = {}
|
||||||
|
|
||||||
|
|
||||||
class ExtruderInfo:
|
class ExtruderInfo:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.position = None
|
self.position = None
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
self.variant_info = None
|
self.variant_info: Optional[ContainerInfo] = None
|
||||||
self.root_material_id = None
|
self.root_material_id: Optional[str] = None
|
||||||
|
|
||||||
self.definition_changes_info = None
|
self.definition_changes_info: Optional[ContainerInfo] = None
|
||||||
self.user_changes_info = None
|
self.user_changes_info: Optional[ContainerInfo] = None
|
||||||
self.intent_info = None
|
self.intent_info: Optional[ContainerInfo] = None
|
||||||
|
|
||||||
|
|
||||||
class ThreeMFWorkspaceReader(WorkspaceReader):
|
class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
@ -131,14 +131,14 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
# - variant
|
# - variant
|
||||||
self._ignored_instance_container_types = {"quality", "variant"}
|
self._ignored_instance_container_types = {"quality", "variant"}
|
||||||
|
|
||||||
self._resolve_strategies = {} # type: Dict[str, str]
|
self._resolve_strategies: Dict[str, str] = {}
|
||||||
|
|
||||||
self._id_mapping = {} # type: Dict[str, str]
|
self._id_mapping: Dict[str, str] = {}
|
||||||
|
|
||||||
# In Cura 2.5 and 2.6, the empty profiles used to have those long names
|
# In Cura 2.5 and 2.6, the empty profiles used to have those long names
|
||||||
self._old_empty_profile_id_dict = {"empty_%s" % k: "empty" for k in ["material", "variant"]}
|
self._old_empty_profile_id_dict = {"empty_%s" % k: "empty" for k in ["material", "variant"]}
|
||||||
|
|
||||||
self._old_new_materials = {} # type: Dict[str, str]
|
self._old_new_materials: Dict[str, str] = {}
|
||||||
self._machine_info = None
|
self._machine_info = None
|
||||||
|
|
||||||
def _clearState(self):
|
def _clearState(self):
|
||||||
@ -461,11 +461,15 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
|
|
||||||
materials_in_extruders_dict = {} # Which material is in which extruder
|
materials_in_extruders_dict = {} # Which material is in which extruder
|
||||||
|
|
||||||
# if the global stack is found, we check if there are conflicts in the extruder stacks
|
# If the global stack is found, we check if there are conflicts in the extruder stacks
|
||||||
for extruder_stack_file in extruder_stack_files:
|
for extruder_stack_file in extruder_stack_files:
|
||||||
serialized = archive.open(extruder_stack_file).read().decode("utf-8")
|
serialized = archive.open(extruder_stack_file).read().decode("utf-8")
|
||||||
|
|
||||||
|
not_upgraded_parser = ConfigParser(interpolation=None)
|
||||||
|
not_upgraded_parser.read_string(serialized)
|
||||||
|
|
||||||
serialized = ExtruderStack._updateSerialized(serialized, extruder_stack_file)
|
serialized = ExtruderStack._updateSerialized(serialized, extruder_stack_file)
|
||||||
parser = ConfigParser(interpolation = None)
|
parser = ConfigParser(interpolation=None)
|
||||||
parser.read_string(serialized)
|
parser.read_string(serialized)
|
||||||
|
|
||||||
# The check should be done for the extruder stack that's associated with the existing global stack,
|
# The check should be done for the extruder stack that's associated with the existing global stack,
|
||||||
@ -497,19 +501,26 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
extruder_info.user_changes_info = instance_container_info_dict[user_changes_id]
|
extruder_info.user_changes_info = instance_container_info_dict[user_changes_id]
|
||||||
self._machine_info.extruder_info_dict[position] = extruder_info
|
self._machine_info.extruder_info_dict[position] = extruder_info
|
||||||
|
|
||||||
|
intent_container_id = parser["containers"][str(_ContainerIndexes.Intent)]
|
||||||
|
|
||||||
intent_id = parser["containers"][str(_ContainerIndexes.Intent)]
|
intent_id = parser["containers"][str(_ContainerIndexes.Intent)]
|
||||||
if intent_id not in ("empty", "empty_intent"):
|
if intent_id not in ("empty", "empty_intent"):
|
||||||
extruder_info.intent_info = instance_container_info_dict[intent_id]
|
if intent_container_id in instance_container_info_dict:
|
||||||
|
extruder_info.intent_info = instance_container_info_dict[intent_id]
|
||||||
|
else:
|
||||||
|
# It can happen that an intent has been renamed. In that case, we should still use the old
|
||||||
|
# name, since we used that to generate the instance_container_info_dict keys.
|
||||||
|
extruder_info.intent_info = instance_container_info_dict[not_upgraded_parser["containers"][str(_ContainerIndexes.Intent)]]
|
||||||
|
|
||||||
if not machine_conflict and containers_found_dict["machine"] and global_stack:
|
if not machine_conflict and containers_found_dict["machine"] and global_stack:
|
||||||
if int(position) >= len(global_stack.extruderList):
|
if int(position) >= len(global_stack.extruderList):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
existing_extruder_stack = global_stack.extruderList[int(position)]
|
existing_extruder_stack = global_stack.extruderList[int(position)]
|
||||||
# check if there are any changes at all in any of the container stacks.
|
# Check if there are any changes at all in any of the container stacks.
|
||||||
id_list = self._getContainerIdListFromSerialized(serialized)
|
id_list = self._getContainerIdListFromSerialized(serialized)
|
||||||
for index, container_id in enumerate(id_list):
|
for index, container_id in enumerate(id_list):
|
||||||
# take into account the old empty container IDs
|
# Take into account the old empty container IDs
|
||||||
container_id = self._old_empty_profile_id_dict.get(container_id, container_id)
|
container_id = self._old_empty_profile_id_dict.get(container_id, container_id)
|
||||||
if existing_extruder_stack.getContainer(index).getId() != container_id:
|
if existing_extruder_stack.getContainer(index).getId() != container_id:
|
||||||
machine_conflict = True
|
machine_conflict = True
|
||||||
@ -740,7 +751,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
# quality_changes file. If that's the case, take the extruder count into account when creating the machine
|
# quality_changes file. If that's the case, take the extruder count into account when creating the machine
|
||||||
# or else the extruderList will return only the first extruder, leading to missing non-global settings in
|
# or else the extruderList will return only the first extruder, leading to missing non-global settings in
|
||||||
# the other extruders.
|
# the other extruders.
|
||||||
machine_extruder_count = self._getMachineExtruderCount() # type: Optional[int]
|
machine_extruder_count: Optional[int] = self._getMachineExtruderCount()
|
||||||
global_stack = CuraStackBuilder.createMachine(machine_name, self._machine_info.definition_id, machine_extruder_count)
|
global_stack = CuraStackBuilder.createMachine(machine_name, self._machine_info.definition_id, machine_extruder_count)
|
||||||
if global_stack: # Only switch if creating the machine was successful.
|
if global_stack: # Only switch if creating the machine was successful.
|
||||||
extruder_stack_dict = {str(position): extruder for position, extruder in enumerate(global_stack.extruderList)}
|
extruder_stack_dict = {str(position): extruder for position, extruder in enumerate(global_stack.extruderList)}
|
||||||
@ -867,7 +878,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _loadMetadata(file_name: str) -> Dict[str, Dict[str, Any]]:
|
def _loadMetadata(file_name: str) -> Dict[str, Dict[str, Any]]:
|
||||||
result = dict() # type: Dict[str, Dict[str, Any]]
|
result: Dict[str, Dict[str, Any]] = dict()
|
||||||
try:
|
try:
|
||||||
archive = zipfile.ZipFile(file_name, "r")
|
archive = zipfile.ZipFile(file_name, "r")
|
||||||
except zipfile.BadZipFile:
|
except zipfile.BadZipFile:
|
||||||
@ -879,7 +890,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
|
|
||||||
metadata_files = [name for name in archive.namelist() if name.endswith("plugin_metadata.json")]
|
metadata_files = [name for name in archive.namelist() if name.endswith("plugin_metadata.json")]
|
||||||
|
|
||||||
|
|
||||||
for metadata_file in metadata_files:
|
for metadata_file in metadata_files:
|
||||||
try:
|
try:
|
||||||
plugin_id = metadata_file.split("/")[0]
|
plugin_id = metadata_file.split("/")[0]
|
||||||
@ -920,7 +930,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
quality_changes_name = self._container_registry.uniqueName(quality_changes_name)
|
quality_changes_name = self._container_registry.uniqueName(quality_changes_name)
|
||||||
for position, container_info in container_info_dict.items():
|
for position, container_info in container_info_dict.items():
|
||||||
extruder_stack = None
|
extruder_stack = None
|
||||||
intent_category = None # type: Optional[str]
|
intent_category: Optional[str] = None
|
||||||
if position is not None:
|
if position is not None:
|
||||||
try:
|
try:
|
||||||
extruder_stack = global_stack.extruderList[int(position)]
|
extruder_stack = global_stack.extruderList[int(position)]
|
||||||
@ -1161,7 +1171,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||||||
root_material_id = self._old_new_materials.get(root_material_id, root_material_id)
|
root_material_id = self._old_new_materials.get(root_material_id, root_material_id)
|
||||||
|
|
||||||
material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
|
material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
|
||||||
extruder_stack.material = material_node.container # type: InstanceContainer
|
extruder_stack.material = material_node.container
|
||||||
|
|
||||||
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
|
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
|
||||||
# Clear all first
|
# Clear all first
|
||||||
|
@ -10,6 +10,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
upgrade = VersionUpgrade52to53.VersionUpgrade52to53()
|
upgrade = VersionUpgrade52to53.VersionUpgrade52to53()
|
||||||
|
|
||||||
|
|
||||||
def getMetaData() -> Dict[str, Any]:
|
def getMetaData() -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"version_upgrade": {
|
"version_upgrade": {
|
||||||
@ -21,6 +22,7 @@ def getMetaData() -> Dict[str, Any]:
|
|||||||
("quality_changes", 4000020): ("quality_changes", 4000021, upgrade.upgradeInstanceContainer),
|
("quality_changes", 4000020): ("quality_changes", 4000021, upgrade.upgradeInstanceContainer),
|
||||||
("quality", 4000020): ("quality", 4000021, upgrade.upgradeInstanceContainer),
|
("quality", 4000020): ("quality", 4000021, upgrade.upgradeInstanceContainer),
|
||||||
("user", 4000020): ("user", 4000021, upgrade.upgradeInstanceContainer),
|
("user", 4000020): ("user", 4000021, upgrade.upgradeInstanceContainer),
|
||||||
|
("intent", 4000020): ("intent", 4000021, upgrade.upgradeInstanceContainer),
|
||||||
},
|
},
|
||||||
"sources": {
|
"sources": {
|
||||||
"preferences": {
|
"preferences": {
|
||||||
|
@ -811,18 +811,18 @@ msgctxt "@text"
|
|||||||
msgid "Unknown error."
|
msgid "Unknown error."
|
||||||
msgstr "Error desconocido."
|
msgstr "Error desconocido."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:547
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:559
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:status Don't translate the XML tags <filename> or <message>!"
|
msgctxt "@info:status Don't translate the XML tags <filename> or <message>!"
|
||||||
msgid "Project file <filename>{0}</filename> contains an unknown machine type <message>{1}</message>. Cannot import the machine. Models will be imported instead."
|
msgid "Project file <filename>{0}</filename> contains an unknown machine type <message>{1}</message>. Cannot import the machine. Models will be imported instead."
|
||||||
msgstr "El archivo del proyecto <filename>{0}</filename> contiene un tipo de máquina desconocida <message>{1}</message>. No se puede importar la máquina, en su lugar, se importarán los modelos."
|
msgstr "El archivo del proyecto <filename>{0}</filename> contiene un tipo de máquina desconocida <message>{1}</message>. No se puede importar la máquina, en su lugar, se importarán los modelos."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:550
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:562
|
||||||
msgctxt "@info:title"
|
msgctxt "@info:title"
|
||||||
msgid "Open Project File"
|
msgid "Open Project File"
|
||||||
msgstr "Abrir archivo de proyecto"
|
msgstr "Abrir archivo de proyecto"
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:631
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:643
|
||||||
#: plugins/3MFReader/WorkspaceDialog.qml:99
|
#: plugins/3MFReader/WorkspaceDialog.qml:99
|
||||||
#: plugins/3MFReader/WorkspaceDialog.qml:127
|
#: plugins/3MFReader/WorkspaceDialog.qml:127
|
||||||
#: plugins/3MFReader/WorkspaceDialog.qml:134
|
#: plugins/3MFReader/WorkspaceDialog.qml:134
|
||||||
@ -830,27 +830,27 @@ msgctxt "@button"
|
|||||||
msgid "Create new"
|
msgid "Create new"
|
||||||
msgstr "Crear nuevo"
|
msgstr "Crear nuevo"
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:681
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:693
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
||||||
msgid "Project file <filename>{0}</filename> is suddenly inaccessible: <message>{1}</message>."
|
msgid "Project file <filename>{0}</filename> is suddenly inaccessible: <message>{1}</message>."
|
||||||
msgstr "El archivo de proyecto <filename>{0}</filename> está repentinamente inaccesible: <message>{1}</message>."
|
msgstr "El archivo de proyecto <filename>{0}</filename> está repentinamente inaccesible: <message>{1}</message>."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:682
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:694
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:690
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:702
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:709
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:721
|
||||||
msgctxt "@info:title"
|
msgctxt "@info:title"
|
||||||
msgid "Can't Open Project File"
|
msgid "Can't Open Project File"
|
||||||
msgstr "No se puede abrir el archivo de proyecto"
|
msgstr "No se puede abrir el archivo de proyecto"
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:689
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:701
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:707
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:719
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
||||||
msgid "Project file <filename>{0}</filename> is corrupt: <message>{1}</message>."
|
msgid "Project file <filename>{0}</filename> is corrupt: <message>{1}</message>."
|
||||||
msgstr "El archivo de proyecto <filename>{0}</filename> está dañado: <message>{1}</message>."
|
msgstr "El archivo de proyecto <filename>{0}</filename> está dañado: <message>{1}</message>."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:754
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:766
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:error Don't translate the XML tag <filename>!"
|
msgctxt "@info:error Don't translate the XML tag <filename>!"
|
||||||
msgid "Project file <filename>{0}</filename> is made using profiles that are unknown to this version of UltiMaker Cura."
|
msgid "Project file <filename>{0}</filename> is made using profiles that are unknown to this version of UltiMaker Cura."
|
||||||
|
@ -807,18 +807,18 @@ msgctxt "@text"
|
|||||||
msgid "Unknown error."
|
msgid "Unknown error."
|
||||||
msgstr "Неизвестная ошибка."
|
msgstr "Неизвестная ошибка."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:547
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:559
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:status Don't translate the XML tags <filename> or <message>!"
|
msgctxt "@info:status Don't translate the XML tags <filename> or <message>!"
|
||||||
msgid "Project file <filename>{0}</filename> contains an unknown machine type <message>{1}</message>. Cannot import the machine. Models will be imported instead."
|
msgid "Project file <filename>{0}</filename> contains an unknown machine type <message>{1}</message>. Cannot import the machine. Models will be imported instead."
|
||||||
msgstr "Файл проекта <filename>{0}</filename> содержит неизвестный тип принтера <message>{1}</message>. Не удалось импортировать принтер. Вместо этого будут импортированы модели."
|
msgstr "Файл проекта <filename>{0}</filename> содержит неизвестный тип принтера <message>{1}</message>. Не удалось импортировать принтер. Вместо этого будут импортированы модели."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:550
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:562
|
||||||
msgctxt "@info:title"
|
msgctxt "@info:title"
|
||||||
msgid "Open Project File"
|
msgid "Open Project File"
|
||||||
msgstr "Открыть файл проекта"
|
msgstr "Открыть файл проекта"
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:631
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:643
|
||||||
#: plugins/3MFReader/WorkspaceDialog.qml:99
|
#: plugins/3MFReader/WorkspaceDialog.qml:99
|
||||||
#: plugins/3MFReader/WorkspaceDialog.qml:127
|
#: plugins/3MFReader/WorkspaceDialog.qml:127
|
||||||
#: plugins/3MFReader/WorkspaceDialog.qml:134
|
#: plugins/3MFReader/WorkspaceDialog.qml:134
|
||||||
@ -826,27 +826,27 @@ msgctxt "@button"
|
|||||||
msgid "Create new"
|
msgid "Create new"
|
||||||
msgstr "Создать новый"
|
msgstr "Создать новый"
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:681
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:693
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
||||||
msgid "Project file <filename>{0}</filename> is suddenly inaccessible: <message>{1}</message>."
|
msgid "Project file <filename>{0}</filename> is suddenly inaccessible: <message>{1}</message>."
|
||||||
msgstr "Файл проекта <filename>{0}</filename> внезапно стал недоступен: <message>{1}.</message>."
|
msgstr "Файл проекта <filename>{0}</filename> внезапно стал недоступен: <message>{1}.</message>."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:682
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:694
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:690
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:702
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:709
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:721
|
||||||
msgctxt "@info:title"
|
msgctxt "@info:title"
|
||||||
msgid "Can't Open Project File"
|
msgid "Can't Open Project File"
|
||||||
msgstr "Невозможно открыть файл проекта"
|
msgstr "Невозможно открыть файл проекта"
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:689
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:701
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:707
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:719
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
msgctxt "@info:error Don't translate the XML tags <filename> or <message>!"
|
||||||
msgid "Project file <filename>{0}</filename> is corrupt: <message>{1}</message>."
|
msgid "Project file <filename>{0}</filename> is corrupt: <message>{1}</message>."
|
||||||
msgstr "Файл проекта <filename>{0}</filename> поврежден: <message>{1}</message>."
|
msgstr "Файл проекта <filename>{0}</filename> поврежден: <message>{1}</message>."
|
||||||
|
|
||||||
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:754
|
#: plugins/3MFReader/ThreeMFWorkspaceReader.py:766
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "@info:error Don't translate the XML tag <filename>!"
|
msgctxt "@info:error Don't translate the XML tag <filename>!"
|
||||||
msgid "Project file <filename>{0}</filename> is made using profiles that are unknown to this version of UltiMaker Cura."
|
msgid "Project file <filename>{0}</filename> is made using profiles that are unknown to this version of UltiMaker Cura."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user