Move intents name and description to resource file

NP-250
This commit is contained in:
Erwan MATHIEU 2025-10-30 14:41:32 +01:00
parent 5bd93c4e52
commit 2fa770b559
5 changed files with 117 additions and 80 deletions

View file

@ -1,11 +1,11 @@
#Copyright (c) 2019 Ultimaker B.V.
#Cura is released under the terms of the LGPLv3 or higher.
import collections
from PyQt6.QtCore import Qt, QTimer
from typing import TYPE_CHECKING, Optional, Dict
from cura.Machines.Models.IntentModel import IntentModel
from cura.Machines.Models.IntentTranslations import IntentTranslations
from cura.Settings.IntentManager import IntentManager
from UM.Qt.ListModel import ListModel
from UM.Settings.ContainerRegistry import ContainerRegistry #To update the list if anything changes.
@ -29,45 +29,6 @@ class IntentCategoryModel(ListModel):
modelUpdated = pyqtSignal()
_translations = collections.OrderedDict() # type: "collections.OrderedDict[str,Dict[str,Optional[str]]]"
@classmethod
def _get_translations(cls):
"""Translations to user-visible string. Ordered by weight.
TODO: Create a solution for this name and weight to be used dynamically.
"""
if len(cls._translations) == 0:
cls._translations["default"] = {
"name": catalog.i18nc("@label", "Balanced"),
"description": catalog.i18nc("@text",
"The balanced profile is designed to strike a balance between productivity, surface quality, mechanical properties and dimensional accuracy.")
}
cls._translations["visual"] = {
"name": catalog.i18nc("@label", "Visual"),
"description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality.")
}
cls._translations["engineering"] = {
"name": catalog.i18nc("@label", "Engineering"),
"description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances.")
}
cls._translations["quick"] = {
"name": catalog.i18nc("@label", "Draft"),
"description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.")
}
cls._translations["annealing"] = {
"name": catalog.i18nc("@label", "Annealing"),
"description": catalog.i18nc("@text",
"The annealing profile requires post-processing in an oven after the print is finished. This profile retains the dimensional accuracy of the printed part after annealing and improves strength, stiffness, and thermal resistance.")
}
cls._translations["solid"] = {
"name": catalog.i18nc("@label", "Solid"),
"description": catalog.i18nc("@text",
"A highly dense and strong part but at a slower print time. Great for functional parts.")
}
return cls._translations
def __init__(self, intent_category: str) -> None:
"""Creates a new model for a certain intent category.
@ -120,7 +81,7 @@ class IntentCategoryModel(ListModel):
qualities = IntentModel()
qualities.setIntentCategory(category)
try:
weight = list(IntentCategoryModel._get_translations().keys()).index(category)
weight = IntentTranslations.getInstance().index(category)
except ValueError:
weight = 99
result.append({
@ -137,5 +98,7 @@ class IntentCategoryModel(ListModel):
def translation(category: str, key: str, default: Optional[str] = None):
"""Get a display value for a category.for categories and keys"""
display_strings = IntentCategoryModel._get_translations().get(category, {})
return display_strings.get(key, default)
try:
return IntentTranslations.getInstance().getTranslation(category)[key]
except KeyError:
return default

View file

@ -1,35 +1,74 @@
import collections
import warnings
import json
from typing import Dict, Optional
from UM.Decorators import singleton, deprecated
from UM.i18n import i18nCatalog
from UM.Logger import Logger
from UM.Resources import Resources
from typing import Dict, Optional
catalog = i18nCatalog("cura")
intent_translations = collections.OrderedDict() # type: collections.OrderedDict[str, Dict[str, Optional[str]]]
intent_translations["default"] = {
"name": catalog.i18nc("@label", "Balanced"),
"description": catalog.i18nc("@text",
"The balanced profile is designed to strike a balance between productivity, surface quality, mechanical properties and dimensional accuracy.")
}
intent_translations["visual"] = {
"name": catalog.i18nc("@label", "Visual"),
"description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality.")
}
intent_translations["engineering"] = {
"name": catalog.i18nc("@label", "Engineering"),
"description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances.")
}
intent_translations["quick"] = {
"name": catalog.i18nc("@label", "Draft"),
"description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.")
}
intent_translations["annealing"] = {
"name": catalog.i18nc("@label", "Annealing"),
"description": catalog.i18nc("@text", "The annealing profile requires post-processing in an oven after the print is finished. This profile retains the dimensional accuracy of the printed part after annealing and improves strength, stiffness, and thermal resistance.")
}
intent_translations["solid"] = {
"name": catalog.i18nc("@label", "Solid"),
"description": catalog.i18nc("@text",
"A highly dense and strong part but at a slower print time. Great for functional parts.")
}
@singleton
class IntentTranslations:
def __init__(self):
from cura.CuraApplication import CuraApplication
intents_definition_path = Resources.getPath(CuraApplication.ResourceTypes.IntentInstanceContainer, "intents.def.json")
self._intent_translations: collections.OrderedDict[str, Dict[str, str]] = collections.OrderedDict()
with open(intents_definition_path, "r") as file:
intents_data = json.load(file)
for intent_id in intents_data:
intent_definition = intents_data[intent_id]
self._intent_translations[intent_id] = {
"name": catalog.i18nc("@label", intent_definition["label"]),
"description": catalog.i18nc("@text", intent_definition["description"])
}
def index(self, intent_id: str) -> int:
"""
Get the index of the given intent key in the list
:warning: There is no checking for presence, so this will throw a ValueError if the id is not present
"""
return list(self._intent_translations.keys()).index(intent_id)
def getTranslation(self, intent_id: str) -> Dict[str, str]:
"""
Get the translation of the given intent key
:return If found, a dictionary containing the name and description of the intent
:warning: There is no checking for presence, so this will throw a KeyError if the id is not present
"""
return self._intent_translations[intent_id]
def getLabel(self, intent_id: str) -> str:
"""
Get the translated name of the given intent key
:warning: There is no checking for presence, so this will throw a KeyError if the id is not present
"""
return self.getTranslation(intent_id)["name"]
def getDescription(self, intent_id: str) -> str:
"""
Get the translated description of the given intent key
:warning: There is no checking for presence, so this will throw a KeyError if the id is not present
"""
return self.getTranslation(intent_id)["description"]
@deprecated("This method only exists to provide the old intent_translations list, it should not be used anywhere else", "5.12")
def getTranslations(self) -> collections.OrderedDict[str, Dict[str, str]]:
return self._intent_translations
def __getattr__(name):
if name == "intent_translations":
warning = ("IntentTranslations.intent_translations is deprecated since 5.12, please use the IntentTranslations "
"singleton instead. Note that the intents translations will not work as long as this old behavior "
"is used within a plugin")
Logger.log("w_once", warning)
warnings.warn(warning, DeprecationWarning, stacklevel=2)
return IntentTranslations.getInstance().getTranslations()
return None

View file

@ -14,7 +14,7 @@ from cura.Machines.ContainerTree import ContainerTree
from cura.Settings.cura_empty_instance_containers import empty_quality_changes_container
from cura.Settings.IntentManager import IntentManager
from cura.Machines.Models.MachineModelUtils import fetchLayerHeight
from cura.Machines.Models.IntentTranslations import intent_translations
from cura.Machines.Models.IntentTranslations import IntentTranslations
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -358,7 +358,12 @@ class QualityManagementModel(ListModel):
for intent_category, quality_type in available_intent_list:
if not quality_group_dict[quality_type].is_available:
continue
try:
intent_label = IntentTranslations.getInstance().getLabel(intent_category)
except KeyError:
intent_label = catalog.i18nc("@label", intent_category.title())
result.append({
"name": quality_group_dict[quality_type].name, # Use the quality name as the display name
"is_read_only": True,
@ -366,15 +371,13 @@ class QualityManagementModel(ListModel):
"quality_type": quality_type,
"quality_changes_group": None,
"intent_category": intent_category,
"section_name": catalog.i18nc("@label", intent_translations.get(intent_category, {}).get("name", catalog.i18nc("@label", intent_category.title()))),
"section_name": intent_label,
})
# Sort by quality_type for each intent category
intent_translations_list = list(intent_translations)
def getIntentWeight(intent_category):
try:
return intent_translations_list.index(intent_category)
return IntentTranslations.getInstance().index(intent_category)
except ValueError:
return 99

View file

@ -6,7 +6,7 @@ from PyQt6.QtGui import QDesktopServices
from typing import List, Optional, Dict, cast
from cura.Machines.Models.MachineListModel import MachineListModel
from cura.Machines.Models.IntentTranslations import intent_translations
from cura.Machines.Models.IntentTranslations import IntentTranslations
from cura.Settings.GlobalStack import GlobalStack
from UM.Application import Application
from UM.FlameProfiler import pyqtSlot
@ -259,13 +259,13 @@ class WorkspaceDialog(QObject):
def setIntentName(self, intent_name: str) -> None:
if self._intent_name != intent_name:
try:
self._intent_name = intent_translations[intent_name]["name"]
except:
self._intent_name = IntentTranslations.getInstance().getLabel(intent_name)
except KeyError:
self._intent_name = intent_name.title()
self.intentNameChanged.emit()
if not self._intent_name:
self._intent_name = intent_translations["default"]["name"]
self._intent_name = IntentTranslations.getInstance().getLabel("default")
self.intentNameChanged.emit()
@pyqtProperty(str, notify=activeModeChanged)

View file

@ -0,0 +1,32 @@
{
"default":
{
"label": "Balanced",
"description": "The balanced profile is designed to strike a balance between productivity, surface quality, mechanical properties and dimensional accuracy."
},
"visual":
{
"label": "Visual",
"description": "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality."
},
"engineering":
{
"label": "Engineering",
"description": "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances."
},
"quick":
{
"label": "Draft",
"description": "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction."
},
"annealing":
{
"label": "Annealing",
"description": "The annealing profile requires post-processing in an oven after the print is finished. This profile retains the dimensional accuracy of the printed part after annealing and improves strength, stiffness, and thermal resistance."
},
"solid":
{
"label": "Solid",
"description": "A highly dense and strong part but at a slower print time. Great for functional parts."
}
}