Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make text in MRML library translatable #7210

Merged
merged 2 commits into from
Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions Base/QTCLI/qSlicerCLIProgressBar.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ void qSlicerCLIProgressBar::updateUiFromCommandLineModuleNode(
}

// Update progress
d->StatusLabel->setText(node->GetStatusString());
d->StatusLabel->setText(QString::fromStdString(node->GetDisplayableStatusString()));
d->NameLabel->setText(node->GetName());

// Update Progress
Expand All @@ -383,7 +383,7 @@ void qSlicerCLIProgressBar::updateUiFromCommandLineModuleNode(
d->ProgressBar->setValue(info->Progress * 100.);
if (info->ElapsedTime != 0.)
{
d->StatusLabel->setText(statusLabelFormat.arg(node->GetStatusString()).arg(info->ElapsedTime, 0, 'f', 1));
d->StatusLabel->setText(statusLabelFormat.arg(QString::fromStdString(node->GetDisplayableStatusString())).arg(info->ElapsedTime, 0, 'f', 1));
}
// We keep StageProgressBar maximum at 100, because if it was set to 0
// then the progress message would not be displayed.
Expand All @@ -395,7 +395,7 @@ void qSlicerCLIProgressBar::updateUiFromCommandLineModuleNode(
case vtkMRMLCommandLineModuleNode::CompletedWithErrors:
if (info->ElapsedTime != 0.)
{
d->StatusLabel->setText(statusLabelFormat.arg(node->GetStatusString()).arg(info->ElapsedTime, 0, 'f', 1));
d->StatusLabel->setText(statusLabelFormat.arg(QString::fromStdString(node->GetDisplayableStatusString())).arg(info->ElapsedTime, 0, 'f', 1));
}
d->ProgressBar->setMaximum(100);
d->ProgressBar->setValue(100);
Expand Down
30 changes: 30 additions & 0 deletions Base/QTCore/qSlicerCoreApplication.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@
#ifdef Slicer_BUILD_CLI_SUPPORT
# include <vtkMRMLCommandLineModuleNode.h>
#endif
#include <vtkMRMLI18N.h>
#include <vtkMRMLScene.h>
#include <vtkMRMLTranslator.h>

// CTK includes
#include <ctkUtils.h>
Expand Down Expand Up @@ -153,6 +155,30 @@
#include <ctkDICOMDatabase.h>
#endif

//-----------------------------------------------------------------------------
// Adapter class for translation in MRML classes using Qt translation infrastructure

class vtkQtTranslator: public vtkMRMLTranslator
{
public:
static vtkQtTranslator* New();
vtkTypeMacro(vtkQtTranslator, vtkMRMLTranslator);

/// Translation function for logic classes
std::string Translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1) override
{
return QCoreApplication::translate(context, sourceText, disambiguation, n).toStdString();
}

protected:
vtkQtTranslator() = default;
~vtkQtTranslator() override = default;
vtkQtTranslator(const vtkQtTranslator&) = delete;
void operator=(const vtkQtTranslator&) = delete;
};

vtkStandardNewMacro(vtkQtTranslator);

//-----------------------------------------------------------------------------
// Helper function

Expand Down Expand Up @@ -353,6 +379,10 @@ void qSlicerCoreApplicationPrivate::init()
vtkEventBroker::GetInstance()->SetRequestModifiedCallback(modifiedRequestCallback);
}

// Set up translation in MRML classes using Qt translator
vtkNew<vtkQtTranslator> mrmlTranslator;
vtkMRMLI18N::GetInstance()->SetTranslator(mrmlTranslator);

// Ensure that temporary folder is writable
{
// QTemporaryFile is deleted automatically when leaving this scope
Expand Down
20 changes: 20 additions & 0 deletions Libs/MRML/CLI/vtkMRMLCommandLineModuleNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Version: $Revision: 1.2 $
#include "vtkMRMLCommandLineModuleNode.h"

// MRML includes
#include "vtkMRMLI18N.h"

/// SlicerExecutionModel includes
#include <ModuleDescription.h>
Expand Down Expand Up @@ -673,6 +674,25 @@ const char* vtkMRMLCommandLineModuleNode::GetStatusString() const
return "Unknown";
}

//----------------------------------------------------------------------------
std::string vtkMRMLCommandLineModuleNode::GetDisplayableStatusString() const
{
switch (this->Internal->Status)
{
case Idle: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Idle");
case Scheduled: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Scheduled");
case Running: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Running");
case Cancelling: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Cancelling");
case Cancelled: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Cancelled");
case Completing: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Completing");
case Completed: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Completed");
case CompletedWithErrors: return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Completed with errors");
default:
break;
}
return vtkMRMLTr("vtkMRMLCommandLineModuleNode", "Unknown");
}

//----------------------------------------------------------------------------
void vtkMRMLCommandLineModuleNode::Cancel()
{
Expand Down
8 changes: 6 additions & 2 deletions Libs/MRML/CLI/vtkMRMLCommandLineModuleNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,14 @@ class VTK_MRML_CLI_EXPORT vtkMRMLCommandLineModuleNode : public vtkMRMLNode
/// \sa SetStatus(), GetStatusString(), IsBusy()
int GetStatus() const;

/// Return current status as a string for display.
/// \sa GetStatus(), IsBusy()
/// Return current status as a string. Not translated.
/// \sa GetStatus(), IsBusy(), GetDisplayableStatusString()
const char* GetStatusString() const;

/// Return current status as a string for display (translated to current language).
/// \sa GetStatusString()
std::string GetDisplayableStatusString() const;

//@{
/// Start/stop continuous updating of output and error texts during execution.
///
Expand Down
3 changes: 3 additions & 0 deletions Libs/MRML/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ set(MRMLCore_SRCS
vtkCodedEntry.cxx
vtkEventBroker.cxx
vtkDataFileFormatHelper.cxx
vtkMRMLI18N.cxx
vtkMRMLI18N.h
vtkMRMLMeasurement.cxx
vtkMRMLStaticMeasurement.cxx
vtkMRMLLogic.cxx
Expand Down Expand Up @@ -221,6 +223,7 @@ set(MRMLCore_SRCS
vtkMRMLTransformStorageNode.cxx
vtkMRMLTransformDisplayNode.cxx
vtkMRMLTransformableNode.cxx
vtkMRMLTranslator.h
vtkMRMLUnitNode.cxx
vtkMRMLVectorVolumeDisplayNode.cxx
vtkMRMLViewNode.cxx
Expand Down
1 change: 1 addition & 0 deletions Libs/MRML/Core/Testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ create_test_sourcelist(Tests ${KIT}CxxTests.cxx
vtkMRMLGridTransformNodeTest1.cxx
vtkMRMLHierarchyNodeTest1.cxx
vtkMRMLHierarchyNodeTest3.cxx
vtkMRMLI18NTest1.cxx
vtkMRMLInteractionNodeTest1.cxx
vtkMRMLLabelMapVolumeDisplayNodeTest1.cxx
vtkMRMLLayoutNodeTest1.cxx
Expand Down
61 changes: 61 additions & 0 deletions Libs/MRML/Core/Testing/vtkMRMLI18NTest1.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*=auto=========================================================================

Portions (c) Copyright 2005 Brigham and Women's Hospital (BWH)
All Rights Reserved.

See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.

Program: 3D Slicer

=========================================================================auto=*/

// MRML includes
#include "vtkMRMLCoreTestingMacros.h"
#include "vtkMRMLScene.h"

// VTK includes
#include <vtkMRMLI18N.h>
#include <vtkMRMLTranslator.h>

namespace
{

class vtkTestTranslator : public vtkMRMLTranslator
{
public:
static vtkTestTranslator * New();
vtkTypeMacro(vtkTestTranslator, vtkMRMLTranslator);

/// Translation method for testing that returns "translated-(context)(sourceText)" as translation
std::string Translate(const char* context, const char* sourceText, const char* disambiguation = nullptr, int n = -1) override
{
return std::string("translated-") + context + sourceText;
}

protected:
vtkTestTranslator () = default;
~vtkTestTranslator () override = default;
vtkTestTranslator (const vtkTestTranslator &) = delete;
void operator=(const vtkTestTranslator &) = delete;
};

vtkStandardNewMacro(vtkTestTranslator );
}

int vtkMRMLI18NTest1(int, char*[])
{
// Check default translation (simply sourcetext is returned)
CHECK_STD_STRING(vtkMRMLI18N::Translate("SomeContext", "SomeMessage"), "SomeMessage");

// Set custom translator
vtkNew<vtkTestTranslator> translator;
vtkMRMLI18N::GetInstance()->SetTranslator(translator);

// Check translation with custom translator
CHECK_STD_STRING(vtkMRMLI18N::Translate("SomeContext", "SomeMessage"), "translated-SomeContextSomeMessage");
// Use translation convenience function
CHECK_STD_STRING(vtkMRMLTr("SomeContext", "SomeMessage"), "translated-SomeContextSomeMessage");

return EXIT_SUCCESS;
}
9 changes: 5 additions & 4 deletions Libs/MRML/Core/vtkMRMLColorTableStorageNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Version: $Revision: 1.6 $
// MRML include
#include "vtkMRMLColorTableStorageNode.h"
#include "vtkMRMLColorTableNode.h"
#include "vtkMRMLI18N.h"
#include "vtkMRMLScene.h"

// VTK include
Expand Down Expand Up @@ -315,13 +316,13 @@ int vtkMRMLColorTableStorageNode::WriteDataInternal(vtkMRMLNode *refNode)
//----------------------------------------------------------------------------
void vtkMRMLColorTableStorageNode::InitializeSupportedReadFileTypes()
{
this->SupportedReadFileTypes->InsertNextValue("Color Table (.ctbl)");
this->SupportedReadFileTypes->InsertNextValue("Text (.txt)");
this->SupportedReadFileTypes->InsertNextValue(vtkMRMLTr("vtkMRMLColorTableStorageNode", "MRML Color Table") + " (.ctbl)"); //: file format name
this->SupportedReadFileTypes->InsertNextValue(vtkMRMLTr("vtkMRMLColorTableStorageNode", "MRML Color Table") + " (.txt)"); //: file format name
}

//----------------------------------------------------------------------------
void vtkMRMLColorTableStorageNode::InitializeSupportedWriteFileTypes()
{
this->SupportedWriteFileTypes->InsertNextValue("Color Table (.ctbl)");
this->SupportedWriteFileTypes->InsertNextValue("Text (.txt)");
this->SupportedWriteFileTypes->InsertNextValue(vtkMRMLTr("vtkMRMLColorTableStorageNode", "MRML Color Table") + " (.ctbl)"); //: file format name
this->SupportedWriteFileTypes->InsertNextValue(vtkMRMLTr("vtkMRMLColorTableStorageNode", "MRML Color Table") + " (.txt)"); //: file format name
}
149 changes: 149 additions & 0 deletions Libs/MRML/Core/vtkMRMLI18N.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*==============================================================================

Program: 3D Slicer

Copyright(c) Kitware Inc.

See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

==============================================================================*/

// MRML includes
#include "vtkMRMLI18N.h"
#include "vtkMRMLTranslator.h"

// VTK includes
#include <vtkObjectFactory.h>

vtkCxxSetObjectMacro(vtkMRMLI18N, Translator, vtkMRMLTranslator);

//----------------------------------------------------------------------------
// The i18n manager singleton.
// This MUST be default initialized to zero by the compiler and is
// therefore not initialized here. The ClassInitialize and
// ClassFinalize methods handle this instance.
static vtkMRMLI18N* vtkMRMLI18NInstance;

//----------------------------------------------------------------------------
// Must NOT be initialized. Default initialization to zero is necessary.
unsigned int vtkMRMLI18NInitialize::Count;

//----------------------------------------------------------------------------
// Implementation of vtkMRMLI18NInitialize class.
//----------------------------------------------------------------------------
vtkMRMLI18NInitialize::vtkMRMLI18NInitialize()
{
if(++Self::Count == 1)
{
vtkMRMLI18N::classInitialize();
}
}

//----------------------------------------------------------------------------
vtkMRMLI18NInitialize::~vtkMRMLI18NInitialize()
{
if(--Self::Count == 0)
{
vtkMRMLI18N::classFinalize();
}
}

//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// Up the reference count so it behaves like New
vtkMRMLI18N* vtkMRMLI18N::New()
{
vtkMRMLI18N* ret = vtkMRMLI18N::GetInstance();
ret->Register(nullptr);
return ret;
}

//----------------------------------------------------------------------------
// Return the single instance of the vtkMRMLI18N
vtkMRMLI18N* vtkMRMLI18N::GetInstance()
{
if(!vtkMRMLI18NInstance)
{
// Try the factory first
vtkMRMLI18NInstance = (vtkMRMLI18N*)vtkObjectFactory::CreateInstance("vtkMRMLI18N");
// if the factory did not provide one, then create it here
if(!vtkMRMLI18NInstance)
{
vtkMRMLI18NInstance = new vtkMRMLI18N;
#ifdef VTK_HAS_INITIALIZE_OBJECT_BASE
vtkMRMLI18NInstance->InitializeObjectBase();
#endif
}
}
// return the instance
return vtkMRMLI18NInstance;
}

//----------------------------------------------------------------------------
vtkMRMLI18N::vtkMRMLI18N()
{
this->Translator = nullptr;
}

//----------------------------------------------------------------------------
vtkMRMLI18N::~vtkMRMLI18N()
{
if (this->Translator)
{
this->Translator->Delete();
}
this->Translator = nullptr;
}

//----------------------------------------------------------------------------
void vtkMRMLI18N::PrintSelf(ostream& os, vtkIndent indent)
{
this->vtkObject::PrintSelf(os, indent);

os << indent << "Translator:";
if (this->GetTranslator())
{
this->GetTranslator()->PrintSelf(os, indent.GetNextIndent());
}
else
{
os << " (none)" << "\n";
}
}

//----------------------------------------------------------------------------
void vtkMRMLI18N::classInitialize()
{
// Allocate the singleton
vtkMRMLI18NInstance = vtkMRMLI18N::GetInstance();
}

//----------------------------------------------------------------------------
void vtkMRMLI18N::classFinalize()
{
vtkMRMLI18NInstance->Delete();
vtkMRMLI18NInstance = nullptr;
}

//----------------------------------------------------------------------------
std::string vtkMRMLI18N::Translate(const char *context, const char *sourceText, const char *disambiguation/*=nullptr*/, int n/*=-1*/)
{
vtkMRMLI18N* i18n = vtkMRMLI18N::GetInstance();
vtkMRMLTranslator* translator = i18n ? i18n->GetTranslator() : nullptr;
if (translator)
{
return translator->Translate(context, sourceText, disambiguation, n);
}
else
{
return sourceText ? sourceText : "";
}
}