From 080eaa2539e922f7a5d590ea4afcc18c13b4b157 Mon Sep 17 00:00:00 2001 From: Mouhamed DIOP Date: Wed, 6 Sep 2023 08:11:06 +0000 Subject: [PATCH] BUG: Make translatable Editor effects titles in Segmentations Enables fixing of these Slicer/SlicerLanguagePacks#12 Slicer#6177 --- ...ScriptedSegmentEditorAutoCompleteEffect.py | 37 +++--- .../Python/SegmentEditorDrawEffect.py | 18 +-- .../SegmentEditorFillBetweenSlicesEffect.py | 27 +++-- .../SegmentEditorGrowFromSeedsEffect.py | 42 +++---- .../Python/SegmentEditorHollowEffect.py | 40 ++++--- .../Python/SegmentEditorIslandsEffect.py | 44 +++---- .../Python/SegmentEditorLevelTracingEffect.py | 23 ++-- .../Python/SegmentEditorLogicalEffect.py | 72 ++++++------ .../Python/SegmentEditorMarginEffect.py | 39 ++++--- .../Python/SegmentEditorMaskVolumeEffect.py | 67 ++++++----- .../Python/SegmentEditorSmoothingEffect.py | 71 ++++++------ .../Python/SegmentEditorThresholdEffect.py | 109 +++++++++--------- .../qSlicerSegmentEditorAbstractEffect.cxx | 24 ++++ .../qSlicerSegmentEditorAbstractEffect.h | 15 ++- .../qSlicerSegmentEditorEraseEffect.cxx | 1 + .../qSlicerSegmentEditorPaintEffect.cxx | 1 + .../qSlicerSegmentEditorScissorsEffect.cxx | 1 + .../Widgets/qMRMLSegmentEditorWidget.cxx | 6 +- ...RMLSegmentationRepresentationsListView.cxx | 3 +- 19 files changed, 359 insertions(+), 281 deletions(-) diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/AbstractScriptedSegmentEditorAutoCompleteEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/AbstractScriptedSegmentEditorAutoCompleteEffect.py index dae44b105b7..a6cf3f729b5 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/AbstractScriptedSegmentEditorAutoCompleteEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/AbstractScriptedSegmentEditorAutoCompleteEffect.py @@ -5,6 +5,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from .AbstractScriptedSegmentEditorEffect import * @@ -86,14 +87,14 @@ def isBackgroundLabelmap(labelmapOrientedImageData, label=None): return False def setupOptionsFrame(self): - self.autoUpdateCheckBox = qt.QCheckBox("Auto-update") - self.autoUpdateCheckBox.setToolTip("Auto-update results preview when input segments change.") + self.autoUpdateCheckBox = qt.QCheckBox(_("Auto-update")) + self.autoUpdateCheckBox.setToolTip(_("Auto-update results preview when input segments change.")) self.autoUpdateCheckBox.setChecked(True) self.autoUpdateCheckBox.setEnabled(False) - self.previewButton = qt.QPushButton("Initialize") + self.previewButton = qt.QPushButton(_("Initialize")) self.previewButton.objectName = self.__class__.__name__ + 'Preview' - self.previewButton.setToolTip("Preview complete segmentation") + self.previewButton.setToolTip(_("Preview complete segmentation")) # qt.QSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding) # fails on some systems, therefore set the policies using separate method calls qSize = qt.QSizePolicy() @@ -103,10 +104,10 @@ def setupOptionsFrame(self): previewFrame = qt.QHBoxLayout() previewFrame.addWidget(self.autoUpdateCheckBox) previewFrame.addWidget(self.previewButton) - self.scriptedEffect.addLabeledOptionsWidget("Preview:", previewFrame) + self.scriptedEffect.addLabeledOptionsWidget(_("Preview:"), previewFrame) self.previewOpacitySlider = ctk.ctkSliderWidget() - self.previewOpacitySlider.setToolTip("Adjust visibility of results preview.") + self.previewOpacitySlider.setToolTip(_("Adjust visibility of results preview.")) self.previewOpacitySlider.minimum = 0 self.previewOpacitySlider.maximum = 1.0 self.previewOpacitySlider.value = 0.0 @@ -114,24 +115,24 @@ def setupOptionsFrame(self): self.previewOpacitySlider.pageStep = 0.1 self.previewOpacitySlider.spinBoxVisible = False - self.previewShow3DButton = qt.QPushButton("Show 3D") - self.previewShow3DButton.setToolTip("Preview results in 3D.") + self.previewShow3DButton = qt.QPushButton(_("Show 3D")) + self.previewShow3DButton.setToolTip(_("Preview results in 3D.")) self.previewShow3DButton.setCheckable(True) displayFrame = qt.QHBoxLayout() - displayFrame.addWidget(qt.QLabel("inputs")) + displayFrame.addWidget(qt.QLabel(_("inputs"))) displayFrame.addWidget(self.previewOpacitySlider) - displayFrame.addWidget(qt.QLabel("results")) + displayFrame.addWidget(qt.QLabel(_("results"))) displayFrame.addWidget(self.previewShow3DButton) - self.scriptedEffect.addLabeledOptionsWidget("Display:", displayFrame) + self.scriptedEffect.addLabeledOptionsWidget(_("Display:"), displayFrame) - self.cancelButton = qt.QPushButton("Cancel") + self.cancelButton = qt.QPushButton(_("Cancel")) self.cancelButton.objectName = self.__class__.__name__ + 'Cancel' - self.cancelButton.setToolTip("Clear preview and cancel auto-complete") + self.cancelButton.setToolTip(_("Clear preview and cancel auto-complete")) - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' - self.applyButton.setToolTip("Replace segments by previewed result") + self.applyButton.setToolTip(_("Replace segments by previewed result")) finishFrame = qt.QHBoxLayout() finishFrame.addWidget(self.cancelButton) @@ -244,13 +245,13 @@ def updateGUIFromMRML(self): wasBlocked = self.previewOpacitySlider.blockSignals(True) self.previewOpacitySlider.value = self.getPreviewOpacity() self.previewOpacitySlider.blockSignals(wasBlocked) - self.previewButton.text = "Update" + self.previewButton.text = _("Update") self.previewShow3DButton.setEnabled(True) self.previewShow3DButton.setChecked(self.getPreviewShow3D()) self.autoUpdateCheckBox.setEnabled(True) self.observeSegmentation(self.autoUpdateCheckBox.isChecked()) else: - self.previewButton.text = "Initialize" + self.previewButton.text = _("Initialize") self.autoUpdateCheckBox.setEnabled(False) self.previewShow3DButton.setEnabled(False) self.delayedAutoUpdateTimer.stop() @@ -276,7 +277,7 @@ def onPreview(self): return self.previewComputationInProgress = True - slicer.util.showStatusMessage(f"Running {self.scriptedEffect.name} auto-complete...", 2000) + slicer.util.showStatusMessage(_("Running {effectName} auto-complete...").format(effectName=self.scriptedEffect.name), 2000) try: # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorDrawEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorDrawEffect.py index b3e70323c4b..36beadf0daa 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorDrawEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorDrawEffect.py @@ -5,6 +5,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -15,7 +16,8 @@ class SegmentEditorDrawEffect(AbstractScriptedSegmentEditorLabelEffect): """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Draw' + scriptedEffect.name = 'Draw' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Draw') self.drawPipelines = {} AbstractScriptedSegmentEditorLabelEffect.__init__(self, scriptedEffect) @@ -32,13 +34,13 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Draw segment outline in slice viewers
. -

""" + return _("""Draw segment outline in slice viewers
. +

""") def deactivate(self): # Clear draw pipelines diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorFillBetweenSlicesEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorFillBetweenSlicesEffect.py index 7b881a8ec32..0a1b15b8ea2 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorFillBetweenSlicesEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorFillBetweenSlicesEffect.py @@ -3,6 +3,8 @@ import qt import vtk +from slicer.i18n import tr as _ + from SegmentEditorEffects import * @@ -14,7 +16,8 @@ class SegmentEditorFillBetweenSlicesEffect(AbstractScriptedSegmentEditorAutoComp def __init__(self, scriptedEffect): AbstractScriptedSegmentEditorAutoCompleteEffect.__init__(self, scriptedEffect) - scriptedEffect.name = 'Fill between slices' + scriptedEffect.name = 'Fill between slices' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Fill between slices') def clone(self): import qSlicerSegmentationsEditorEffectsPythonQt as effects @@ -29,17 +32,17 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Interpolate segmentation between slices
. Instructions: -

-Masking settings are ignored. If segments overlap, segment higher in the segments table will have priority. -The effect uses morphological contour interpolation method. -

""" + return _("""Interpolate segmentation between slices
. Instructions: +

+ Masking settings are ignored. If segments overlap, segment higher in the segments table will have priority. + The effect uses morphological contour interpolation method. +

""") def computePreviewLabelmap(self, mergedImage, outputLabelmap): import vtkITK diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorGrowFromSeedsEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorGrowFromSeedsEffect.py index 1d9b9980720..aeb383e38cc 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorGrowFromSeedsEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorGrowFromSeedsEffect.py @@ -6,6 +6,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -18,7 +19,8 @@ class SegmentEditorGrowFromSeedsEffect(AbstractScriptedSegmentEditorAutoComplete def __init__(self, scriptedEffect): AbstractScriptedSegmentEditorAutoCompleteEffect.__init__(self, scriptedEffect) - scriptedEffect.name = 'Grow from seeds' + scriptedEffect.name = 'Grow from seeds' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Grow from seeds') self.minimumNumberOfSegments = 2 self.clippedMasterImageDataRequired = True # source volume intensities are used by this effect self.clippedMaskImageDataRequired = True # masking is used @@ -37,21 +39,21 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Growing segments to create complete segmentation
. -Location, size, and shape of initial segments and content of source volume are taken into account. -Final segment boundaries will be placed where source volume brightness changes abruptly. Instructions:

-

-If segments overlap, segment higher in the segments table will have priority. -The effect uses fast grow-cut method. -

""" + return _("""Growing segments to create complete segmentation
. + Location, size, and shape of initial segments and content of source volume are taken into account. + Final segment boundaries will be placed where source volume brightness changes abruptly. Instructions:

+

+ If segments overlap, segment higher in the segments table will have priority. + The effect uses fast grow-cut method. +

""") def reset(self): self.growCutFilter = None @@ -70,10 +72,10 @@ def setupOptionsFrame(self): self.seedLocalityFactorSlider.decimals = 1 self.seedLocalityFactorSlider.singleStep = 0.1 self.seedLocalityFactorSlider.pageStep = 1.0 - self.seedLocalityFactorSlider.setToolTip('Increasing this value makes the effect of seeds more localized,' - ' thereby reducing leaks, but requires seed regions to be more evenly distributed in the image.' - ' The value is specified as an additional "intensity level difference" per "unit distance."') - self.scriptedEffect.addLabeledOptionsWidget("Seed locality:", self.seedLocalityFactorSlider) + self.seedLocalityFactorSlider.setToolTip(_('Increasing this value makes the effect of seeds more localized,' + ' thereby reducing leaks, but requires seed regions to be more evenly distributed in the image.' + ' The value is specified as an additional "intensity level difference" per "unit distance."')) + self.scriptedEffect.addLabeledOptionsWidget(_("Seed locality:"), self.seedLocalityFactorSlider) self.seedLocalityFactorSlider.connect('valueChanged(double)', self.updateAlgorithmParameterFromGUI) def setMRMLDefaults(self): diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorHollowEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorHollowEffect.py index d444f12124e..37b82ca5e9e 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorHollowEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorHollowEffect.py @@ -6,6 +6,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -14,7 +15,8 @@ class SegmentEditorHollowEffect(AbstractScriptedSegmentEditorEffect): """This effect makes a segment hollow by replacing it with a shell at the segment boundary""" def __init__(self, scriptedEffect): - scriptedEffect.name = 'Hollow' + scriptedEffect.name = 'Hollow' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Hollow') AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect) def clone(self): @@ -30,47 +32,48 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Make the selected segment hollow by replacing the segment with a uniform-thickness shell defined by the segment boundary.""" + return _("""Make the selected segment hollow by replacing the segment with a uniform-thickness shell defined by the segment boundary.""") def setupOptionsFrame(self): operationLayout = qt.QVBoxLayout() - self.insideSurfaceOptionRadioButton = qt.QRadioButton("inside surface") - self.medialSurfaceOptionRadioButton = qt.QRadioButton("medial surface") - self.outsideSurfaceOptionRadioButton = qt.QRadioButton("outside surface") + self.insideSurfaceOptionRadioButton = qt.QRadioButton(_("inside surface")) + self.medialSurfaceOptionRadioButton = qt.QRadioButton(_("medial surface")) + self.outsideSurfaceOptionRadioButton = qt.QRadioButton(_("outside surface")) operationLayout.addWidget(self.insideSurfaceOptionRadioButton) operationLayout.addWidget(self.medialSurfaceOptionRadioButton) operationLayout.addWidget(self.outsideSurfaceOptionRadioButton) self.insideSurfaceOptionRadioButton.setChecked(True) - self.scriptedEffect.addLabeledOptionsWidget("Use current segment as:", operationLayout) + self.scriptedEffect.addLabeledOptionsWidget(_("Use current segment as:"), operationLayout) self.shellThicknessMMSpinBox = slicer.qMRMLSpinBox() self.shellThicknessMMSpinBox.setMRMLScene(slicer.mrmlScene) - self.shellThicknessMMSpinBox.setToolTip("Thickness of the hollow shell.") + self.shellThicknessMMSpinBox.setToolTip(_("Thickness of the hollow shell.")) self.shellThicknessMMSpinBox.quantity = "length" self.shellThicknessMMSpinBox.minimum = 0.0 self.shellThicknessMMSpinBox.value = 3.0 self.shellThicknessMMSpinBox.singleStep = 1.0 self.shellThicknessLabel = qt.QLabel() - self.shellThicknessLabel.setToolTip("Closest achievable thickness. Constrained by the segmentation's binary labelmap representation spacing.") + self.shellThicknessLabel.setToolTip(_("Closest achievable thickness. Constrained by the segmentation's binary labelmap representation spacing.")) shellThicknessFrame = qt.QHBoxLayout() shellThicknessFrame.addWidget(self.shellThicknessMMSpinBox) - self.shellThicknessMMLabel = self.scriptedEffect.addLabeledOptionsWidget("Shell thickness:", shellThicknessFrame) + self.shellThicknessMMLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Shell thickness:"), shellThicknessFrame) self.scriptedEffect.addLabeledOptionsWidget("", self.shellThicknessLabel) self.applyToAllVisibleSegmentsCheckBox = qt.QCheckBox() - self.applyToAllVisibleSegmentsCheckBox.setToolTip("Apply hollow effect to all visible segments in this segmentation node. \ - This operation may take a while.") + self.applyToAllVisibleSegmentsCheckBox.setToolTip(_("Apply hollow effect to all visible segments in this segmentation node. \ + This operation may take a while.")) self.applyToAllVisibleSegmentsCheckBox.objectName = self.__class__.__name__ + 'ApplyToAllVisibleSegments' - self.applyToAllVisibleSegmentsLabel = self.scriptedEffect.addLabeledOptionsWidget("Apply to visible segments:", self.applyToAllVisibleSegmentsCheckBox) + self.applyToAllVisibleSegmentsLabel = self.scriptedEffect.addLabeledOptionsWidget( + _("Apply to visible segments:"), self.applyToAllVisibleSegmentsCheckBox) - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' - self.applyButton.setToolTip("Makes the segment hollow by replacing it with a thick shell at the segment boundary.") + self.applyButton.setToolTip(_("Makes the segment hollow by replacing it with a thick shell at the segment boundary.")) self.scriptedEffect.addOptionsWidget(self.applyButton) self.applyButton.connect('clicked()', self.onApply) @@ -124,14 +127,14 @@ def updateGUIFromMRML(self): selectedSegmentLabelmapSpacing = selectedSegmentLabelmap.GetSpacing() shellThicknessPixel = self.getShellThicknessPixel() if shellThicknessPixel[0] < 1 or shellThicknessPixel[1] < 1 or shellThicknessPixel[2] < 1: - self.shellThicknessLabel.text = "Not feasible at current resolution." + self.shellThicknessLabel.text = _("Not feasible at current resolution.") self.applyButton.setEnabled(False) else: thicknessMM = self.getShellThicknessMM() - self.shellThicknessLabel.text = "Actual: {} x {} x {} mm ({}x{}x{} pixel)".format(*thicknessMM, *shellThicknessPixel) + self.shellThicknessLabel.text = _("Actual:") + " {} x {} x {} mm ({}x{}x{} pixel)".format(*thicknessMM, *shellThicknessPixel) self.applyButton.setEnabled(True) else: - self.shellThicknessLabel.text = "Empty segment" + self.shellThicknessLabel.text = _("Empty segment") self.setWidgetMinMaxStepFromImageSpacing(self.shellThicknessMMSpinBox, self.scriptedEffect.selectedSegmentLabelmap()) @@ -242,7 +245,8 @@ def onApply(self): # select input segments one by one, process for index in range(inputSegmentIDs.GetNumberOfValues()): segmentID = inputSegmentIDs.GetValue(index) - self.showStatusMessage(f'Processing {segmentationNode.GetSegmentation().GetSegment(segmentID).GetName()}...') + self.showStatusMessage(_('Processing {segmentName}...') + .format(segmentName=segmentationNode.GetSegmentation().GetSegment(segmentID).GetName())) self.scriptedEffect.parameterSetNode().SetSelectedSegmentID(segmentID) self.processHollowing() # restore segment selection diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorIslandsEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorIslandsEffect.py index 0c93eb1c2d5..f55fccd75e1 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorIslandsEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorIslandsEffect.py @@ -6,6 +6,7 @@ import vtkITK import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -15,7 +16,8 @@ class SegmentEditorIslandsEffect(AbstractScriptedSegmentEditorEffect): """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Islands' + scriptedEffect.name = 'Islands' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Islands') AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect) self.widgetToOperationNameMap = {} @@ -32,46 +34,46 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Edit islands (connected components) in a segment
. To get more information -about each operation, hover the mouse over the option and wait for the tooltip to appear.""" + return _("""Edit islands (connected components) in a segment
. To get more information + about each operation, hover the mouse over the option and wait for the tooltip to appear.""") def setupOptionsFrame(self): self.operationRadioButtons = [] - self.keepLargestOptionRadioButton = qt.QRadioButton("Keep largest island") + self.keepLargestOptionRadioButton = qt.QRadioButton(_("Keep largest island")) self.keepLargestOptionRadioButton.setToolTip( - "Keep only the largest island in selected segment, remove all other islands in the segment.") + _("Keep only the largest island in selected segment, remove all other islands in the segment.")) self.operationRadioButtons.append(self.keepLargestOptionRadioButton) self.widgetToOperationNameMap[self.keepLargestOptionRadioButton] = KEEP_LARGEST_ISLAND - self.keepSelectedOptionRadioButton = qt.QRadioButton("Keep selected island") + self.keepSelectedOptionRadioButton = qt.QRadioButton(_("Keep selected island")) self.keepSelectedOptionRadioButton.setToolTip( - "Click on an island in a slice view to keep that island and remove all other islands in selected segment.") + _("Click on an island in a slice view to keep that island and remove all other islands in selected segment.")) self.operationRadioButtons.append(self.keepSelectedOptionRadioButton) self.widgetToOperationNameMap[self.keepSelectedOptionRadioButton] = KEEP_SELECTED_ISLAND - self.removeSmallOptionRadioButton = qt.QRadioButton("Remove small islands") + self.removeSmallOptionRadioButton = qt.QRadioButton(_("Remove small islands")) self.removeSmallOptionRadioButton.setToolTip( - "Remove all islands from the selected segment that are smaller than the specified minimum size.") + _("Remove all islands from the selected segment that are smaller than the specified minimum size.")) self.operationRadioButtons.append(self.removeSmallOptionRadioButton) self.widgetToOperationNameMap[self.removeSmallOptionRadioButton] = REMOVE_SMALL_ISLANDS - self.removeSelectedOptionRadioButton = qt.QRadioButton("Remove selected island") + self.removeSelectedOptionRadioButton = qt.QRadioButton(_("Remove selected island")) self.removeSelectedOptionRadioButton.setToolTip( - "Click on an island in a slice view to remove it from selected segment.") + _("Click on an island in a slice view to remove it from selected segment.")) self.operationRadioButtons.append(self.removeSelectedOptionRadioButton) self.widgetToOperationNameMap[self.removeSelectedOptionRadioButton] = REMOVE_SELECTED_ISLAND - self.addSelectedOptionRadioButton = qt.QRadioButton("Add selected island") + self.addSelectedOptionRadioButton = qt.QRadioButton(_("Add selected island")) self.addSelectedOptionRadioButton.setToolTip( - "Click on a region in a slice view to add it to selected segment.") + _("Click on a region in a slice view to add it to selected segment.")) self.operationRadioButtons.append(self.addSelectedOptionRadioButton) self.widgetToOperationNameMap[self.addSelectedOptionRadioButton] = ADD_SELECTED_ISLAND - self.splitAllOptionRadioButton = qt.QRadioButton("Split islands to segments") + self.splitAllOptionRadioButton = qt.QRadioButton(_("Split islands to segments")) self.splitAllOptionRadioButton.setToolTip( - "Create a new segment for each island of selected segment. Islands smaller than minimum size will be removed. " + - "Segments will be ordered by island size.") + _("Create a new segment for each island of selected segment. Islands smaller than minimum size will be removed. " \ + "Segments will be ordered by island size.")) self.operationRadioButtons.append(self.splitAllOptionRadioButton) self.widgetToOperationNameMap[self.splitAllOptionRadioButton] = SPLIT_ISLANDS_TO_SEGMENTS @@ -87,14 +89,14 @@ def setupOptionsFrame(self): self.scriptedEffect.addOptionsWidget(operationLayout) self.minimumSizeSpinBox = qt.QSpinBox() - self.minimumSizeSpinBox.setToolTip("Islands consisting of less voxels than this minimum size, will be deleted.") + self.minimumSizeSpinBox.setToolTip(_("Islands consisting of less voxels than this minimum size, will be deleted.")) self.minimumSizeSpinBox.setMinimum(0) self.minimumSizeSpinBox.setMaximum(vtk.VTK_INT_MAX) self.minimumSizeSpinBox.setValue(1000) - self.minimumSizeSpinBox.suffix = " voxels" - self.minimumSizeLabel = self.scriptedEffect.addLabeledOptionsWidget("Minimum size:", self.minimumSizeSpinBox) + self.minimumSizeSpinBox.suffix = _(" voxels") + self.minimumSizeLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Minimum size:"), self.minimumSizeSpinBox) - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' self.scriptedEffect.addOptionsWidget(self.applyButton) @@ -384,7 +386,7 @@ def updateGUIFromMRML(self): segmentSelectionRequired = self.currentOperationRequiresSegmentSelection() self.applyButton.setEnabled(not segmentSelectionRequired) if segmentSelectionRequired: - self.applyButton.setToolTip("Click in a slice view to select an island.") + self.applyButton.setToolTip(_("Click in a slice view to select an island.")) else: self.applyButton.setToolTip("") diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLevelTracingEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLevelTracingEffect.py index c2137e96ce1..179fe41e18f 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLevelTracingEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLevelTracingEffect.py @@ -6,6 +6,7 @@ import vtkITK import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -16,7 +17,8 @@ class SegmentEditorLevelTracingEffect(AbstractScriptedSegmentEditorLabelEffect): """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Level tracing' + scriptedEffect.name = 'Level tracing' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Level tracing') AbstractScriptedSegmentEditorLabelEffect.__init__(self, scriptedEffect) # Effect-specific members @@ -36,12 +38,12 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Add uniform intensity region to selected segment
. -

""" + return _("""Add uniform intensity region to selected segment
. +

""") def setupOptionsFrame(self): self.sliceRotatedErrorLabel = qt.QLabel() @@ -99,9 +101,10 @@ def processInteractionEvents(self, callerInteractor, eventId, viewWidget): if pipeline.preview(xy): self.sliceRotatedErrorLabel.text = "" else: - self.sliceRotatedErrorLabel.text = ("" - + "Slice view is not aligned with segmentation axis.
To use this effect, click the 'Slice views orientation' warning button." - + "
") + self.sliceRotatedErrorLabel.text = ( + "" + + _("Slice view is not aligned with segmentation axis.
To use this effect, click the 'Slice views orientation' warning button.") + + "
") abortEvent = True self.lastXY = xy elif eventId == vtk.vtkCommand.EnterEvent: diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLogicalEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLogicalEffect.py index b0901ddd74f..37fe0f872e1 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLogicalEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorLogicalEffect.py @@ -5,6 +5,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -14,7 +15,8 @@ class SegmentEditorLogicalEffect(AbstractScriptedSegmentEditorEffect): """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Logical operators' + scriptedEffect.name = 'Logical operators' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Logical operators') self.operationsRequireModifierSegment = [LOGICAL_COPY, LOGICAL_UNION, LOGICAL_SUBTRACT, LOGICAL_INTERSECT] AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect) @@ -31,45 +33,46 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Apply logical operators or combine segments
. Available operations:

-

-Selected segment: segment selected in the segment list - above. Modifier segment: segment chosen in segment list in effect options - below. -

""" + return _("""Apply logical operators or combine segments
. Available operations:

+

+ Selected segment: segment selected in the segment list - above. Modifier segment: segment chosen in + segment list in effect options - below. +

""") def setupOptionsFrame(self): self.methodSelectorComboBox = qt.QComboBox() - self.methodSelectorComboBox.addItem("Copy", LOGICAL_COPY) - self.methodSelectorComboBox.addItem("Add", LOGICAL_UNION) - self.methodSelectorComboBox.addItem("Subtract", LOGICAL_SUBTRACT) - self.methodSelectorComboBox.addItem("Intersect", LOGICAL_INTERSECT) - self.methodSelectorComboBox.addItem("Invert", LOGICAL_INVERT) - self.methodSelectorComboBox.addItem("Clear", LOGICAL_CLEAR) - self.methodSelectorComboBox.addItem("Fill", LOGICAL_FILL) - self.methodSelectorComboBox.setToolTip('Click Show details link above for description of operations.') - - self.bypassMaskingCheckBox = qt.QCheckBox("Bypass masking") - self.bypassMaskingCheckBox.setToolTip("Ignore all masking options and only modify the selected segment.") + self.methodSelectorComboBox.addItem(_("Copy"), LOGICAL_COPY) + self.methodSelectorComboBox.addItem(_("Add"), LOGICAL_UNION) + self.methodSelectorComboBox.addItem(_("Subtract"), LOGICAL_SUBTRACT) + self.methodSelectorComboBox.addItem(_("Intersect"), LOGICAL_INTERSECT) + self.methodSelectorComboBox.addItem(_("Invert"), LOGICAL_INVERT) + self.methodSelectorComboBox.addItem(_("Clear"), LOGICAL_CLEAR) + self.methodSelectorComboBox.addItem(_("Fill"), LOGICAL_FILL) + self.methodSelectorComboBox.setToolTip(_('Click Show details link above for description of operations.')) + + self.bypassMaskingCheckBox = qt.QCheckBox(_("Bypass masking")) + self.bypassMaskingCheckBox.setToolTip(_("Ignore all masking options and only modify the selected segment.")) self.bypassMaskingCheckBox.objectName = self.__class__.__name__ + 'BypassMasking' - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' operationFrame = qt.QHBoxLayout() operationFrame.addWidget(self.methodSelectorComboBox) operationFrame.addWidget(self.applyButton) operationFrame.addWidget(self.bypassMaskingCheckBox) - self.marginSizeMmLabel = self.scriptedEffect.addLabeledOptionsWidget("Operation:", operationFrame) + self.marginSizeMmLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Operation:"), operationFrame) - self.modifierSegmentSelectorLabel = qt.QLabel("Modifier segment:") + self.modifierSegmentSelectorLabel = qt.QLabel(_("Modifier segment:")) self.scriptedEffect.addOptionsWidget(self.modifierSegmentSelectorLabel) self.modifierSegmentSelector = slicer.qMRMLSegmentsTableView() @@ -79,7 +82,8 @@ def setupOptionsFrame(self): self.modifierSegmentSelector.opacityColumnVisible = False self.modifierSegmentSelector.setMRMLScene(slicer.mrmlScene) - self.modifierSegmentSelector.setToolTip('Contents of this segment will be used for modifying the selected segment. This segment itself will not be changed.') + self.modifierSegmentSelector.setToolTip(_('Contents of this segment will be used for modifying the selected segment. ' + 'This segment itself will not be changed.')) self.scriptedEffect.addOptionsWidget(self.modifierSegmentSelector) self.applyButton.connect('clicked()', self.onApply) @@ -127,18 +131,18 @@ def updateGUIFromMRML(self): self.modifierSegmentSelector.setVisible(modifierSegmentRequired) if operation == LOGICAL_COPY: - self.modifierSegmentSelectorLabel.text = "Copy from segment:" + self.modifierSegmentSelectorLabel.text = _("Copy from segment:") elif operation == LOGICAL_UNION: - self.modifierSegmentSelectorLabel.text = "Add segment:" + self.modifierSegmentSelectorLabel.text = _("Add segment:") elif operation == LOGICAL_SUBTRACT: - self.modifierSegmentSelectorLabel.text = "Subtract segment:" + self.modifierSegmentSelectorLabel.text = _("Subtract segment:") elif operation == LOGICAL_INTERSECT: - self.modifierSegmentSelectorLabel.text = "Intersect with segment:" + self.modifierSegmentSelectorLabel.text = _("Intersect with segment:") else: - self.modifierSegmentSelectorLabel.text = "Modifier segment:" + self.modifierSegmentSelectorLabel.text = _("Modifier segment:") if modifierSegmentRequired and not modifierSegmentID: - self.applyButton.setToolTip("Please select a modifier segment in the list below.") + self.applyButton.setToolTip(_("Please select a modifier segment in the list below.")) self.applyButton.enabled = False else: self.applyButton.setToolTip("") diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMarginEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMarginEffect.py index 388fe4e53bb..2ef91c597f6 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMarginEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMarginEffect.py @@ -6,6 +6,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -15,7 +16,8 @@ class SegmentEditorMarginEffect(AbstractScriptedSegmentEditorEffect): """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Margin' + scriptedEffect.name = 'Margin' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Margin') AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect) def clone(self): @@ -31,44 +33,46 @@ def icon(self): return qt.QIcon() def helpText(self): - return "Grow or shrink selected segment by specified margin size." + return _("Grow or shrink selected segment by specified margin size.") def setupOptionsFrame(self): operationLayout = qt.QVBoxLayout() - self.shrinkOptionRadioButton = qt.QRadioButton("Shrink") - self.growOptionRadioButton = qt.QRadioButton("Grow") + self.shrinkOptionRadioButton = qt.QRadioButton(_("Shrink")) + self.growOptionRadioButton = qt.QRadioButton(_("Grow")) operationLayout.addWidget(self.shrinkOptionRadioButton) operationLayout.addWidget(self.growOptionRadioButton) self.growOptionRadioButton.setChecked(True) - self.scriptedEffect.addLabeledOptionsWidget("Operation:", operationLayout) + self.scriptedEffect.addLabeledOptionsWidget(_("Operation:"), operationLayout) self.marginSizeMMSpinBox = slicer.qMRMLSpinBox() self.marginSizeMMSpinBox.setMRMLScene(slicer.mrmlScene) - self.marginSizeMMSpinBox.setToolTip("Segment boundaries will be shifted by this distance. Positive value means the segments will grow, negative value means segment will shrink.") + self.marginSizeMMSpinBox.setToolTip(_("Segment boundaries will be shifted by this distance. " + "Positive value means the segments will grow, negative value means segment will shrink.")) self.marginSizeMMSpinBox.quantity = "length" self.marginSizeMMSpinBox.value = 3.0 self.marginSizeMMSpinBox.singleStep = 1.0 self.marginSizeLabel = qt.QLabel() - self.marginSizeLabel.setToolTip("Size change in pixel. Computed from the segment's spacing and the specified margin size.") + self.marginSizeLabel.setToolTip(_("Size change in pixel. Computed from the segment's spacing and the specified margin size.")) marginSizeFrame = qt.QHBoxLayout() marginSizeFrame.addWidget(self.marginSizeMMSpinBox) - self.marginSizeMMLabel = self.scriptedEffect.addLabeledOptionsWidget("Margin size:", marginSizeFrame) + self.marginSizeMMLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Margin size:"), marginSizeFrame) self.scriptedEffect.addLabeledOptionsWidget("", self.marginSizeLabel) self.applyToAllVisibleSegmentsCheckBox = qt.QCheckBox() - self.applyToAllVisibleSegmentsCheckBox.setToolTip("Grow or shrink all visible segments in this segmentation node. \ - This operation may take a while.") + self.applyToAllVisibleSegmentsCheckBox.setToolTip(_("Grow or shrink all visible segments in this segmentation node. \ + This operation may take a while.")) self.applyToAllVisibleSegmentsCheckBox.objectName = self.__class__.__name__ + 'ApplyToAllVisibleSegments' - self.applyToAllVisibleSegmentsLabel = self.scriptedEffect.addLabeledOptionsWidget("Apply to visible segments:", self.applyToAllVisibleSegmentsCheckBox) + self.applyToAllVisibleSegmentsLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Apply to visible segments:"), + self.applyToAllVisibleSegmentsCheckBox) - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' - self.applyButton.setToolTip("Grows or shrinks selected segment /default) or all segments (checkbox) by the specified margin.") + self.applyButton.setToolTip(_("Grows or shrinks selected segment /default) or all segments (checkbox) by the specified margin.")) self.scriptedEffect.addOptionsWidget(self.applyButton) self.applyButton.connect('clicked()', self.onApply) @@ -115,14 +119,14 @@ def updateGUIFromMRML(self): selectedSegmentLabelmapSpacing = selectedSegmentLabelmap.GetSpacing() marginSizePixel = self.getMarginSizePixel() if marginSizePixel[0] < 1 or marginSizePixel[1] < 1 or marginSizePixel[2] < 1: - self.marginSizeLabel.text = "Not feasible at current resolution." + self.marginSizeLabel.text = _("Not feasible at current resolution.") self.applyButton.setEnabled(False) else: marginSizeMM = self.getMarginSizeMM() - self.marginSizeLabel.text = "Actual: {} x {} x {} mm ({}x{}x{} pixel)".format(*marginSizeMM, *marginSizePixel) + self.marginSizeLabel.text = _("Actual:") + " {} x {} x {} mm ({}x{}x{} pixel)".format(*marginSizeMM, *marginSizePixel) self.applyButton.setEnabled(True) else: - self.marginSizeLabel.text = "Empty segment" + self.marginSizeLabel.text = _("Empty segment") applyToAllVisibleSegments = qt.Qt.Unchecked if self.scriptedEffect.integerParameter("ApplyToAllVisibleSegments") == 0 else qt.Qt.Checked wasBlocked = self.applyToAllVisibleSegmentsCheckBox.blockSignals(True) @@ -234,7 +238,8 @@ def onApply(self): # select input segments one by one, process for index in range(inputSegmentIDs.GetNumberOfValues()): segmentID = inputSegmentIDs.GetValue(index) - self.showStatusMessage(f'Processing {segmentationNode.GetSegmentation().GetSegment(segmentID).GetName()}...') + self.showStatusMessage(_('Processing {segmentName}...') + .format(segmentName=segmentationNode.GetSegmentation().GetSegment(segmentID).GetName())) self.scriptedEffect.parameterSetNode().SetSelectedSegmentID(segmentID) self.processMargin() # restore segment selection diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMaskVolumeEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMaskVolumeEffect.py index 52b7160701f..55555f7371c 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMaskVolumeEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorMaskVolumeEffect.py @@ -3,13 +3,16 @@ import logging from SegmentEditorEffects import * +from slicer.i18n import tr as _ + class SegmentEditorMaskVolumeEffect(AbstractScriptedSegmentEditorEffect): """This effect fills a selected volume node inside and/or outside a segment with a chosen value. """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Mask volume' + scriptedEffect.name = 'Mask volume' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Mask volume') scriptedEffect.perSegment = True # this effect operates on a single selected segment AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect) @@ -31,10 +34,10 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Use the currently selected segment as a mask to blank out regions in a volume. -
The mask is applied to the source volume by default.

-Fill inside and outside operation creates a binary labelmap volume as output, with the inside and outside fill values modifiable. -""" + return "" + _("""Use the currently selected segment as a mask to blank out regions in a volume. +
The mask is applied to the source volume by default.

+ Fill inside and outside operation creates a binary labelmap volume as output, with the inside and outside fill values modifiable. + """) + "" def setupOptionsFrame(self): self.operationRadioButtons = [] @@ -43,16 +46,16 @@ def setupOptionsFrame(self): self.invisibleIcon = qt.QIcon(":/Icons/Small/SlicerInvisible.png") # Fill operation buttons - self.fillInsideButton = qt.QRadioButton("Fill inside") + self.fillInsideButton = qt.QRadioButton(_("Fill inside")) self.operationRadioButtons.append(self.fillInsideButton) self.buttonToOperationNameMap[self.fillInsideButton] = 'FILL_INSIDE' - self.fillOutsideButton = qt.QRadioButton("Fill outside") + self.fillOutsideButton = qt.QRadioButton(_("Fill outside")) self.operationRadioButtons.append(self.fillOutsideButton) self.buttonToOperationNameMap[self.fillOutsideButton] = 'FILL_OUTSIDE' - self.binaryMaskFillButton = qt.QRadioButton("Fill inside and outside") - self.binaryMaskFillButton.setToolTip("Create a labelmap volume with specified inside and outside fill values.") + self.binaryMaskFillButton = qt.QRadioButton(_("Fill inside and outside")) + self.binaryMaskFillButton.setToolTip(_("Create a labelmap volume with specified inside and outside fill values.")) self.operationRadioButtons.append(self.binaryMaskFillButton) self.buttonToOperationNameMap[self.binaryMaskFillButton] = 'FILL_INSIDE_AND_OUTSIDE' @@ -61,22 +64,22 @@ def setupOptionsFrame(self): operationLayout.addWidget(self.fillInsideButton, 0, 0) operationLayout.addWidget(self.fillOutsideButton, 1, 0) operationLayout.addWidget(self.binaryMaskFillButton, 0, 1) - self.scriptedEffect.addLabeledOptionsWidget("Operation:", operationLayout) + self.scriptedEffect.addLabeledOptionsWidget(_("Operation:"), operationLayout) # fill value self.fillValueEdit = ctk.ctkDoubleSpinBox() - self.fillValueEdit.setToolTip("Choose the voxel intensity that will be used to fill the masked region.") - self.fillValueLabel = qt.QLabel("Fill value: ") + self.fillValueEdit.setToolTip(_("Choose the voxel intensity that will be used to fill the masked region.")) + self.fillValueLabel = qt.QLabel(_("Fill value: ")) # Binary mask fill outside value self.binaryMaskFillOutsideEdit = ctk.ctkDoubleSpinBox() - self.binaryMaskFillOutsideEdit.setToolTip("Choose the voxel intensity that will be used to fill outside the mask.") - self.fillOutsideLabel = qt.QLabel("Outside fill value: ") + self.binaryMaskFillOutsideEdit.setToolTip(_("Choose the voxel intensity that will be used to fill outside the mask.")) + self.fillOutsideLabel = qt.QLabel(_("Outside fill value: ")) # Binary mask fill outside value self.binaryMaskFillInsideEdit = ctk.ctkDoubleSpinBox() - self.binaryMaskFillInsideEdit.setToolTip("Choose the voxel intensity that will be used to fill inside the mask.") - self.fillInsideLabel = qt.QLabel(" Inside fill value: ") + self.binaryMaskFillInsideEdit.setToolTip(_("Choose the voxel intensity that will be used to fill inside the mask.")) + self.fillInsideLabel = qt.QLabel(_(" Inside fill value: ")) for fillValueEdit in [self.fillValueEdit, self.binaryMaskFillOutsideEdit, self.binaryMaskFillInsideEdit]: fillValueEdit.decimalsOption = ctk.ctkDoubleSpinBox.DecimalsByValue + ctk.ctkDoubleSpinBox.DecimalsByKey + ctk.ctkDoubleSpinBox.InsertDecimals @@ -105,13 +108,13 @@ def setupOptionsFrame(self): # Soft edge self.softEdgeMmSpinBox = slicer.qMRMLSpinBox() self.softEdgeMmSpinBox.setMRMLScene(slicer.mrmlScene) - self.softEdgeMmSpinBox.setToolTip("Standard deviation of the Gaussian function that blurs the edge of the mask." - " Higher value makes the edge softer.") + self.softEdgeMmSpinBox.setToolTip(_("Standard deviation of the Gaussian function that blurs the edge of the mask." + " Higher value makes the edge softer.")) self.softEdgeMmSpinBox.quantity = "length" self.softEdgeMmSpinBox.value = 0 self.softEdgeMmSpinBox.minimum = 0 self.softEdgeMmSpinBox.singleStep = 0.5 - self.softEdgeMmLabel = self.scriptedEffect.addLabeledOptionsWidget("Soft edge:", self.softEdgeMmSpinBox) + self.softEdgeMmLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Soft edge:"), self.softEdgeMmSpinBox) self.softEdgeMmSpinBox.connect("valueChanged(double)", self.softEdgeMmChanged) # input volume selector @@ -121,10 +124,10 @@ def setupOptionsFrame(self): self.inputVolumeSelector.addEnabled = True self.inputVolumeSelector.removeEnabled = True self.inputVolumeSelector.noneEnabled = True - self.inputVolumeSelector.noneDisplay = "(Source volume)" + self.inputVolumeSelector.noneDisplay = _("(Source volume)") self.inputVolumeSelector.showHidden = False self.inputVolumeSelector.setMRMLScene(slicer.mrmlScene) - self.inputVolumeSelector.setToolTip("Volume to mask. Default is current source volume node.") + self.inputVolumeSelector.setToolTip(_("Volume to mask. Default is current source volume node.")) self.inputVolumeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onInputVolumeChanged) self.inputVisibilityButton = qt.QToolButton() @@ -133,7 +136,7 @@ def setupOptionsFrame(self): inputLayout = qt.QHBoxLayout() inputLayout.addWidget(self.inputVisibilityButton) inputLayout.addWidget(self.inputVolumeSelector) - self.scriptedEffect.addLabeledOptionsWidget("Input Volume: ", inputLayout) + self.scriptedEffect.addLabeledOptionsWidget(_("Input Volume: "), inputLayout) # output volume selector self.outputVolumeSelector = slicer.qMRMLNodeComboBox() @@ -143,10 +146,10 @@ def setupOptionsFrame(self): self.outputVolumeSelector.removeEnabled = True self.outputVolumeSelector.renameEnabled = True self.outputVolumeSelector.noneEnabled = True - self.outputVolumeSelector.noneDisplay = "(Create new Volume)" + self.outputVolumeSelector.noneDisplay = _("(Create new Volume)") self.outputVolumeSelector.showHidden = False self.outputVolumeSelector.setMRMLScene(slicer.mrmlScene) - self.outputVolumeSelector.setToolTip("Masked output volume. It may be the same as the input volume for cumulative masking.") + self.outputVolumeSelector.setToolTip(_("Masked output volume. It may be the same as the input volume for cumulative masking.")) self.outputVolumeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onOutputVolumeChanged) self.outputVisibilityButton = qt.QToolButton() @@ -155,12 +158,12 @@ def setupOptionsFrame(self): outputLayout = qt.QHBoxLayout() outputLayout.addWidget(self.outputVisibilityButton) outputLayout.addWidget(self.outputVolumeSelector) - self.scriptedEffect.addLabeledOptionsWidget("Output Volume: ", outputLayout) + self.scriptedEffect.addLabeledOptionsWidget(_("Output Volume: "), outputLayout) # Apply button - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' - self.applyButton.setToolTip("Apply segment as volume mask. No undo operation available once applied.") + self.applyButton.setToolTip(_("Apply segment as volume mask. No undo operation available once applied.")) self.scriptedEffect.addOptionsWidget(self.applyButton) self.applyButton.connect('clicked()', self.onApply) @@ -223,12 +226,12 @@ def updateGUIFromMRML(self): self.binaryMaskFillOutsideEdit.setVisible(operationName == "FILL_INSIDE_AND_OUTSIDE") self.fillOutsideLabel.setVisible(operationName == "FILL_INSIDE_AND_OUTSIDE") if operationName in ["FILL_INSIDE", "FILL_OUTSIDE"]: - if self.outputVolumeSelector.noneDisplay != "(Create new Volume)": - self.outputVolumeSelector.noneDisplay = "(Create new Volume)" + if self.outputVolumeSelector.noneDisplay != _("(Create new Volume)"): + self.outputVolumeSelector.noneDisplay = _("(Create new Volume)") self.outputVolumeSelector.nodeTypes = ["vtkMRMLScalarVolumeNode", "vtkMRMLLabelMapVolumeNode"] else: - if self.outputVolumeSelector.noneDisplay != "(Create new Labelmap Volume)": - self.outputVolumeSelector.noneDisplay = "(Create new Labelmap Volume)" + if self.outputVolumeSelector.noneDisplay != _("(Create new Labelmap Volume)"): + self.outputVolumeSelector.noneDisplay = _("(Create new Labelmap Volume)") self.outputVolumeSelector.nodeTypes = ["vtkMRMLLabelMapVolumeNode", "vtkMRMLScalarVolumeNode"] self.inputVisibilityButton.setIcon(self.visibleIcon if self.isVolumeVisible(inputVolume) else self.invisibleIcon) @@ -295,7 +298,7 @@ def fillValueChanged(self): self.updateMRMLFromGUI() def onApply(self): - with slicer.util.tryWithErrorDisplay("Failed to apply mask to volume.", waitCursor=True): + with slicer.util.tryWithErrorDisplay(_("Failed to apply mask to volume."), waitCursor=True): inputVolume = self.getInputVolume() outputVolume = self.outputVolumeSelector.currentNode() operationMode = self.scriptedEffect.parameter("Operation") diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorSmoothingEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorSmoothingEffect.py index 90605a237a4..ae681b31b01 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorSmoothingEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorSmoothingEffect.py @@ -6,6 +6,7 @@ import vtk import slicer +from slicer.i18n import tr as _ from SegmentEditorEffects import * @@ -15,7 +16,8 @@ class SegmentEditorSmoothingEffect(AbstractScriptedSegmentEditorPaintEffect): """ def __init__(self, scriptedEffect): - scriptedEffect.name = 'Smoothing' + scriptedEffect.name = 'Smoothing' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Smoothing') AbstractScriptedSegmentEditorPaintEffect.__init__(self, scriptedEffect) def clone(self): @@ -31,69 +33,72 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Make segment boundaries smoother
by removing extrusions and filling small holes. The effect can be either applied locally -(by painting in viewers) or to the whole segment (by clicking Apply button). Available methods:

-

""" + return _("""Make segment boundaries smoother
by removing extrusions and filling small holes. The effect can be either applied locally + (by painting in viewers) or to the whole segment (by clicking Apply button). Available methods:

+

""") def setupOptionsFrame(self): self.methodSelectorComboBox = qt.QComboBox() - self.methodSelectorComboBox.addItem("Median", MEDIAN) - self.methodSelectorComboBox.addItem("Opening (remove extrusions)", MORPHOLOGICAL_OPENING) - self.methodSelectorComboBox.addItem("Closing (fill holes)", MORPHOLOGICAL_CLOSING) - self.methodSelectorComboBox.addItem("Gaussian", GAUSSIAN) - self.methodSelectorComboBox.addItem("Joint smoothing", JOINT_TAUBIN) - self.scriptedEffect.addLabeledOptionsWidget("Smoothing method:", self.methodSelectorComboBox) + self.methodSelectorComboBox.addItem(_("Median"), MEDIAN) + self.methodSelectorComboBox.addItem(_("Opening (remove extrusions)"), MORPHOLOGICAL_OPENING) + self.methodSelectorComboBox.addItem(_("Closing (fill holes)"), MORPHOLOGICAL_CLOSING) + self.methodSelectorComboBox.addItem(_("Gaussian"), GAUSSIAN) + self.methodSelectorComboBox.addItem(_("Joint smoothing"), JOINT_TAUBIN) + self.scriptedEffect.addLabeledOptionsWidget(_("Smoothing method:"), self.methodSelectorComboBox) self.kernelSizeMMSpinBox = slicer.qMRMLSpinBox() self.kernelSizeMMSpinBox.setMRMLScene(slicer.mrmlScene) - self.kernelSizeMMSpinBox.setToolTip("Diameter of the neighborhood that will be considered around each voxel. Higher value makes smoothing stronger (more details are suppressed).") + self.kernelSizeMMSpinBox.setToolTip(_("Diameter of the neighborhood that will be considered around each voxel. " + "Higher value makes smoothing stronger (more details are suppressed).")) self.kernelSizeMMSpinBox.quantity = "length" self.kernelSizeMMSpinBox.minimum = 0.0 self.kernelSizeMMSpinBox.value = 3.0 self.kernelSizeMMSpinBox.singleStep = 1.0 self.kernelSizePixel = qt.QLabel() - self.kernelSizePixel.setToolTip("Diameter of the neighborhood in pixel. Computed from the segment's spacing and the specified kernel size.") + self.kernelSizePixel.setToolTip(_("Diameter of the neighborhood in pixel. Computed from the segment's spacing and the specified kernel size.")) kernelSizeFrame = qt.QHBoxLayout() kernelSizeFrame.addWidget(self.kernelSizeMMSpinBox) kernelSizeFrame.addWidget(self.kernelSizePixel) - self.kernelSizeMMLabel = self.scriptedEffect.addLabeledOptionsWidget("Kernel size:", kernelSizeFrame) + self.kernelSizeMMLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Kernel size:"), kernelSizeFrame) self.gaussianStandardDeviationMMSpinBox = slicer.qMRMLSpinBox() self.gaussianStandardDeviationMMSpinBox.setMRMLScene(slicer.mrmlScene) - self.gaussianStandardDeviationMMSpinBox.setToolTip("Standard deviation of the Gaussian smoothing filter coefficients. Higher value makes smoothing stronger (more details are suppressed).") + self.gaussianStandardDeviationMMSpinBox.setToolTip(_("Standard deviation of the Gaussian smoothing filter coefficients. " + "Higher value makes smoothing stronger (more details are suppressed).")) self.gaussianStandardDeviationMMSpinBox.quantity = "length" self.gaussianStandardDeviationMMSpinBox.value = 3.0 self.gaussianStandardDeviationMMSpinBox.singleStep = 1.0 - self.gaussianStandardDeviationMMLabel = self.scriptedEffect.addLabeledOptionsWidget("Standard deviation:", self.gaussianStandardDeviationMMSpinBox) + self.gaussianStandardDeviationMMLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Standard deviation:"), self.gaussianStandardDeviationMMSpinBox) self.jointTaubinSmoothingFactorSlider = ctk.ctkSliderWidget() - self.jointTaubinSmoothingFactorSlider.setToolTip("Higher value means stronger smoothing.") + self.jointTaubinSmoothingFactorSlider.setToolTip(_("Higher value means stronger smoothing.")) self.jointTaubinSmoothingFactorSlider.minimum = 0.01 self.jointTaubinSmoothingFactorSlider.maximum = 1.0 self.jointTaubinSmoothingFactorSlider.value = 0.5 self.jointTaubinSmoothingFactorSlider.singleStep = 0.01 self.jointTaubinSmoothingFactorSlider.pageStep = 0.1 - self.jointTaubinSmoothingFactorLabel = self.scriptedEffect.addLabeledOptionsWidget("Smoothing factor:", self.jointTaubinSmoothingFactorSlider) + self.jointTaubinSmoothingFactorLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Smoothing factor:"), self.jointTaubinSmoothingFactorSlider) self.applyToAllVisibleSegmentsCheckBox = qt.QCheckBox() - self.applyToAllVisibleSegmentsCheckBox.setToolTip("Apply smoothing effect to all visible segments in this segmentation node. \ - This operation may take a while.") + self.applyToAllVisibleSegmentsCheckBox.setToolTip(_("Apply smoothing effect to all visible segments in this segmentation node. \ + This operation may take a while.")) self.applyToAllVisibleSegmentsCheckBox.objectName = self.__class__.__name__ + 'ApplyToAllVisibleSegments' - self.applyToAllVisibleSegmentsLabel = self.scriptedEffect.addLabeledOptionsWidget("Apply to visible segments:", self.applyToAllVisibleSegmentsCheckBox) + self.applyToAllVisibleSegmentsLabel = self.scriptedEffect.addLabeledOptionsWidget(_("Apply to visible segments:"), + self.applyToAllVisibleSegmentsCheckBox) - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' - self.applyButton.setToolTip("Apply smoothing to selected segment") + self.applyButton.setToolTip(_("Apply smoothing to selected segment")) self.scriptedEffect.addOptionsWidget(self.applyButton) self.methodSelectorComboBox.connect("currentIndexChanged(int)", self.updateMRMLFromGUI) @@ -106,7 +111,7 @@ def setupOptionsFrame(self): # Customize smoothing brush self.scriptedEffect.setColorSmudgeCheckboxVisible(False) self.paintOptionsGroupBox = ctk.ctkCollapsibleGroupBox() - self.paintOptionsGroupBox.setTitle("Smoothing brush options") + self.paintOptionsGroupBox.setTitle(_("Smoothing brush options")) self.paintOptionsGroupBox.setLayout(qt.QVBoxLayout()) self.paintOptionsGroupBox.layout().addWidget(self.scriptedEffect.paintOptionsFrame()) self.paintOptionsGroupBox.collapsed = True @@ -224,7 +229,7 @@ def onApply(self, maskImage=None, maskExtent=None): return for index in range(inputSegmentIDs.GetNumberOfValues()): segmentID = inputSegmentIDs.GetValue(index) - self.showStatusMessage(f'Smoothing {segmentationNode.GetSegmentation().GetSegment(segmentID).GetName()}...') + self.showStatusMessage(_('Smoothing {segmentName}...').format(segmentationNode.GetSegmentation().GetSegment(segmentID).GetName())) self.scriptedEffect.parameterSetNode().SetSelectedSegmentID(segmentID) self.smoothSelectedSegment(maskImage, maskExtent) # restore segment selection @@ -365,7 +370,7 @@ def smoothSelectedSegment(self, maskImage=None, maskExtent=None): def smoothMultipleSegments(self, maskImage=None, maskExtent=None): import vtkSegmentationCorePython as vtkSegmentationCore - self.showStatusMessage(f'Joint smoothing ...') + self.showStatusMessage(_(f'Joint smoothing ...')) # Generate merged labelmap of all visible segments segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode() visibleSegmentIds = vtk.vtkStringArray() @@ -472,7 +477,7 @@ def paintApply(self, viewWidget): if smoothingMethod == JOINT_TAUBIN: self.scriptedEffect.clearBrushes() self.scriptedEffect.forceRender(viewWidget) - slicer.util.messageBox("Smoothing brush is not available for 'joint smoothing' method.") + slicer.util.messageBox(_("Smoothing brush is not available for 'joint smoothing' method.")) return modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() diff --git a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorThresholdEffect.py b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorThresholdEffect.py index c533ddf995b..c70b271f6b0 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorThresholdEffect.py +++ b/Modules/Loadable/Segmentations/EditorEffects/Python/SegmentEditorThresholdEffect.py @@ -8,6 +8,8 @@ import slicer from SegmentEditorEffects import * +from slicer.i18n import tr as _ + class SegmentEditorThresholdEffect(AbstractScriptedSegmentEditorEffect): """ ThresholdEffect is an Effect implementing the global threshold @@ -20,7 +22,8 @@ class SegmentEditorThresholdEffect(AbstractScriptedSegmentEditorEffect): def __init__(self, scriptedEffect): AbstractScriptedSegmentEditorEffect.__init__(self, scriptedEffect) - scriptedEffect.name = 'Threshold' + scriptedEffect.name = 'Threshold' # no tr (don't translate it because modules find effects by this name) + scriptedEffect.title = _('Threshold') self.segment2DFillOpacity = None self.segment2DOutlineOpacity = None @@ -72,11 +75,11 @@ def icon(self): return qt.QIcon() def helpText(self): - return """Fill segment based on source volume intensity range
. Options:

-

""" + return _("""Fill segment based on source volume intensity range
. Options:

+

""") def activate(self): self.setCurrentSegmentTransparent() @@ -145,8 +148,8 @@ def restorePreviewedSegmentTransparency(self): self.previewedSegmentID = None def setupOptionsFrame(self): - self.thresholdSliderLabel = qt.QLabel("Threshold Range:") - self.thresholdSliderLabel.setToolTip("Set the range of the background values that should be labeled.") + self.thresholdSliderLabel = qt.QLabel(_("Threshold Range:")) + self.thresholdSliderLabel.setToolTip(_("Set the range of the background values that should be labeled.")) self.scriptedEffect.addOptionsWidget(self.thresholdSliderLabel) self.thresholdSlider = ctk.ctkRangeWidget() @@ -155,45 +158,45 @@ def setupOptionsFrame(self): self.scriptedEffect.addOptionsWidget(self.thresholdSlider) self.autoThresholdModeSelectorComboBox = qt.QComboBox() - self.autoThresholdModeSelectorComboBox.addItem("threshold above", MODE_SET_LOWER_MAX) - self.autoThresholdModeSelectorComboBox.addItem("threshold below", MODE_SET_MIN_UPPER) - self.autoThresholdModeSelectorComboBox.addItem("set as lower value", MODE_SET_LOWER) - self.autoThresholdModeSelectorComboBox.addItem("set as upper value", MODE_SET_UPPER) - self.autoThresholdModeSelectorComboBox.setToolTip("How to set lower and upper values of the threshold range." - " Threshold above/below: sets the range from the computed value to maximum/minimum." - " Set as lower/upper value: only modifies one side of the threshold range.") + self.autoThresholdModeSelectorComboBox.addItem(_("threshold above"), MODE_SET_LOWER_MAX) + self.autoThresholdModeSelectorComboBox.addItem(_("threshold below"), MODE_SET_MIN_UPPER) + self.autoThresholdModeSelectorComboBox.addItem(_("set as lower value"), MODE_SET_LOWER) + self.autoThresholdModeSelectorComboBox.addItem(_("set as upper value"), MODE_SET_UPPER) + self.autoThresholdModeSelectorComboBox.setToolTip(_("How to set lower and upper values of the threshold range." + " Threshold above/below: sets the range from the computed value to maximum/minimum." + " Set as lower/upper value: only modifies one side of the threshold range.")) self.autoThresholdMethodSelectorComboBox = qt.QComboBox() - self.autoThresholdMethodSelectorComboBox.addItem("Otsu", METHOD_OTSU) - self.autoThresholdMethodSelectorComboBox.addItem("Huang", METHOD_HUANG) - self.autoThresholdMethodSelectorComboBox.addItem("IsoData", METHOD_ISO_DATA) + self.autoThresholdMethodSelectorComboBox.addItem(_("Otsu"), METHOD_OTSU) + self.autoThresholdMethodSelectorComboBox.addItem(_("Huang"), METHOD_HUANG) + self.autoThresholdMethodSelectorComboBox.addItem(_("IsoData"), METHOD_ISO_DATA) # Kittler-Illingworth sometimes fails with an exception, but it does not cause any major issue, # it just logs an error message and does not compute a new threshold value - self.autoThresholdMethodSelectorComboBox.addItem("Kittler-Illingworth", METHOD_KITTLER_ILLINGWORTH) + self.autoThresholdMethodSelectorComboBox.addItem(_("Kittler-Illingworth"), METHOD_KITTLER_ILLINGWORTH) # Li sometimes crashes (index out of range error in # ITK/Modules/Filtering/Thresholding/include/itkLiThresholdCalculator.hxx#L94) # We can add this method back when issue is fixed in ITK. # self.autoThresholdMethodSelectorComboBox.addItem("Li", METHOD_LI) - self.autoThresholdMethodSelectorComboBox.addItem("Maximum entropy", METHOD_MAXIMUM_ENTROPY) - self.autoThresholdMethodSelectorComboBox.addItem("Moments", METHOD_MOMENTS) - self.autoThresholdMethodSelectorComboBox.addItem("Renyi entropy", METHOD_RENYI_ENTROPY) - self.autoThresholdMethodSelectorComboBox.addItem("Shanbhag", METHOD_SHANBHAG) - self.autoThresholdMethodSelectorComboBox.addItem("Triangle", METHOD_TRIANGLE) - self.autoThresholdMethodSelectorComboBox.addItem("Yen", METHOD_YEN) - self.autoThresholdMethodSelectorComboBox.setToolTip("Select method to compute threshold value automatically.") + self.autoThresholdMethodSelectorComboBox.addItem(_("Maximum entropy"), METHOD_MAXIMUM_ENTROPY) + self.autoThresholdMethodSelectorComboBox.addItem(_("Moments"), METHOD_MOMENTS) + self.autoThresholdMethodSelectorComboBox.addItem(_("Renyi entropy"), METHOD_RENYI_ENTROPY) + self.autoThresholdMethodSelectorComboBox.addItem(_("Shanbhag"), METHOD_SHANBHAG) + self.autoThresholdMethodSelectorComboBox.addItem(_("Triangle"), METHOD_TRIANGLE) + self.autoThresholdMethodSelectorComboBox.addItem(_("Yen"), METHOD_YEN) + self.autoThresholdMethodSelectorComboBox.setToolTip(_("Select method to compute threshold value automatically.")) self.selectPreviousAutoThresholdButton = qt.QToolButton() self.selectPreviousAutoThresholdButton.text = "<" - self.selectPreviousAutoThresholdButton.setToolTip("Select previous thresholding method and set thresholds." - + " Useful for iterating through all available methods.") + self.selectPreviousAutoThresholdButton.setToolTip(_("Select previous thresholding method and set thresholds." + " Useful for iterating through all available methods.")) self.selectNextAutoThresholdButton = qt.QToolButton() self.selectNextAutoThresholdButton.text = ">" - self.selectNextAutoThresholdButton.setToolTip("Select next thresholding method and set thresholds." - + " Useful for iterating through all available methods.") + self.selectNextAutoThresholdButton.setToolTip(_("Select next thresholding method and set thresholds." + " Useful for iterating through all available methods.")) - self.setAutoThresholdButton = qt.QPushButton("Set") - self.setAutoThresholdButton.setToolTip("Set threshold using selected method.") + self.setAutoThresholdButton = qt.QPushButton(_("Set")) + self.setAutoThresholdButton.setToolTip(_("Set threshold using selected method.")) # qt.QSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding) # fails on some systems, therefore set the policies using separate method calls qSize = qt.QSizePolicy() @@ -208,7 +211,7 @@ def setupOptionsFrame(self): autoThresholdFrame.addWidget(self.setAutoThresholdButton, 2, 0, 1, 3) autoThresholdGroupBox = ctk.ctkCollapsibleGroupBox() - autoThresholdGroupBox.setTitle("Automatic threshold") + autoThresholdGroupBox.setTitle(_("Automatic threshold")) autoThresholdGroupBox.setLayout(autoThresholdFrame) autoThresholdGroupBox.collapsed = True self.scriptedEffect.addOptionsWidget(autoThresholdGroupBox) @@ -218,35 +221,35 @@ def setupOptionsFrame(self): histogramBrushFrame = qt.QHBoxLayout() histogramFrame.addLayout(histogramBrushFrame) - self.regionLabel = qt.QLabel("Region shape:") + self.regionLabel = qt.QLabel(_("Region shape:")) histogramBrushFrame.addWidget(self.regionLabel) self.histogramBrushButtonGroup = qt.QButtonGroup() self.histogramBrushButtonGroup.setExclusive(True) self.boxROIButton = qt.QToolButton() - self.boxROIButton.setText("Box") + self.boxROIButton.setText(_("Box")) self.boxROIButton.setCheckable(True) self.boxROIButton.clicked.connect(self.updateMRMLFromGUI) histogramBrushFrame.addWidget(self.boxROIButton) self.histogramBrushButtonGroup.addButton(self.boxROIButton) self.circleROIButton = qt.QToolButton() - self.circleROIButton.setText("Circle") + self.circleROIButton.setText(_("Circle")) self.circleROIButton.setCheckable(True) self.circleROIButton.clicked.connect(self.updateMRMLFromGUI) histogramBrushFrame.addWidget(self.circleROIButton) self.histogramBrushButtonGroup.addButton(self.circleROIButton) self.drawROIButton = qt.QToolButton() - self.drawROIButton.setText("Draw") + self.drawROIButton.setText(_("Draw")) self.drawROIButton.setCheckable(True) self.drawROIButton.clicked.connect(self.updateMRMLFromGUI) histogramBrushFrame.addWidget(self.drawROIButton) self.histogramBrushButtonGroup.addButton(self.drawROIButton) self.lineROIButton = qt.QToolButton() - self.lineROIButton.setText("Line") + self.lineROIButton.setText(_("Line")) self.lineROIButton.setCheckable(True) self.lineROIButton.clicked.connect(self.updateMRMLFromGUI) histogramBrushFrame.addWidget(self.lineROIButton) @@ -307,7 +310,7 @@ def setupOptionsFrame(self): ### # Lower histogram threshold buttons - lowerGroupBox = qt.QGroupBox("Lower") + lowerGroupBox = qt.QGroupBox(_("Lower")) lowerHistogramLayout = qt.QHBoxLayout() lowerHistogramLayout.setContentsMargins(0, 3, 0, 3) lowerGroupBox.setLayout(lowerHistogramLayout) @@ -316,22 +319,22 @@ def setupOptionsFrame(self): self.histogramLowerMethodButtonGroup.setExclusive(True) self.histogramLowerThresholdMinimumButton = qt.QToolButton() - self.histogramLowerThresholdMinimumButton.setText("Min") - self.histogramLowerThresholdMinimumButton.setToolTip("Minimum") + self.histogramLowerThresholdMinimumButton.setText(_("Min")) + self.histogramLowerThresholdMinimumButton.setToolTip(_("Minimum")) self.histogramLowerThresholdMinimumButton.setCheckable(True) self.histogramLowerThresholdMinimumButton.clicked.connect(self.updateMRMLFromGUI) lowerHistogramLayout.addWidget(self.histogramLowerThresholdMinimumButton) self.histogramLowerMethodButtonGroup.addButton(self.histogramLowerThresholdMinimumButton) self.histogramLowerThresholdLowerButton = qt.QToolButton() - self.histogramLowerThresholdLowerButton.setText("Lower") + self.histogramLowerThresholdLowerButton.setText(_("Lower")) self.histogramLowerThresholdLowerButton.setCheckable(True) self.histogramLowerThresholdLowerButton.clicked.connect(self.updateMRMLFromGUI) lowerHistogramLayout.addWidget(self.histogramLowerThresholdLowerButton) self.histogramLowerMethodButtonGroup.addButton(self.histogramLowerThresholdLowerButton) self.histogramLowerThresholdAverageButton = qt.QToolButton() - self.histogramLowerThresholdAverageButton.setText("Mean") + self.histogramLowerThresholdAverageButton.setText(_("Mean")) self.histogramLowerThresholdAverageButton.setCheckable(True) self.histogramLowerThresholdAverageButton.clicked.connect(self.updateMRMLFromGUI) lowerHistogramLayout.addWidget(self.histogramLowerThresholdAverageButton) @@ -340,7 +343,7 @@ def setupOptionsFrame(self): ### # Upper histogram threshold buttons - upperGroupBox = qt.QGroupBox("Upper") + upperGroupBox = qt.QGroupBox(_("Upper")) upperHistogramLayout = qt.QHBoxLayout() upperHistogramLayout.setContentsMargins(0, 3, 0, 3) upperGroupBox.setLayout(upperHistogramLayout) @@ -349,40 +352,40 @@ def setupOptionsFrame(self): self.histogramUpperMethodButtonGroup.setExclusive(True) self.histogramUpperThresholdAverageButton = qt.QToolButton() - self.histogramUpperThresholdAverageButton.setText("Mean") + self.histogramUpperThresholdAverageButton.setText(_("Mean")) self.histogramUpperThresholdAverageButton.setCheckable(True) self.histogramUpperThresholdAverageButton.clicked.connect(self.updateMRMLFromGUI) upperHistogramLayout.addWidget(self.histogramUpperThresholdAverageButton) self.histogramUpperMethodButtonGroup.addButton(self.histogramUpperThresholdAverageButton) self.histogramUpperThresholdUpperButton = qt.QToolButton() - self.histogramUpperThresholdUpperButton.setText("Upper") + self.histogramUpperThresholdUpperButton.setText(_("Upper")) self.histogramUpperThresholdUpperButton.setCheckable(True) self.histogramUpperThresholdUpperButton.clicked.connect(self.updateMRMLFromGUI) upperHistogramLayout.addWidget(self.histogramUpperThresholdUpperButton) self.histogramUpperMethodButtonGroup.addButton(self.histogramUpperThresholdUpperButton) self.histogramUpperThresholdMaximumButton = qt.QToolButton() - self.histogramUpperThresholdMaximumButton.setText("Max") - self.histogramUpperThresholdMaximumButton.setToolTip("Maximum") + self.histogramUpperThresholdMaximumButton.setText(_("Max")) + self.histogramUpperThresholdMaximumButton.setToolTip(_("Maximum")) self.histogramUpperThresholdMaximumButton.setCheckable(True) self.histogramUpperThresholdMaximumButton.clicked.connect(self.updateMRMLFromGUI) upperHistogramLayout.addWidget(self.histogramUpperThresholdMaximumButton) self.histogramUpperMethodButtonGroup.addButton(self.histogramUpperThresholdMaximumButton) histogramGroupBox = ctk.ctkCollapsibleGroupBox() - histogramGroupBox.setTitle("Local histogram") + histogramGroupBox.setTitle(_("Local histogram")) histogramGroupBox.setLayout(histogramFrame) histogramGroupBox.collapsed = True self.scriptedEffect.addOptionsWidget(histogramGroupBox) - self.useForPaintButton = qt.QPushButton("Use for masking") - self.useForPaintButton.setToolTip("Use specified intensity range for masking and switch to Paint effect.") + self.useForPaintButton = qt.QPushButton(_("Use for masking")) + self.useForPaintButton.setToolTip(_("Use specified intensity range for masking and switch to Paint effect.")) self.scriptedEffect.addOptionsWidget(self.useForPaintButton) - self.applyButton = qt.QPushButton("Apply") + self.applyButton = qt.QPushButton(_("Apply")) self.applyButton.objectName = self.__class__.__name__ + 'Apply' - self.applyButton.setToolTip("Fill selected segment in regions that are in the specified intensity range.") + self.applyButton.setToolTip(_("Fill selected segment in regions that are in the specified intensity range.")) self.scriptedEffect.addOptionsWidget(self.applyButton) self.useForPaintButton.connect('clicked()', self.onUseForPaint) diff --git a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.cxx b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.cxx index 6c0a27ced29..c4b0c3c470b 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.cxx +++ b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.cxx @@ -142,6 +142,30 @@ void qSlicerSegmentEditorAbstractEffect::setName(QString name) qCritical() << Q_FUNC_INFO << ": Cannot set effect name by method, only in constructor!"; } +//----------------------------------------------------------------------------- +QString qSlicerSegmentEditorAbstractEffect::title()const +{ + if (!this->m_Title.isEmpty()) + { + return this->m_Title; + } + else if (!this->m_Name.isEmpty()) + { + return this->m_Name; + } + else + { + qWarning() << Q_FUNC_INFO << ": Empty effect title!"; + return QString(); + } +} + +//----------------------------------------------------------------------------- +void qSlicerSegmentEditorAbstractEffect::setTitle(QString title) +{ + this->m_Title = title; +} + //----------------------------------------------------------------------------- bool qSlicerSegmentEditorAbstractEffect::perSegment()const { diff --git a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.h b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.h index c8029b6be60..779d80af259 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.h +++ b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorAbstractEffect.h @@ -70,6 +70,10 @@ class Q_SLICER_SEGMENTATIONS_EFFECTS_EXPORT qSlicerSegmentEditorAbstractEffect : /// \sa name(), \sa setName() Q_PROPERTY(QString name READ name WRITE setName) + /// This property stores the title of the effect + /// \sa title(), \sa setTitle() + Q_PROPERTY(QString title READ title WRITE setTitle) + /// This property stores the flag indicating whether effect operates on individual segments (true) /// or the whole segmentation (false). /// True by default. @@ -243,6 +247,11 @@ public slots: /// NOTE: name must be defined in constructor in C++ effects, this can only be used in python scripted ones virtual void setName(QString name); + /// Get title of effect. Returns the effect's name when the title is empty + virtual QString title()const; + /// Set the title of the effect + virtual void setTitle(QString title); + /// Get flag indicating whether effect operates on segments (true) or the whole segmentation (false). virtual bool perSegment()const; /// Set flag indicating whether effect operates on segments (true) or the whole segmentation (false). @@ -416,10 +425,14 @@ public slots: Q_INVOKABLE bool segmentationDisplayableInView(vtkMRMLAbstractViewNode* viewNode); protected: - /// Name of the effect + /// Name of the effect. This name is used by various modules for getting access to an effect. + /// This string is not displayed on the user interface and must not be translated. QString m_Name; bool m_Active{false}; + /// Title of the effect. This is displayed on the user interface and translated to the current language. + QString m_Title; + /// Flag indicating whether effect operates on individual segments (true) or the whole segmentation (false). /// If the selected effect works on whole segmentation, selection of the segments does not trigger creation /// of modifier labelmap, but it is set to empty in the parameter set node. diff --git a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorEraseEffect.cxx b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorEraseEffect.cxx index 7c980362fa4..f237a95bb37 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorEraseEffect.cxx +++ b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorEraseEffect.cxx @@ -53,6 +53,7 @@ qSlicerSegmentEditorEraseEffect::qSlicerSegmentEditorEraseEffect(QObject* parent , d_ptr( new qSlicerSegmentEditorEraseEffectPrivate(*this) ) { this->m_Name = QString(/*no tr*/"Erase"); + this->m_Title = tr("Erase"); this->m_AlwaysErase = true; this->m_ShowEffectCursorInThreeDView = true; } diff --git a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorPaintEffect.cxx b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorPaintEffect.cxx index 347a743f80d..9e35e1f971b 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorPaintEffect.cxx +++ b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorPaintEffect.cxx @@ -970,6 +970,7 @@ qSlicerSegmentEditorPaintEffect::qSlicerSegmentEditorPaintEffect(QObject* parent , d_ptr( new qSlicerSegmentEditorPaintEffectPrivate(*this) ) { this->m_Name = QString(/*no tr*/"Paint"); + this->m_Title = tr("Paint"); this->m_AlwaysErase = false; this->m_Erase = false; this->m_ShowEffectCursorInThreeDView = true; diff --git a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorScissorsEffect.cxx b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorScissorsEffect.cxx index e49bcb46081..2f81c27bb51 100644 --- a/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorScissorsEffect.cxx +++ b/Modules/Loadable/Segmentations/EditorEffects/qSlicerSegmentEditorScissorsEffect.cxx @@ -1160,6 +1160,7 @@ qSlicerSegmentEditorScissorsEffect::qSlicerSegmentEditorScissorsEffect(QObject* , d_ptr( new qSlicerSegmentEditorScissorsEffectPrivate(*this) ) { this->m_Name = QString(/*no tr*/"Scissors"); + this->m_Title = tr("Scissors"); this->m_ShowEffectCursorInThreeDView = true; } diff --git a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx index 70ce3766c78..299ce9fa292 100644 --- a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx +++ b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentEditorWidget.cxx @@ -1078,8 +1078,8 @@ void qMRMLSegmentEditorWidget::updateEffectList() effectButton->setCheckable(true); effectButton->setToolButtonStyle(d->EffectButtonStyle); effectButton->setIcon(effect->icon()); - effectButton->setText(effect->name()); - effectButton->setToolTip(effect->name()); + effectButton->setText(effect->title()); + effectButton->setToolTip(effect->title()); effectButton->setProperty("Effect", QVariant::fromValue(effect)); effectButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); // make all effect buttons the same width d->EffectButtonGroup.addButton(effectButton); @@ -1689,7 +1689,7 @@ void qMRMLSegmentEditorWidget::updateEffectsSectionFromMRML() // Activate newly selected effect activeEffect->activate(); d->OptionsGroupBox->show(); - d->OptionsGroupBox->setTitle(activeEffect->name()); + d->OptionsGroupBox->setTitle(activeEffect->title()); d->EffectHelpBrowser->setCollapsibleText(activeEffect->helpText()); d->MaskingGroupBox->show(); } diff --git a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentationRepresentationsListView.cxx b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentationRepresentationsListView.cxx index 6e86f889645..b9feb485e1b 100644 --- a/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentationRepresentationsListView.cxx +++ b/Modules/Loadable/Segmentations/Widgets/qMRMLSegmentationRepresentationsListView.cxx @@ -313,7 +313,8 @@ void qMRMLSegmentationRepresentationsListView::createRepresentationDefault() QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); if (!d->SegmentationNode->GetSegmentation()->CreateRepresentation(representationName.toUtf8().constData())) { - QString message = QString("Failed to convert %1 to %2!\n\nProbably there is no valid conversion path between the source representation and %2").arg(d->SegmentationNode->GetName()).arg(representationName); + QString message = tr("Failed to convert %1 to %2!\n\nProbably there is no valid conversion path between the source representation and %2") + .arg(d->SegmentationNode->GetName()).arg(representationName); QMessageBox::warning(nullptr, tr("Conversion failed"), message); } QApplication::restoreOverrideCursor();