Skip to content

Commit 3433fc9

Browse files
authored
i18n: Use MR::Id for locale domain ids (#5917)
1 parent 6f94f2f commit 3433fc9

11 files changed

Lines changed: 61 additions & 63 deletions

source/MRMesh/MRMeshFwd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class MRMESH_CLASS ObjTag;
107107
class MRMESH_CLASS TextureTag;
108108
class MRMESH_CLASS GraphVertTag;
109109
class MRMESH_CLASS GraphEdgeTag;
110+
class MRMESH_CLASS LocaleDomainTag;
110111

111112
MR_CANONICAL_TYPEDEFS( (template <typename T> class MRMESH_CLASS), Id,
112113
( EdgeId, Id<EdgeTag> )
@@ -121,6 +122,7 @@ MR_CANONICAL_TYPEDEFS( (template <typename T> class MRMESH_CLASS), Id,
121122
( TextureId, Id<TextureTag> )
122123
( GraphVertId, Id<GraphVertTag> )
123124
( GraphEdgeId, Id<GraphEdgeTag> )
125+
( LocaleDomainId, Id<LocaleDomainTag> )
124126
)
125127
// Those are full specializations in `MRId.h`, so `MR_CANONICAL_TYPEDEFS` doesn't work on them.
126128
// Have to add this too.

source/MRViewer/MRI18n.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,38 +25,38 @@ inline const char* asCStr( const std::string_view& sv )
2525

2626
} // namespace
2727

28-
std::string translate( std::string_view msg, Domain domain )
28+
std::string translate( std::string_view msg, LocaleDomainId domainId )
2929
{
3030
#ifndef MRVIEWER_NO_LOCALE
31-
if ( domain.id >= 0 )
32-
return boost::locale::translate( asCStr( msg ) ).str( get(), domain.id );
31+
if ( domainId.valid() )
32+
return boost::locale::translate( asCStr( msg ) ).str( get(), domainId.get() );
3333
#endif
3434
return translate_noop( asCStr( msg ) );
3535
}
3636

37-
std::string translate( std::string_view context, std::string_view msg, Domain domain )
37+
std::string translate( std::string_view context, std::string_view msg, LocaleDomainId domainId )
3838
{
3939
#ifndef MRVIEWER_NO_LOCALE
40-
if ( domain.id >= 0 )
41-
return boost::locale::translate( asCStr( context ), asCStr( msg ) ).str( get(), domain.id );
40+
if ( domainId.valid() )
41+
return boost::locale::translate( asCStr( context ), asCStr( msg ) ).str( get(), domainId.get() );
4242
#endif
4343
return translate_noop( asCStr( context ), asCStr( msg ) );
4444
}
4545

46-
std::string translate( std::string_view single, std::string_view plural, Int64 n, Domain domain )
46+
std::string translate( std::string_view single, std::string_view plural, Int64 n, LocaleDomainId domainId )
4747
{
4848
#ifndef MRVIEWER_NO_LOCALE
49-
if ( domain.id >= 0 )
50-
return boost::locale::translate( asCStr( single ), asCStr( plural ), n ).str( get(), domain.id );
49+
if ( domainId.valid() )
50+
return boost::locale::translate( asCStr( single ), asCStr( plural ), n ).str( get(), domainId.get() );
5151
#endif
5252
return translate_noop( asCStr( single ), asCStr( plural ), n );
5353
}
5454

55-
std::string translate( std::string_view context, std::string_view single, std::string_view plural, Int64 n, Domain domain )
55+
std::string translate( std::string_view context, std::string_view single, std::string_view plural, Int64 n, LocaleDomainId domainId )
5656
{
5757
#ifndef MRVIEWER_NO_LOCALE
58-
if ( domain.id >= 0 )
59-
return boost::locale::translate( asCStr( context ), asCStr( single ), asCStr( plural ), n ).str( get(), domain.id );
58+
if ( domainId.valid() )
59+
return boost::locale::translate( asCStr( context ), asCStr( single ), asCStr( plural ), n ).str( get(), domainId.get() );
6060
#endif
6161
return translate_noop( asCStr( context ), asCStr( single ), asCStr( plural ), n );
6262
}

source/MRViewer/MRI18n.h

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "config.h"
44
#include "exports.h"
55

6-
#include <MRMesh/MRMeshFwd.h>
6+
#include "MRMesh/MRId.h"
77

88
#include <string>
99
#include <string_view>
@@ -12,43 +12,38 @@
1212
namespace MR::Locale
1313
{
1414

15-
/// Information about locale domains. Contains the only field `id`.
16-
/// The purpose of the struct is to resolve an ambiguous overload `translate( "str", "str", 0 )`
17-
/// which otherwise could be treated as both "context, message, domain id" and "single, plural, number".
18-
struct Domain
19-
{
20-
int id = 0;
21-
};
15+
/// Locale domain internal identifier for MeshLib's own translations.
16+
constexpr inline LocaleDomainId cDefaultDomainId { 0 };
2217

2318
/// \brief Translates a message using the active locale.
24-
MRVIEWER_API std::string translate( std::string_view msg, Domain domain = {} );
19+
MRVIEWER_API std::string translate( std::string_view msg, LocaleDomainId domainId = cDefaultDomainId );
2520

2621
/// \brief Translates a message in context using the active locale.
27-
MRVIEWER_API std::string translate( std::string_view context, std::string_view msg, Domain domain = {} );
22+
MRVIEWER_API std::string translate( std::string_view context, std::string_view msg, LocaleDomainId domainId = cDefaultDomainId );
2823

2924
/// \brief Translates a plural message form using the active locale.
30-
MRVIEWER_API std::string translate( std::string_view single, std::string_view plural, Int64 n, Domain domain = {} );
25+
MRVIEWER_API std::string translate( std::string_view single, std::string_view plural, Int64 n, LocaleDomainId domainId = cDefaultDomainId );
3126

3227
/// \brief Translates a plural message form in context using the active locale.
33-
MRVIEWER_API std::string translate( std::string_view context, std::string_view single, std::string_view plural, Int64 n, Domain domain = {} );
28+
MRVIEWER_API std::string translate( std::string_view context, std::string_view single, std::string_view plural, Int64 n, LocaleDomainId domainId = cDefaultDomainId );
3429

3530
/// \brief Translates all strings in a vector using the active locale.
36-
inline std::vector<std::string> translateAll( const std::vector<std::string>& items, Domain domain = {} )
31+
inline std::vector<std::string> translateAll( const std::vector<std::string>& items, LocaleDomainId domainId = cDefaultDomainId )
3732
{
3833
std::vector<std::string> result;
3934
result.reserve( items.size() );
4035
for ( const auto& s : items )
41-
result.push_back( translate( s, domain ) );
36+
result.push_back( translate( s, domainId ) );
4237
return result;
4338
}
4439

4540
/// \brief Translates all strings in a vector with context using the active locale.
46-
inline std::vector<std::string> translateAll( const char* context, const std::vector<std::string>& items, Domain domain = {} )
41+
inline std::vector<std::string> translateAll( const char* context, const std::vector<std::string>& items, LocaleDomainId domainId = cDefaultDomainId )
4742
{
4843
std::vector<std::string> result;
4944
result.reserve( items.size() );
5045
for ( const auto& s : items )
51-
result.push_back( translate( context, s, domain ) );
46+
result.push_back( translate( context, s, domainId ) );
5247
return result;
5348
}
5449

source/MRViewer/MRLocale.cpp

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "MRMesh/MRDirectory.h"
44
#include "MRMesh/MRFinally.h"
5+
#include "MRMesh/MRId.h"
56
#include "MRMesh/MROnInit.h"
67
#include "MRMesh/MRString.h"
78
#include "MRMesh/MRStringConvert.h"
@@ -48,7 +49,7 @@ std::unordered_map<std::string, std::string> gKnownLocales = {
4849
#include "MRLocaleNames.inl"
4950
};
5051

51-
std::map<const char*, int> gDomainCache = {};
52+
std::map<const char*, LocaleDomainId> gDomainCache = {};
5253

5354
} // namespace
5455

@@ -104,42 +105,39 @@ void Locale::addCatalogPath( const std::filesystem::path& path )
104105
gLocale = gLocaleGen.generate( gLocaleName );
105106
}
106107

107-
int Locale::addDomain( const char* domainName )
108+
LocaleDomainId Locale::addDomain( const char* domainName )
108109
{
109110
if ( auto it = gDomainCache.find( domainName ); it != gDomainCache.end() )
110111
return it->second;
111112

112113
gLocaleGen.add_messages_domain( domainName );
113114
gLocale = gLocaleGen.generate( gLocaleName );
114115

115-
using facet_type = boost::locale::message_format<char>;
116-
assert( std::has_facet<facet_type>( gLocale ) );
117-
return ( gDomainCache[domainName] = std::use_facet<facet_type>( gLocale ).domain( domainName ) );
116+
return ( gDomainCache[domainName] = findDomain( std::string{ domainName } ) );
118117
}
119118

120-
int Locale::addDomain( const std::string& domainName )
119+
LocaleDomainId Locale::addDomain( const std::string& domainName )
121120
{
122121
gLocaleGen.add_messages_domain( domainName );
123122
gLocale = gLocaleGen.generate( gLocaleName );
124123

125124
return findDomain( domainName );
126125
}
127126

128-
int Locale::findDomain( const char* domainName )
127+
LocaleDomainId Locale::findDomain( const char* domainName )
129128
{
130129
if ( auto it = gDomainCache.find( domainName ); it != gDomainCache.end() )
131130
return it->second;
132131

133-
using facet_type = boost::locale::message_format<char>;
134-
assert( std::has_facet<facet_type>( gLocale ) );
135-
return ( gDomainCache[domainName] = std::use_facet<facet_type>( gLocale ).domain( domainName ) );
132+
return ( gDomainCache[domainName] = findDomain( std::string{ domainName } ) );
136133
}
137134

138-
int Locale::findDomain( const std::string& domainName )
135+
LocaleDomainId Locale::findDomain( const std::string& domainName )
139136
{
140137
using facet_type = boost::locale::message_format<char>;
141138
assert( std::has_facet<facet_type>( gLocale ) );
142-
return std::use_facet<facet_type>( gLocale ).domain( domainName );
139+
const auto id = std::use_facet<facet_type>( gLocale ).domain( domainName );
140+
return id != 0 ? LocaleDomainId{ id } : LocaleDomainId{};
143141
}
144142

145143
std::string Locale::getDisplayName( const std::string& localeName )

source/MRViewer/MRLocale.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#ifndef MRVIEWER_NO_LOCALE
55
#include "exports.h"
66

7+
#include "MRMesh/MRMeshFwd.h"
8+
79
#include <boost/signals2/connection.hpp>
810

911
#include <filesystem>
@@ -37,20 +39,20 @@ MRVIEWER_API void addCatalogPath( const std::filesystem::path& path );
3739
/// The active locale is reloaded on every call.
3840
/// \note This overload is meant to be used with string literals for faster lookups.
3941
/// \returns The id of the added domain.
40-
MRVIEWER_API int addDomain( const char* domainName );
42+
MRVIEWER_API LocaleDomainId addDomain( const char* domainName );
4143
/// \brief Adds a new domain.
4244
/// The active locale is reloaded on every call.
4345
/// \returns The id of the added domain.
44-
MRVIEWER_API int addDomain( const std::string& domainName );
46+
MRVIEWER_API LocaleDomainId addDomain( const std::string& domainName );
4547
/// \brief Find an id for the given domain that can be passed to the `translate` functions.
46-
/// \returns The domain id if the domain is previously added and 0 (the default domain id) otherwise.
48+
/// \returns The domain id if the domain is previously added and invalid id otherwise.
4749
/// \note This overload is meant to be used with string literals for faster lookups.
4850
/// \ref translate
49-
MRVIEWER_API int findDomain( const char* domainName );
51+
MRVIEWER_API LocaleDomainId findDomain( const char* domainName );
5052
/// \brief Find an id for the given domain that can be passed to the `translate` functions.
51-
/// \returns The domain id if the domain is previously added and 0 (the default domain id) otherwise.
53+
/// \returns The domain id if the domain is previously added and invalid id otherwise.
5254
/// \ref translate
53-
MRVIEWER_API int findDomain( const std::string& domainName );
55+
MRVIEWER_API LocaleDomainId findDomain( const std::string& domainName );
5456

5557
/// \brief Returns a display name for the given locale.
5658
/// \returns

source/MRViewer/MRRibbonButtonDrawer.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ bool RibbonButtonDrawer::GradientCheckboxItem( const MenuItemInfo& item, bool* v
9595
drawButtonIcon( item, DrawButtonParams{.itemSize = ImVec2( height + 4, height + 4 ), .iconSize = height / UI::scale(),
9696
.rootType = DrawButtonParams::RootType::Toolbar } );
9797
ImGui::SameLine( 0.f, spacing );
98-
const auto caption = Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } );
98+
const auto caption = Locale::translate( item.getCaption().c_str(), item.localeDomainId );
9999
ImGui::Text( "%s", caption.c_str() );
100100
return res;
101101
}
@@ -358,7 +358,7 @@ void RibbonButtonDrawer::drawCustomButtonItem( const MenuItemInfo& item, const C
358358
else
359359
ImGui::SetCursorPosY( ImGui::GetCursorPosY() + ( availableHeight - textHeight ) * 0.5f - ImGui::GetStyle().WindowPadding.y + 3 * UI::scale() );
360360

361-
const auto caption = Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } );
361+
const auto caption = Locale::translate( item.getCaption().c_str(), item.localeDomainId );
362362
size_t pos = 0;
363363
for ( const auto& i : item.captionSize.splitInfo )
364364
{
@@ -371,7 +371,7 @@ void RibbonButtonDrawer::drawCustomButtonItem( const MenuItemInfo& item, const C
371371
{
372372
ImGui::SameLine();
373373
ImGui::SetCursorPosY( ( params.itemSize.y - ImGui::GetTextLineHeight() ) * 0.5f );
374-
const auto caption = Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } );
374+
const auto caption = Locale::translate( item.getCaption().c_str(), item.localeDomainId );
375375
ImGui::Text( "%s", caption.c_str() );
376376
}
377377

@@ -631,9 +631,9 @@ void RibbonButtonDrawer::drawTooltip_( const MenuItemInfo& item, const std::stri
631631
ImGui::PushStyleVar( ImGuiStyleVar_WindowPadding, ImVec2( cRibbonButtonWindowPaddingX * UI::scale(), cRibbonButtonWindowPaddingY * UI::scale() ) );
632632
std::string tooltip = item.item->getDynamicTooltip();
633633
if ( tooltip.empty() )
634-
tooltip = Locale::translate( item.tooltip.c_str(), Locale::Domain{ item.localeDomainId } );
634+
tooltip = Locale::translate( item.tooltip.c_str(), item.localeDomainId );
635635

636-
std::string caption = Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } );
636+
std::string caption = Locale::translate( item.getCaption().c_str(), item.localeDomainId );
637637

638638
std::string fullText;
639639
fullText = caption;

source/MRViewer/MRRibbonMenu.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ std::string getItemCaption( const std::string& name )
6464
if ( it == RibbonSchemaHolder::schema().items.end() )
6565
return name;
6666
const auto& item = it->second;
67-
return Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } );
67+
return Locale::translate( item.getCaption().c_str(), item.localeDomainId );
6868
}
6969

7070
} //anonymous namespace
@@ -526,7 +526,7 @@ void RibbonMenu::drawHeaderPannel_()
526526
if ( schema.tabsOrder[i].experimental && !getViewerInstance().experimentalFeatures )
527527
continue;
528528
const auto& tab = schema.tabsOrder[i];
529-
translatedTabNames[i] = Locale::translate( "Tab name", tab.name.c_str(), Locale::Domain{ tab.localeDomainId } );
529+
translatedTabNames[i] = Locale::translate( "Tab name", tab.name.c_str(), tab.localeDomainId );
530530
textSizes[i] = ImGui::CalcTextSize( translatedTabNames[i].c_str() ).x;
531531
tabSizes[i] = std::max( textSizes[i] + cTabLabelMinPadding * 2 * UI::scale(), cTabMinimumWidth * UI::scale() );
532532
summaryTabPannelSize += ( tabSizes[i] + cTabsInterval * UI::scale() );

source/MRViewer/MRRibbonSchema.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void RibbonSchema::updateCaptions()
5656
auto statePlugin = std::dynamic_pointer_cast< StateBasePlugin >( item.item );
5757
if ( !statePlugin )
5858
continue;
59-
statePlugin->setUIName( Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } ) );
59+
statePlugin->setUIName( Locale::translate( item.getCaption().c_str(), item.localeDomainId ) );
6060
}
6161
}
6262

@@ -517,7 +517,7 @@ void RibbonSchemaLoader::recalcItemSizes()
517517

518518
auto& sizes = item.captionSize;
519519

520-
const auto caption = Locale::translate( item.getCaption().c_str(), Locale::Domain{ item.localeDomainId } );
520+
const auto caption = Locale::translate( item.getCaption().c_str(), item.localeDomainId );
521521
sizes.baseSize = sCalcSize( font, fontSize, caption.data(), caption.data() + caption.size() );
522522
sizes.splitInfo = sAutoSplit( caption, fontSize, cMaxTextWidth, font, sizes.baseSize );
523523
}
@@ -580,7 +580,7 @@ void RibbonSchemaLoader::readItemsJson_( const std::filesystem::path& path ) con
580580

581581
void RibbonSchemaLoader::readItemsJson_( const Json::Value& itemsStruct, const std::string& schemaName ) const
582582
{
583-
const auto domainId = !schemaName.empty() ? Locale::addDomain( schemaName ) : -1;
583+
const auto domainId = !schemaName.empty() ? Locale::addDomain( schemaName ) : LocaleDomainId{};
584584

585585
auto items = itemsStruct["Items"];
586586
if ( !items.isArray() )
@@ -674,7 +674,7 @@ void RibbonSchemaLoader::readUIJson_( const std::filesystem::path& path ) const
674674
readUIJson_( *itemsStructRes, domainId );
675675
}
676676

677-
void RibbonSchemaLoader::readUIJson_( const Json::Value& itemsStructure, int domainId ) const
677+
void RibbonSchemaLoader::readUIJson_( const Json::Value& itemsStructure, LocaleDomainId domainId ) const
678678
{
679679
auto tabs = itemsStructure["Tabs"];
680680
if ( !tabs.isArray() )

source/MRViewer/MRRibbonSchema.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include "MRViewerFwd.h"
33
#include "MRRibbonRegisterItem.h"
4+
#include "MRMesh/MRId.h"
45
#include "MRMesh/MRMeshFwd.h"
56
#include "MRMesh/MRphmap.h"
67
#include <json/forwards.h>
@@ -29,7 +30,7 @@ struct MenuItemInfo
2930
std::string icon;
3031
MenuItemCaptionSize captionSize; // already scaled
3132
std::string helpLink; // link to help page
32-
int localeDomainId = -1; // needed for translation
33+
LocaleDomainId localeDomainId; // needed for translation
3334

3435
const std::string& getCaption() const { return !caption.empty() ? caption : item->name(); }
3536
};
@@ -55,7 +56,7 @@ struct RibbonTab
5556
std::string name;
5657
int priority{ 0 };
5758
bool experimental{ false };
58-
int localeDomainId{ -1 }; // domain that owns this tab's translation; set by the first .ui.json that creates it
59+
LocaleDomainId localeDomainId; // domain that owns this tab's translation; set by the first .ui.json that creates it
5960
};
6061

6162
// This structure describes UI schema of ribbon menu
@@ -155,7 +156,7 @@ class MRVIEWER_CLASS RibbonSchemaLoader
155156
MRVIEWER_API void readItemsJson_( const Json::Value& root, const std::string& schemaName = {} ) const;
156157
// appends one ui json info
157158
MRVIEWER_API void readUIJson_( const std::filesystem::path& path ) const;
158-
MRVIEWER_API void readUIJson_( const Json::Value& root, int domainId = -1 ) const;
159+
MRVIEWER_API void readUIJson_( const Json::Value& root, LocaleDomainId domainId = {} ) const;
159160
};
160161

161162

source/MRViewer/MRStatePlugin.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ StateBasePlugin::StateBasePlugin( std::string name, StatePluginTabs tab ):
3333
CommandLoop::appendCommand( [this] ()
3434
{
3535
std::string name = this->name();
36-
int localeDomainId = -1;
36+
LocaleDomainId localeDomainId;
3737
auto item = RibbonSchemaHolder::schema().items.find( name );
3838
if ( item != RibbonSchemaHolder::schema().items.end() )
3939
{
4040
if ( !item->second.caption.empty() )
4141
name = item->second.caption;
4242
localeDomainId = item->second.localeDomainId;
4343
}
44-
plugin_name = Locale::translate( name.c_str(), Locale::Domain{ localeDomainId } );
44+
plugin_name = Locale::translate( name.c_str(), localeDomainId );
4545
plugin_name += UINameSuffix();
4646
}, CommandLoop::StartPosition::AfterPluginInit );
4747
tab_ = tab;

0 commit comments

Comments
 (0)