Skip to content

Commit

Permalink
item: let translators reorder tname segments
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei8l committed Nov 15, 2024
1 parent dca38e5 commit 382a5fe
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 3 deletions.
7 changes: 7 additions & 0 deletions data/mods/TEST_DATA/lang/po/ru.po
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ msgstr[0] "щука"
msgstr[1] "щуки"
msgstr[2] "щук"
msgstr[3] "щуки"

msgid "tname_segments_order"
msgstr "FAULTS DIRT OVERHEAT FAVORITE_PRE DURABILITY WHEEL_DIAMETER WEAPON_MODS CUSTOM_ITEM_PREFIX TYPE BURN"

msgctxt "burnt adjective"
msgid "burnt "
msgstr " (burnt)"
3 changes: 1 addition & 2 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6859,8 +6859,7 @@ std::string item::tname( unsigned int quantity, tname::segment_bitset const &seg
{
std::string ret;

for( size_t i = 0; i < static_cast<size_t>( tname::segments::last_segment ); i++ ) {
tname::segments const idx = static_cast<tname::segments>( i );
for( tname::segments idx : tname::get_tname_set() ) {
if( !segments[idx] ) {
continue;
}
Expand Down
142 changes: 141 additions & 1 deletion src/item_tname.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,13 +609,153 @@ static_assert( all_segments_have_printers(),
"every element of tname::segments (up to tname::segments::last_segment) "
"must map to a printer in segs_array" );


namespace io
{
template<>
std::string enum_to_string<tname::segments>( tname::segments seg )
{
switch( seg ) {
// *INDENT-OFF*
case tname::segments::FAULTS: return "FAULTS";
case tname::segments::DIRT: return "DIRT";
case tname::segments::OVERHEAT: return "OVERHEAT";
case tname::segments::FAVORITE_PRE: return "FAVORITE_PRE";
case tname::segments::DURABILITY: return "DURABILITY";
case tname::segments::WHEEL_DIAMETER: return "WHEEL_DIAMETER";
case tname::segments::BURN: return "BURN";
case tname::segments::WEAPON_MODS: return "WEAPON_MODS";
case tname::segments::CUSTOM_ITEM_PREFIX: return "CUSTOM_ITEM_PREFIX";
case tname::segments::TYPE: return "TYPE";
case tname::segments::CATEGORY: return "CATEGORY";
case tname::segments::CUSTOM_ITEM_SUFFIX: return "CUSTOM_ITEM_SUFFIX";
case tname::segments::MODS: return "MODS";
case tname::segments::CRAFT: return "CRAFT";
case tname::segments::WHITEBLACKLIST: return "WHITEBLACKLIST";
case tname::segments::CHARGES: return "CHARGES";
case tname::segments::FOOD_TRAITS: return "FOOD_TRAITS";
case tname::segments::FOOD_STATUS: return "FOOD_STATUS";
case tname::segments::FOOD_IRRADIATED: return "FOOD_IRRADIATED";
case tname::segments::TEMPERATURE: return "TEMPERATURE";
case tname::segments::LOCATION_HINT: return "LOCATION_HINT";
case tname::segments::CLOTHING_SIZE: return "CLOTHING_SIZE";
case tname::segments::ETHEREAL: return "ETHEREAL";
case tname::segments::FILTHY: return "FILTHY";
case tname::segments::BROKEN: return "BROKEN";
case tname::segments::CBM_STATUS: return "CBM_STATUS";
case tname::segments::UPS: return "UPS";
case tname::segments::TAGS: return "TAGS";
case tname::segments::VARS: return "VARS";
case tname::segments::WETNESS: return "WETNESS";
case tname::segments::ACTIVE: return "ACTIVE";
case tname::segments::SEALED: return "SEALED";
case tname::segments::FAVORITE_POST: return "FAVORITE_POST";
case tname::segments::RELIC: return "RELIC";
case tname::segments::LINK: return "LINK";
case tname::segments::TECHNIQUES: return "TECHNIQUES";
case tname::segments::CONTENTS: return "CONTENTS";
case tname::segments::last_segment: return "last_segment";
case tname::segments::VARIANT: return "VARIANT";
case tname::segments::COMPONENTS: return "COMPONENTS";
case tname::segments::CORPSE: return "CORPSE";
case tname::segments::CONTENTS_FULL: return "CONTENTS_FULL";
case tname::segments::CONTENTS_ABREV: return "CONTENTS_ABBREV";
case tname::segments::CONTENTS_COUNT: return "CONTENTS_COUNT";
case tname::segments::FOOD_PERISHABLE: return "FOOD_PERISHABLE";
case tname::segments::last: return "last";
default:
// *INDENT-ON*
break;
}
return {};
}

} // namespace io

namespace
{

constexpr tname::segments fixed_pos_segments = tname::segments::CONTENTS;
static_assert( fixed_pos_segments <= tname::segments::last_segment );

using tname_array = std::array<int, static_cast<std::size_t>( fixed_pos_segments )>;
struct segment_order {
constexpr explicit segment_order( tname_array const &arr_ ) : arr( &arr_ ) {};
constexpr bool operator()( tname::segments lhs, tname::segments rhs ) const {
return arr->at( static_cast<std::size_t>( lhs ) ) <
arr->at( static_cast<std::size_t>( rhs ) );
}

tname_array const *arr;
};

std::optional<std::size_t> str_to_segment_idx( std::string const &str )
{
if( std::optional<tname::segments> ret = io::string_to_enum_optional<tname::segments>( str );
ret && ret < fixed_pos_segments ) {

return static_cast<std::size_t>( *ret );
}

return {};
}

} // namespace
namespace tname
{
std::string print_segment( tname::segments segment, item const &it, unsigned int quantity,
segment_bitset const &segments )
{
static std::array<decl_f_print_segment *, num_segments> const arr = get_segs_array();
size_t const idx = static_cast<size_t>( segment );
std::size_t const idx = static_cast<std::size_t>( segment );
return ( *arr.at( idx ) )( it, quantity, segments );
}

tname_set const &get_tname_set()
{
static tname_set tns;
static int lang_ver = INVALID_LANGUAGE_VERSION;
if( int const cur_lang_ver = detail::get_current_language_version(); lang_ver != cur_lang_ver ) {
lang_ver = cur_lang_ver;
tns.clear();
for( std::size_t i = 0; i < static_cast<std::size_t>( fixed_pos_segments ); i++ ) {
tns.emplace_back( static_cast<tname::segments>( i ) );
}

//~ You can use this string to change the order of item name segments. The default order is:
//~ FAULTS DIRT OVERHEAT FAVORITE_PRE DURABILITY WHEEL_DIAMETER BURN WEAPON_MODS
//~ CUSTOM_ITEM_PREFIX TYPE CATEGORY CUSTOM_ITEM_SUFFIX MODS CRAFT WHITEBLACKLIST CHARGES
//~ FOOD_TRAITS FOOD_STATUS FOOD_IRRADIATED TEMPERATURE LOCATION_HINT CLOTHING_SIZE ETHEREAL
//~ FILTHY BROKEN CBM_STATUS UPS TAGS VARS WETNESS ACTIVE SEALED FAVORITE_POST RELIC LINK
//~ TECHNIQUES
//~ --
//~ refer to io::enum_to_string<tname::segments> for an updated list
std::string order_i18n( _( "tname_segments_order" ) );
if( order_i18n != "tname_segments_order" ) {
std::stringstream ss( order_i18n );
std::istream_iterator<std::string> begin( ss );
std::istream_iterator<std::string> end;
std::vector<std::string> tokens( begin, end );

tname_array tna;
tna.fill( 999 );
int cur_order = 0;
for( std::string const &s : tokens ) {
if( std::optional<std::size_t> idx = str_to_segment_idx( s ); idx ) {
tna[*idx] = cur_order++;
} else {
DebugLog( D_WARNING, D_MAIN ) << "Ignoring tname segment " << std::quoted( s ) << std::endl;
}
}

std::stable_sort( tns.begin(), tns.end(), segment_order( tna ) );
}
for( std::size_t i = static_cast<std::size_t>( fixed_pos_segments );
i < static_cast<std::size_t>( tname::segments::last_segment ); i++ ) {
tns.emplace_back( static_cast<tname::segments>( i ) );
}
}

return tns;
}
} // namespace tname
3 changes: 3 additions & 0 deletions src/item_tname.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ using segment_bitset = enum_bitset<tname::segments>;
std::string print_segment( tname::segments segment, item const &it, unsigned int quantity,
segment_bitset const &segments );

using tname_set = std::vector<tname::segments>;
tname_set const &get_tname_set();

#endif // CATA_IN_TOOL
} // namespace tname

Expand Down
17 changes: 17 additions & 0 deletions tests/item_tname_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -947,3 +947,20 @@ TEST_CASE( "nested_items_tname", "[item][tname]" )
}
}
}

#ifdef LOCALIZE
TEST_CASE( "tname_i18n_order", "[item][tname][translations]" )
{
item backpack( "backpack" );
backpack.burnt = 1;
backpack.set_flag( flag_FILTHY );
REQUIRE( backpack.tname() == "<color_c_green>++</color> burnt backpack (filthy)" );

set_language( "ru" );
TranslationManager::GetInstance().LoadDocuments( { "./data/mods/TEST_DATA/lang/mo/ru/LC_MESSAGES/TEST_DATA.mo" } );
CHECK( backpack.tname() ==
"<color_c_green>++</color> backpack (burnt) (filthy)" );

set_language_from_options();
}
#endif

0 comments on commit 382a5fe

Please sign in to comment.